1
+ use std:: marker:: PhantomData ;
2
+
3
+ use aead:: consts:: { U12 , U16 } ;
4
+ use aes:: cipher:: { BlockEncrypt , BlockSizeUser , Unsigned } ;
1
5
use aes_gcm:: aead:: generic_array:: GenericArray ;
2
6
use aes_gcm:: aead:: { Aead , Payload } ;
3
- use aes_gcm:: { Aes128Gcm , KeyInit , Nonce } ;
7
+ use aes_gcm:: { AesGcm , KeyInit , Nonce } ;
4
8
use byteorder:: { BigEndian , ByteOrder } ;
5
9
use bytes:: { Bytes , BytesMut } ;
6
10
use util:: marshal:: * ;
7
11
8
12
use super :: Cipher ;
9
13
use crate :: error:: { Error , Result } ;
10
14
use crate :: key_derivation:: * ;
15
+ use crate :: protection_profile:: ProtectionProfile ;
11
16
12
17
pub const CIPHER_AEAD_AES_GCM_AUTH_TAG_LEN : usize = 16 ;
13
18
14
19
const RTCP_ENCRYPTION_FLAG : u8 = 0x80 ;
15
20
16
21
/// AEAD Cipher based on AES.
17
- pub ( crate ) struct CipherAeadAesGcm {
18
- srtp_cipher : aes_gcm:: Aes128Gcm ,
19
- srtcp_cipher : aes_gcm:: Aes128Gcm ,
22
+ pub ( crate ) struct CipherAeadAesGcm < AES , NonceSize = U12 >
23
+ where
24
+ NonceSize : Unsigned ,
25
+ {
26
+ profile : ProtectionProfile ,
27
+ srtp_cipher : aes_gcm:: AesGcm < AES , NonceSize > ,
28
+ srtcp_cipher : aes_gcm:: AesGcm < AES , NonceSize > ,
20
29
srtp_session_salt : Vec < u8 > ,
21
30
srtcp_session_salt : Vec < u8 > ,
31
+ _tag : PhantomData < AES > ,
22
32
}
23
33
24
- impl Cipher for CipherAeadAesGcm {
25
- fn auth_tag_len ( & self ) -> usize {
26
- CIPHER_AEAD_AES_GCM_AUTH_TAG_LEN
34
+ impl < AES , NS > Cipher for CipherAeadAesGcm < AES , NS >
35
+ where
36
+ NS : Unsigned ,
37
+ AES : BlockEncrypt + KeyInit + BlockSizeUser < BlockSize = U16 > + ' static ,
38
+ AesGcm < AES , NS > : Aead ,
39
+ {
40
+ fn rtp_auth_tag_len ( & self ) -> usize {
41
+ self . profile . rtp_auth_tag_len ( )
42
+ }
43
+
44
+ /// Get RTCP authenticated tag length.
45
+ fn rtcp_auth_tag_len ( & self ) -> usize {
46
+ self . profile . rtcp_auth_tag_len ( )
47
+ }
48
+
49
+ /// Get AEAD auth key length of the cipher.
50
+ fn aead_auth_tag_len ( & self ) -> usize {
51
+ self . profile . aead_auth_tag_len ( )
27
52
}
28
53
29
54
fn encrypt_rtp (
@@ -34,7 +59,7 @@ impl Cipher for CipherAeadAesGcm {
34
59
) -> Result < Bytes > {
35
60
// Grow the given buffer to fit the output.
36
61
let header_len = header. marshal_size ( ) ;
37
- let mut writer = BytesMut :: with_capacity ( payload. len ( ) + self . auth_tag_len ( ) ) ;
62
+ let mut writer = BytesMut :: with_capacity ( payload. len ( ) + self . aead_auth_tag_len ( ) ) ;
38
63
39
64
// Copy header unencrypted.
40
65
writer. extend_from_slice ( & payload[ ..header_len] ) ;
@@ -59,7 +84,7 @@ impl Cipher for CipherAeadAesGcm {
59
84
header : & rtp:: header:: Header ,
60
85
roc : u32 ,
61
86
) -> Result < Bytes > {
62
- if ciphertext. len ( ) < self . auth_tag_len ( ) {
87
+ if ciphertext. len ( ) < self . aead_auth_tag_len ( ) {
63
88
return Err ( Error :: ErrFailedToVerifyAuthTag ) ;
64
89
}
65
90
@@ -101,7 +126,7 @@ impl Cipher for CipherAeadAesGcm {
101
126
}
102
127
103
128
fn decrypt_rtcp ( & mut self , encrypted : & [ u8 ] , srtcp_index : usize , ssrc : u32 ) -> Result < Bytes > {
104
- if encrypted. len ( ) < self . auth_tag_len ( ) + SRTCP_INDEX_SIZE {
129
+ if encrypted. len ( ) < self . aead_auth_tag_len ( ) + SRTCP_INDEX_SIZE {
105
130
return Err ( Error :: ErrFailedToVerifyAuthTag ) ;
106
131
}
107
132
@@ -131,10 +156,31 @@ impl Cipher for CipherAeadAesGcm {
131
156
}
132
157
}
133
158
134
- impl CipherAeadAesGcm {
159
+ impl < AES , NS > CipherAeadAesGcm < AES , NS >
160
+ where
161
+ NS : Unsigned ,
162
+ AES : BlockEncrypt + KeyInit + BlockSizeUser < BlockSize = U16 > + ' static ,
163
+ AesGcm < AES , NS > : Aead ,
164
+ {
135
165
/// Create a new AEAD instance.
136
- pub ( crate ) fn new ( master_key : & [ u8 ] , master_salt : & [ u8 ] ) -> Result < CipherAeadAesGcm > {
137
- let srtp_session_key = aes_cm_key_derivation (
166
+ pub ( crate ) fn new (
167
+ profile : ProtectionProfile ,
168
+ master_key : & [ u8 ] ,
169
+ master_salt : & [ u8 ] ,
170
+ ) -> Result < CipherAeadAesGcm < AES > > {
171
+ assert_eq ! ( profile. aead_auth_tag_len( ) , AES :: block_size( ) ) ;
172
+ assert_eq ! ( profile. key_len( ) , AES :: key_size( ) ) ;
173
+ assert_eq ! ( profile. salt_len( ) , master_salt. len( ) ) ;
174
+
175
+ type Kdf = fn ( u8 , & [ u8 ] , & [ u8 ] , usize , usize ) -> Result < Vec < u8 > > ;
176
+ let kdf: Kdf = match profile {
177
+ ProtectionProfile :: AeadAes128Gcm => aes_cm_key_derivation,
178
+ // AES_256_GCM must use AES_256_CM_PRF as per https://datatracker.ietf.org/doc/html/rfc7714#section-11
179
+ ProtectionProfile :: AeadAes256Gcm => aes_256_cm_key_derivation,
180
+ _ => unreachable ! ( ) ,
181
+ } ;
182
+
183
+ let srtp_session_key = kdf (
138
184
LABEL_SRTP_ENCRYPTION ,
139
185
master_key,
140
186
master_salt,
@@ -144,9 +190,9 @@ impl CipherAeadAesGcm {
144
190
145
191
let srtp_block = GenericArray :: from_slice ( & srtp_session_key) ;
146
192
147
- let srtp_cipher = Aes128Gcm :: new ( srtp_block) ;
193
+ let srtp_cipher = AesGcm :: < AES , U12 > :: new ( srtp_block) ;
148
194
149
- let srtcp_session_key = aes_cm_key_derivation (
195
+ let srtcp_session_key = kdf (
150
196
LABEL_SRTCP_ENCRYPTION ,
151
197
master_key,
152
198
master_salt,
@@ -156,29 +202,31 @@ impl CipherAeadAesGcm {
156
202
157
203
let srtcp_block = GenericArray :: from_slice ( & srtcp_session_key) ;
158
204
159
- let srtcp_cipher = Aes128Gcm :: new ( srtcp_block) ;
205
+ let srtcp_cipher = AesGcm :: < AES , U12 > :: new ( srtcp_block) ;
160
206
161
- let srtp_session_salt = aes_cm_key_derivation (
207
+ let srtp_session_salt = kdf (
162
208
LABEL_SRTP_SALT ,
163
209
master_key,
164
210
master_salt,
165
211
0 ,
166
- master_key . len ( ) ,
212
+ master_salt . len ( ) ,
167
213
) ?;
168
214
169
- let srtcp_session_salt = aes_cm_key_derivation (
215
+ let srtcp_session_salt = kdf (
170
216
LABEL_SRTCP_SALT ,
171
217
master_key,
172
218
master_salt,
173
219
0 ,
174
- master_key . len ( ) ,
220
+ master_salt . len ( ) ,
175
221
) ?;
176
222
177
223
Ok ( CipherAeadAesGcm {
224
+ profile,
178
225
srtp_cipher,
179
226
srtcp_cipher,
180
227
srtp_session_salt,
181
228
srtcp_session_salt,
229
+ _tag : PhantomData ,
182
230
} )
183
231
}
184
232
@@ -245,3 +293,52 @@ impl CipherAeadAesGcm {
245
293
aad
246
294
}
247
295
}
296
+
297
+ #[ cfg( test) ]
298
+ mod tests {
299
+ use aes:: { Aes128 , Aes256 } ;
300
+
301
+ use super :: * ;
302
+
303
+ #[ test]
304
+ fn test_aead_aes_gcm_128 ( ) {
305
+ let profile = ProtectionProfile :: AeadAes128Gcm ;
306
+ let master_key = vec ! [ 0u8 ; profile. key_len( ) ] ;
307
+ let master_salt = vec ! [ 0u8 ; 12 ] ;
308
+
309
+ let mut cipher =
310
+ CipherAeadAesGcm :: < Aes128 > :: new ( profile, & master_key, & master_salt) . unwrap ( ) ;
311
+
312
+ let header = rtp:: header:: Header {
313
+ ssrc : 0x12345678 ,
314
+ ..Default :: default ( )
315
+ } ;
316
+
317
+ let payload = vec ! [ 0u8 ; 100 ] ;
318
+ let encrypted = cipher. encrypt_rtp ( & payload, & header, 0 ) . unwrap ( ) ;
319
+
320
+ let decrypted = cipher. decrypt_rtp ( & encrypted, & header, 0 ) . unwrap ( ) ;
321
+ assert_eq ! ( & decrypted[ ..] , & payload[ ..] ) ;
322
+ }
323
+
324
+ #[ test]
325
+ fn test_aead_aes_gcm_256 ( ) {
326
+ let profile = ProtectionProfile :: AeadAes256Gcm ;
327
+ let master_key = vec ! [ 0u8 ; profile. key_len( ) ] ;
328
+ let master_salt = vec ! [ 0u8 ; 12 ] ;
329
+
330
+ let mut cipher =
331
+ CipherAeadAesGcm :: < Aes256 > :: new ( profile, & master_key, & master_salt) . unwrap ( ) ;
332
+
333
+ let header = rtp:: header:: Header {
334
+ ssrc : 0x12345678 ,
335
+ ..Default :: default ( )
336
+ } ;
337
+
338
+ let payload = vec ! [ 0u8 ; 100 ] ;
339
+ let encrypted = cipher. encrypt_rtp ( & payload, & header, 0 ) . unwrap ( ) ;
340
+
341
+ let decrypted = cipher. decrypt_rtp ( & encrypted, & header, 0 ) . unwrap ( ) ;
342
+ assert_eq ! ( & decrypted[ ..] , & payload[ ..] ) ;
343
+ }
344
+ }
0 commit comments