@@ -145,46 +145,29 @@ def _crypt_ctr_oneshot(key: bytes, iv: bytes, plaintext: bytes, max_bytes: Optio
145145 return cipher_out
146146
147147 @staticmethod
148- def _derive_single_key (
149- master_key : bytes ,
150- master_salt : bytes ,
151- key_index : Optional [int ] = 0 ,
152- max_bytes : Optional [int ] = 16
153- ) -> bytes :
154- keysize = len (master_salt )
155- keyout = bytearray (b'\x00 ' * 16 )
156-
157- if keysize >= 14 :
158- keysize = 14
159-
160- if keysize :
161- keyout [13 ] = master_salt [keysize - 1 ]
162- if keysize != 1 :
163- keyout [12 ] = master_salt [keysize - 2 ]
164- if keysize >= 3 :
165- pos = 0
166- for _ in range (2 , keysize ):
167- keyout [pos + 11 ] = master_salt [pos + keysize - 3 ]
168- pos -= 1
169-
170- if keysize <= 13 :
171- null_count = 14 - keysize
172- for i in range (0 , null_count ):
173- keyout [i ] = 0
174-
175- for index in range (14 , 16 ):
176- keyout [index ] = 0
148+ def _derive_single_key (master_key , master_salt , key_index : int = 0 , max_bytes : int = 16 , pkt_i = 0 , key_derivation_rate = 0 ):
149+ import binascii
150+ '''SRTP key derivation, https://tools.ietf.org/html/rfc3711#section-4.3'''
151+
152+ def bytes_to_int (b ):
153+ return int .from_bytes (b , byteorder = 'big' )
154+
155+ def int_to_bytes (i , n_bytes ):
156+ return i .to_bytes (n_bytes , byteorder = 'big' )
157+
158+ assert len (master_key ) == 128 // 8
159+ assert len (master_salt ) == 112 // 8
160+ salt = bytes_to_int (master_salt )
161+
162+ DIV = lambda x , y : 0 if y == 0 else x // y
163+ prng = lambda iv : SrtpContext ._crypt_ctr_oneshot (
164+ master_key , int_to_bytes (iv , 16 ), b'\x00 ' * 16 , max_bytes = max_bytes
165+ )
166+ r = DIV (pkt_i , key_derivation_rate ) # pkt_i is always 48 bits
167+ derive_key_from_label = lambda label : prng (
168+ (salt ^ ((label << 48 ) + r )) << 16 )
177169
178- if key_index :
179- len_before_xor = len (keyout )
180- value_to_xor = struct .unpack_from ('<I' , keyout , 4 )[0 ]
181- value_to_xor ^= (key_index * 0x1000000 )
182- keyout = keyout [:4 ] + struct .pack ('<I' , value_to_xor ) + keyout [8 :]
183- assert len (keyout ) == len_before_xor
184-
185- # Encrypt the key
186- keyout = SrtpContext ._crypt_ctr_oneshot (master_key , keyout , b'\x00 ' * 16 , max_bytes = max_bytes )
187- return keyout
170+ return derive_key_from_label (key_index )
188171
189172 @staticmethod
190173 def _derive_session_keys (master_key : bytes , master_salt : bytes ) -> SrtpSessionKeys :
0 commit comments