/// <summary> /// Regardless of the encryption or message authentication transform that /// is employed (it may be an SRTP pre-defined transform or newly /// introduced according to Section 6), interoperable SRTP /// implementations MUST use the SRTP key derivation to generate session /// keys. Once the key derivation rate is properly signaled at the start /// of the session, there is no need for extra communication between the /// parties that use SRTP key derivation. /// /// https://tools.ietf.org/html/rfc3711#section-4.3 /// </summary> private void DeriveKeys(SrtpStreamContext srtpStreamContext, int packetIndex, byte[] masterKey, byte[] masterSalt) { /* * At least one initial key derivation SHALL be performed by SRTP, i.e., * the first key derivation is REQUIRED. Further applications of the * key derivation MAY be performed, according to the * "key_derivation_rate" value in the cryptographic context. The key * derivation function SHALL initially be invoked before the first * packet and then, when r > 0, a key derivation is performed whenever * index mod r equals zero. This can be thought of as "refreshing" the * session keys. The value of "key_derivation_rate" MUST be kept fixed * for the lifetime of the associated master key. */ /* * Let "a DIV t" denote integer division of a by t, rounded down, and * with the convention that "a DIV 0 = 0" for all a. We also make the * convention of treating "a DIV t" as a bit string of the same length * as a, and thus "a DIV t" will in general have leading zeros. * * Let r = index DIV key_derivation_rate (with DIV as defined above). */ var kdr = srtpStreamContext.KeyDerivationRate; var r = (uint)(kdr == 0 ? 0 : packetIndex / kdr); var shouldDeriveKeys = srtpStreamContext.DerivedKeys is null || r > 0 && packetIndex % r == 0; if (!shouldDeriveKeys) { return; } var derivedKeys = new SrtpDerivedkeys(); derivedKeys.SessionKey = DeriveKey(masterKey, masterSalt, r, SrtpEncryptionKeyLabel.SrtpEncryptionKey, SrtpConstants.SrtpDefaultEncryptionSessionKeyLength); derivedKeys.AuthKey = DeriveKey(masterKey, masterSalt, r, SrtpEncryptionKeyLabel.SrtpMessageAuthenticationKey, SrtpConstants.SrtpDefaultAuthSessionKeyLength); derivedKeys.CipherSalt = DeriveKey(masterKey, masterSalt, r, SrtpEncryptionKeyLabel.SrtpSaltingKey, SrtpConstants.SrtpDefaultSaltSessionKeyLength); srtpStreamContext.DerivedKeys = derivedKeys; }
private static byte[] EncryptPayloadWithAesCtrMode(SrtpDerivedkeys derivedKeys, uint ssrc, byte[] rtpBody, int packetIndex) { var sessionKey = derivedKeys.SessionKey; var cipherSalt = derivedKeys.CipherSalt; // where the 128-bit integer value IV SHALL be defined by the SSRC, the // SRTP packet index i, and the SRTP session salting key k_s, as below. // // IV = (k_s * 2^16) XOR (SSRC * 2^64) XOR (i * 2^16) var iv = cipherSalt.ShiftLeft(16) .Xor(BitConverter.GetBytes(IPAddress.HostToNetworkOrder(ssrc)).ShiftLeft(64)) .Xor(BitConverter.GetBytes(IPAddress.HostToNetworkOrder(packetIndex)).ShiftLeft(16)); var encrypted = AesCounterMode.Encrypt(sessionKey, iv, rtpBody); return(encrypted); }