/* | |
Copyright (C) 2008-2012 Werner Dittmann | |
This library is free software; you can redistribute it and/or | |
modify it under the terms of the GNU Lesser General Public | |
License as published by the Free Software Foundation; either | |
version 2.1 of the License, or (at your option) any later version. | |
This library is distributed in the hope that it will be useful, | |
but WITHOUT ANY WARRANTY; without even the implied warranty of | |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
Lesser General Public License for more details. | |
You should have received a copy of the GNU Lesser General Public | |
License along with this library; if not, write to the Free Software | |
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
* In addition, as a special exception, the copyright holders give | |
* permission to link the code of portions of this program with the | |
* OpenSSL library under certain conditions as described in each | |
* individual source file, and distribute linked combinations | |
* including the two. | |
* You must obey the GNU General Public License in all respects | |
* for all of the code used other than OpenSSL. If you modify | |
* file(s) with this exception, you may extend this exception to your | |
* version of the file(s), but you are not obligated to do so. If you | |
* do not wish to do so, delete this exception statement from your | |
* version. If you delete this exception statement from all source | |
* files in the program, then also delete it here. | |
*/ | |
#ifndef SRTPSYMCRYPTO_H | |
#define SRTPSYMCRYPTO_H | |
/** | |
* @file SrtpSymCrypto.h | |
* @brief Class which implements SRTP cryptographic functions | |
* | |
* @ingroup GNU_ZRTP | |
* @{ | |
*/ | |
#include <stdint.h> | |
#include <CryptoContext.h> | |
#ifndef SRTP_BLOCK_SIZE | |
#define SRTP_BLOCK_SIZE 16 | |
#endif | |
typedef struct _f8_ctx { | |
unsigned char *S; ///< Intermetiade buffer | |
unsigned char *ivAccent; ///< second IV | |
uint32_t J; ///< Counter | |
} F8_CIPHER_CTX; | |
/** | |
* @brief Implments the SRTP encryption modes as defined in RFC3711 | |
* | |
* The SRTP specification defines two encryption modes, AES-CTR | |
* (AES Counter mode) and AES-F8 mode. The AES-CTR is required, | |
* AES-F8 is optional. | |
* | |
* Both modes are desinged to encrypt/decrypt data of arbitrary length | |
* (with a specified upper limit, refer to RFC 3711). These modes do | |
* <em>not</em> require that the amount of data to encrypt is a multiple | |
* of the AES blocksize (16 bytes), no padding is necessary. | |
* | |
* The implementation uses the openSSL library as its cryptographic | |
* backend. | |
* | |
* @author Werner Dittmann <Werner.Dittmann@t-online.de> | |
*/ | |
class SrtpSymCrypto { | |
public: | |
/** | |
* @brief Constructor that does not initialize key data | |
* | |
* @param algo | |
* The Encryption algorithm to use.Possible values are <code> | |
* SrtpEncryptionNull, SrtpEncryptionAESCM, SrtpEncryptionAESF8 | |
* SrtpEncryptionTWOCM, SrtpEncryptionTWOF8</code>. See chapter 4.1.1 | |
* for CM (Counter mode) and 4.1.2 for F8 mode. | |
*/ | |
SrtpSymCrypto(int algo = SrtpEncryptionAESCM); | |
/** | |
* @brief Constructor that initializes key data | |
* | |
* @param key | |
* Pointer to key bytes. | |
* @param key_length | |
* Number of key bytes. | |
* @param algo | |
* The Encryption algorithm to use.Possible values are <code> | |
* SrtpEncryptionNull, SrtpEncryptionAESCM, SrtpEncryptionAESF8 | |
* SrtpEncryptionTWOCM, SrtpEncryptionTWOF8</code>. See chapter 4.1.1 | |
* for CM (Counter mode) and 4.1.2 for F8 mode. | |
*/ | |
SrtpSymCrypto(uint8_t* key, int32_t key_length, int algo = SrtpEncryptionAESCM); | |
~SrtpSymCrypto(); | |
/** | |
* @brief Encrypts the input to the output. | |
* | |
* Encrypts one input block to one output block. Each block | |
* is 16 bytes according to the encryption algorithms used. | |
* | |
* @param input | |
* Pointer to input block, must be 16 bytes | |
* | |
* @param output | |
* Pointer to output block, must be 16 bytes | |
*/ | |
void encrypt( const uint8_t* input, uint8_t* output ); | |
/** | |
* @brief Set new key | |
* | |
* @param key | |
* Pointer to key data, must have at least a size of keyLength | |
* | |
* @param keyLength | |
* Length of the key in bytes, must be 16, 24, or 32 | |
* | |
* @return | |
* false if key could not set. | |
*/ | |
bool setNewKey(const uint8_t* key, int32_t keyLength); | |
/** | |
* @brief Computes the cipher stream for AES CM mode. | |
* | |
* @param output | |
* Pointer to a buffer that receives the cipher stream. Must be | |
* at least <code>length</code> bytes long. | |
* | |
* @param length | |
* Number of cipher stream bytes to produce. Usually the same | |
* length as the data to be encrypted. | |
* | |
* @param iv | |
* The initialization vector as input to create the cipher stream. | |
* Refer to chapter 4.1.1 in RFC 3711. | |
*/ | |
void get_ctr_cipher_stream(uint8_t* output, uint32_t length, uint8_t* iv); | |
/** | |
* @brief Counter-mode encryption. | |
* | |
* This method performs the CM encryption. | |
* | |
* @param input | |
* Pointer to input buffer, must be <code>inputLen</code> bytes. | |
* | |
* @param inputLen | |
* Number of bytes to process. | |
* | |
* @param output | |
* Pointer to output buffer, must be <code>inputLen</code> bytes. | |
* | |
* @param iv | |
* The initialization vector as input to create the cipher stream. | |
* Refer to chapter 4.1.1 in RFC 3711. | |
*/ | |
void ctr_encrypt(const uint8_t* input, uint32_t inputLen, uint8_t* output, uint8_t* iv ); | |
/** | |
* @brief Counter-mode encryption, in place. | |
* | |
* This method performs the CM encryption. | |
* | |
* @param data | |
* Pointer to input and output block, must be <code>dataLen</code> | |
* bytes. | |
* | |
* @param data_length | |
* Number of bytes to process. | |
* | |
* @param iv | |
* The initialization vector as input to create the cipher stream. | |
* Refer to chapter 4.1.1 in RFC 3711. | |
*/ | |
void ctr_encrypt(uint8_t* data, uint32_t data_length, uint8_t* iv ); | |
/** | |
* @brief Derive a cipher context to compute the IV'. | |
* | |
* See chapter 4.1.2.1 in RFC 3711. | |
* | |
* @param f8Cipher | |
* Pointer to the cipher context that will be used to encrypt IV to IV' | |
* | |
* @param key | |
* The master key | |
* | |
* @param keyLen | |
* Length of the master key. | |
* | |
* @param salt | |
* Master salt. | |
* | |
* @param saltLen | |
* length of master salt. | |
*/ | |
void f8_deriveForIV(SrtpSymCrypto* f8Cipher, uint8_t* key, int32_t keyLen, uint8_t* salt, int32_t saltLen); | |
/** | |
* @brief F8 mode encryption, in place. | |
* | |
* This method performs the F8 encryption, see chapter 4.1.2 in RFC 3711. | |
* | |
* @param data | |
* Pointer to input and output block, must be <code>dataLen</code> | |
* bytes. | |
* | |
* @param dataLen | |
* Number of bytes to process. | |
* | |
* @param iv | |
* The initialization vector as input to create the cipher stream. | |
* Refer to chapter 4.1.1 in RFC 3711. | |
* | |
* @param f8Cipher | |
* An AES cipher context used to encrypt IV to IV'. | |
*/ | |
void f8_encrypt(const uint8_t* data, uint32_t dataLen, uint8_t* iv, SrtpSymCrypto* f8Cipher); | |
/** | |
* @brief F8 mode encryption. | |
* | |
* This method performs the F8 encryption, see chapter 4.1.2 in RFC 3711. | |
* | |
* @param data | |
* Pointer to input and output block, must be <code>dataLen</code> | |
* bytes. | |
* | |
* @param dataLen | |
* Number of bytes to process. | |
* | |
* @param out | |
* Pointer to output buffer, must be <code>dataLen</code> bytes. | |
* | |
* @param iv | |
* The initialization vector as input to create the cipher stream. | |
* Refer to chapter 4.1.1 in RFC 3711. | |
* | |
* @param f8Cipher | |
* An AES cipher context used to encrypt IV to IV'. | |
*/ | |
void f8_encrypt(const uint8_t* data, uint32_t dataLen, uint8_t* out, uint8_t* iv, SrtpSymCrypto* f8Cipher); | |
private: | |
int processBlock(F8_CIPHER_CTX* f8ctx, const uint8_t* in, int32_t length, uint8_t* out); | |
void* key; | |
int32_t algorithm; | |
}; | |
#pragma GCC visibility push(default) | |
int testF8(); | |
#pragma GCC visibility pop | |
/* Only SrtpSymCrypto functions defines the MAKE_F8_TEST */ | |
#ifdef MAKE_F8_TEST | |
#include <cstring> | |
#include <iostream> | |
#include <cstdio> | |
#include <common/osSpecifics.h> | |
using namespace std; | |
static void hexdump(const char* title, const unsigned char *s, int l) | |
{ | |
int n=0; | |
if (s == NULL) return; | |
fprintf(stderr, "%s",title); | |
for( ; n < l ; ++n) { | |
if((n%16) == 0) | |
fprintf(stderr, "\n%04x",n); | |
fprintf(stderr, " %02x",s[n]); | |
} | |
fprintf(stderr, "\n"); | |
} | |
/* | |
* The F8 test vectors according to RFC3711 | |
*/ | |
static unsigned char salt[] = {0x32, 0xf2, 0x87, 0x0d}; | |
static unsigned char iv[] = { 0x00, 0x6e, 0x5c, 0xba, 0x50, 0x68, 0x1d, 0xe5, | |
0x5c, 0x62, 0x15, 0x99, 0xd4, 0x62, 0x56, 0x4a}; | |
static unsigned char key[]= { 0x23, 0x48, 0x29, 0x00, 0x84, 0x67, 0xbe, 0x18, | |
0x6c, 0x3d, 0xe1, 0x4a, 0xae, 0x72, 0xd6, 0x2c}; | |
static unsigned char payload[] = { | |
0x70, 0x73, 0x65, 0x75, 0x64, 0x6f, 0x72, 0x61, | |
0x6e, 0x64, 0x6f, 0x6d, 0x6e, 0x65, 0x73, 0x73, | |
0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, | |
0x6e, 0x65, 0x78, 0x74, 0x20, 0x62, 0x65, 0x73, | |
0x74, 0x20, 0x74, 0x68, 0x69, 0x6e, 0x67}; // 39 bytes | |
static unsigned char cipherText[] = { | |
0x01, 0x9c, 0xe7, 0xa2, 0x6e, 0x78, 0x54, 0x01, | |
0x4a, 0x63, 0x66, 0xaa, 0x95, 0xd4, 0xee, 0xfd, | |
0x1a, 0xd4, 0x17, 0x2a, 0x14, 0xf9, 0xfa, 0xf4, | |
0x55, 0xb7, 0xf1, 0xd4, 0xb6, 0x2b, 0xd0, 0x8f, | |
0x56, 0x2c, 0x0e, 0xef, 0x7c, 0x48, 0x02}; // 39 bytes | |
// static unsigned char rtpPacketHeader[] = { | |
// 0x80, 0x6e, 0x5c, 0xba, 0x50, 0x68, 0x1d, 0xe5, | |
// 0x5c, 0x62, 0x15, 0x99}; | |
static unsigned char rtpPacket[] = { | |
0x80, 0x6e, 0x5c, 0xba, 0x50, 0x68, 0x1d, 0xe5, | |
0x5c, 0x62, 0x15, 0x99, // header | |
0x70, 0x73, 0x65, 0x75, 0x64, 0x6f, 0x72, 0x61, // payload | |
0x6e, 0x64, 0x6f, 0x6d, 0x6e, 0x65, 0x73, 0x73, | |
0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, | |
0x6e, 0x65, 0x78, 0x74, 0x20, 0x62, 0x65, 0x73, | |
0x74, 0x20, 0x74, 0x68, 0x69, 0x6e, 0x67}; | |
static uint32_t ROC = 0xd462564a; | |
int testF8() | |
{ | |
SrtpSymCrypto* aesCipher = new SrtpSymCrypto(SrtpEncryptionAESF8); | |
SrtpSymCrypto* f8AesCipher = new SrtpSymCrypto(SrtpEncryptionAESF8); | |
aesCipher->setNewKey(key, sizeof(key)); | |
/* Create the F8 IV (refer to chapter 4.1.2.2 in RFC 3711): | |
* | |
* IV = 0x00 || M || PT || SEQ || TS || SSRC || ROC | |
* 8Bit 1bit 7bit 16bit 32bit 32bit 32bit | |
* ------------\ /-------------------------------------------------- | |
* XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX | |
*/ | |
unsigned char derivedIv[16]; | |
uint32_t* ui32p = (uint32_t*)derivedIv; | |
memcpy(derivedIv, rtpPacket, 12); | |
derivedIv[0] = 0; | |
// set ROC in network order into IV | |
ui32p[3] = zrtpHtonl(ROC); | |
int32_t pad = 0; | |
if (memcmp(iv, derivedIv, 16) != 0) { | |
cerr << "Wrong IV constructed" << endl; | |
hexdump("derivedIv", derivedIv, 16); | |
hexdump("test vector Iv", iv, 16); | |
return -1; | |
} | |
aesCipher->f8_deriveForIV(f8AesCipher, key, sizeof(key), salt, sizeof(salt)); | |
// now encrypt the RTP payload data | |
aesCipher->f8_encrypt(rtpPacket + 12, sizeof(rtpPacket)-12+pad, | |
derivedIv, f8AesCipher); | |
// compare with test vector cipher data | |
if (memcmp(rtpPacket+12, cipherText, sizeof(rtpPacket)-12+pad) != 0) { | |
cerr << "cipher data mismatch" << endl; | |
hexdump("computed cipher data", rtpPacket+12, sizeof(rtpPacket)-12+pad); | |
hexdump("Test vcetor cipher data", cipherText, sizeof(cipherText)); | |
return -1; | |
} | |
// Now decrypt the data to get the payload data again | |
aesCipher->f8_encrypt(rtpPacket+12, sizeof(rtpPacket)-12+pad, derivedIv, f8AesCipher); | |
// compare decrypted data with test vector payload data | |
if (memcmp(rtpPacket+12, payload, sizeof(rtpPacket)-12+pad) != 0) { | |
cerr << "payload data mismatch" << endl; | |
hexdump("computed payload data", rtpPacket+12, sizeof(rtpPacket)-12+pad); | |
hexdump("Test vector payload data", payload, sizeof(payload)); | |
return -1; | |
} | |
return 0; | |
} | |
#endif | |
/** | |
* @} | |
*/ | |
#endif | |