/** * Perform F8 Mode AES encryption / decryption * * @param pkt the RTP packet to be encrypted / decrypted */ public void ProcessPacketAESF8(RawPacket pkt, int index) { // byte[] iv = new byte[16]; // 4 bytes of the iv are zero // the first byte of the RTP header is not used. ivStore[0] = 0; ivStore[1] = 0; ivStore[2] = 0; ivStore[3] = 0; // Need the encryption flag index = (int)(index | 0x80000000); // set the index and the encrypt flag in network order into IV ivStore[4] = (byte)(index >> 24); ivStore[5] = (byte)(index >> 16); ivStore[6] = (byte)(index >> 8); ivStore[7] = (byte)index; // The fixed header follows and fills the rest of the IV MemoryStream buf = pkt.GetBuffer(); buf.Position = 0; buf.Read(ivStore, 8, 8); // Encrypted part excludes fixed header (8 bytes), index (4 bytes), and // authentication tag (variable according to policy) int payloadOffset = 8; int payloadLength = pkt.GetLength() - (4 + policy.AuthTagLength); SrtpCipherF8.Process(cipher, pkt.GetBuffer(), payloadOffset, payloadLength, ivStore, cipherF8); }
/** * Authenticate a packet. * * Calculated authentication tag is stored in tagStore area. * * @param pkt the RTP packet to be authenticated */ private void AuthenticatePacket(RawPacket pkt, int index) { MemoryStream buf = pkt.GetBuffer(); buf.Position = 0; int len = pkt.GetLength(); buf.Read(tempBuffer, 0, len); mac.BlockUpdate(tempBuffer, 0, len); rbStore[0] = (byte)(index >> 24); rbStore[1] = (byte)(index >> 16); rbStore[2] = (byte)(index >> 8); rbStore[3] = (byte)index; mac.BlockUpdate(rbStore, 0, rbStore.Length); mac.DoFinal(tagStore, 0); }
/** * Perform Counter Mode AES encryption / decryption * @param pkt the RTP packet to be encrypted / decrypted */ public void ProcessPacketAESCM(RawPacket pkt, int index) { long ssrc = pkt.GetRTCPSSRC(); /* Compute the CM IV (refer to chapter 4.1.1 in RFC 3711): * * k_s XX XX XX XX XX XX XX XX XX XX XX XX XX XX * SSRC XX XX XX XX * index XX XX XX XX * ------------------------------------------------------XOR * IV XX XX XX XX XX XX XX XX XX XX XX XX XX XX 00 00 * 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 */ ivStore[0] = saltKey[0]; ivStore[1] = saltKey[1]; ivStore[2] = saltKey[2]; ivStore[3] = saltKey[3]; // The shifts transform the ssrc and index into network order ivStore[4] = (byte)(((ssrc >> 24) & 0xff) ^ this.saltKey[4]); ivStore[5] = (byte)(((ssrc >> 16) & 0xff) ^ this.saltKey[5]); ivStore[6] = (byte)(((ssrc >> 8) & 0xff) ^ this.saltKey[6]); ivStore[7] = (byte)((ssrc & 0xff) ^ this.saltKey[7]); ivStore[8] = saltKey[8]; ivStore[9] = saltKey[9]; ivStore[10] = (byte)(((index >> 24) & 0xff) ^ this.saltKey[10]); ivStore[11] = (byte)(((index >> 16) & 0xff) ^ this.saltKey[11]); ivStore[12] = (byte)(((index >> 8) & 0xff) ^ this.saltKey[12]); ivStore[13] = (byte)((index & 0xff) ^ this.saltKey[13]); ivStore[14] = ivStore[15] = 0; // Encrypted part excludes fixed header (8 bytes) int payloadOffset = 8; int payloadLength = pkt.GetLength() - payloadOffset; cipherCtr.Process(cipher, pkt.GetBuffer(), payloadOffset, payloadLength, ivStore); }
/** * Transform a SRTP packet into a RTP packet. This method is called when a * SRTP packet is received. * * Operations done by the this operation include: Authentication check, * Packet replay check and Decryption. * * Both encryption and authentication functionality can be turned off as * long as the SRTPPolicy used in this SRTPCryptoContext requires no * encryption and no authentication. Then the packet will be sent out * untouched. However this is not encouraged. If no SRTP feature is enabled, * then we shall not use SRTP TransformConnector. We should use the original * method (RTPManager managed transportation) instead. * * @param pkt * the RTP packet that is just received * @return true if the packet can be accepted false if the packet failed * authentication or failed replay check */ public bool ReverseTransformPacket(RawPacket pkt) { int seqNo = pkt.GetSequenceNumber(); if (!seqNumSet) { seqNumSet = true; seqNum = seqNo; } // Guess the SRTP index (48 bit), see rFC 3711, 3.3.1 // Stores the guessed roc in this.guessedROC long guessedIndex = GuessIndex(seqNo); // Replay control if (!CheckReplay(seqNo, guessedIndex)) { return(false); } // Authenticate packet if (policy.AuthType != SrtpPolicy.NULL_AUTHENTICATION) { int tagLength = policy.AuthTagLength; // get original authentication and store in tempStore pkt.ReadRegionToBuff(pkt.GetLength() - tagLength, tagLength, tempStore); pkt.shrink(tagLength); // save computed authentication in tagStore AuthenticatePacketHMCSHA1(pkt, guessedROC); for (int i = 0; i < tagLength; i++) { if ((tempStore[i] & 0xff) != (tagStore[i] & 0xff)) { return(false); } } } // Decrypt packet switch (policy.EncType) { case SrtpPolicy.AESCM_ENCRYPTION: case SrtpPolicy.TWOFISH_ENCRYPTION: // using Counter Mode encryption ProcessPacketAESCM(pkt); break; case SrtpPolicy.AESF8_ENCRYPTION: case SrtpPolicy.TWOFISHF8_ENCRYPTION: // using F8 Mode encryption ProcessPacketAESF8(pkt); break; default: return(false); } Update(seqNo, guessedIndex); return(true); }
/** * Transform a SRTCP packet into a RTCP packet. * This method is called when a SRTCP packet was received. * * Operations done by the this operation include: * Authentication check, Packet replay check and decryption. * * Both encryption and authentication functionality can be turned off * as long as the SRTPPolicy used in this SRTPCryptoContext requires no * encryption and no authentication. Then the packet will be sent out * untouched. However this is not encouraged. If no SRTCP feature is enabled, * then we shall not use SRTP TransformConnector. We should use the original * method (RTPManager managed transportation) instead. * * @param pkt the received RTCP packet * @return true if the packet can be accepted * false if authentication or replay check failed */ public bool ReverseTransformPacket(RawPacket pkt) { bool decrypt = false; int tagLength = policy.AuthTagLength; int indexEflag = pkt.GetSRTCPIndex(tagLength); if ((indexEflag & 0x80000000) == 0x80000000) { decrypt = true; } int index = (int)(indexEflag & ~0x80000000); /* Replay control */ if (!CheckReplay(index)) { return(false); } /* Authenticate the packet */ if (policy.AuthType != SrtpPolicy.NULL_AUTHENTICATION) { // get original authentication data and store in tempStore pkt.ReadRegionToBuff(pkt.GetLength() - tagLength, tagLength, tempStore); // Shrink packet to remove the authentication tag and index // because this is part of authenicated data pkt.shrink(tagLength + 4); // compute, then save authentication in tagStore AuthenticatePacket(pkt, indexEflag); for (int i = 0; i < tagLength; i++) { if ((tempStore[i] & 0xff) == (tagStore[i] & 0xff)) { continue; } else { return(false); } } } if (decrypt) { /* Decrypt the packet using Counter Mode encryption */ if (policy.EncType == SrtpPolicy.AESCM_ENCRYPTION || policy.EncType == SrtpPolicy.TWOFISH_ENCRYPTION) { ProcessPacketAESCM(pkt, index); } /* Decrypt the packet using F8 Mode encryption */ else if (policy.EncType == SrtpPolicy.AESF8_ENCRYPTION || policy.EncType == SrtpPolicy.TWOFISHF8_ENCRYPTION) { ProcessPacketAESF8(pkt, index); } } Update(index); return(true); }