summaryrefslogtreecommitdiff
path: root/srtp/crypto/SrtpSymCrypto.h
diff options
context:
space:
mode:
Diffstat (limited to 'srtp/crypto/SrtpSymCrypto.h')
-rw-r--r--srtp/crypto/SrtpSymCrypto.h393
1 files changed, 393 insertions, 0 deletions
diff --git a/srtp/crypto/SrtpSymCrypto.h b/srtp/crypto/SrtpSymCrypto.h
new file mode 100644
index 0000000..1b596c8
--- /dev/null
+++ b/srtp/crypto/SrtpSymCrypto.h
@@ -0,0 +1,393 @@
+/*
+ Copyright (C) 2005, 2004, 2010, 2012 Erik Eliasson, Johan Bilien, 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 AES 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;
+
+/**
+ * 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 Erik Eliasson <eliasson@it.kth.se>
+ * @author Johan Bilien <jobi@via.ecp.fr>
+ * @author Werner Dittmann <Werner.Dittmann@t-online.de>
+ */
+class SrtpSymCrypto {
+public:
+ SrtpSymCrypto(int algo = SrtpEncryptionAESCM);
+
+ /**
+ * Constructor that initializes key data
+ *
+ * @param key
+ * Pointer to key bytes.
+ * @param key_length
+ * Number of key bytes.
+ */
+ SrtpSymCrypto(uint8_t* key, int32_t key_length, int algo = SrtpEncryptionAESCM);
+
+ ~SrtpSymCrypto();
+
+ /**
+ * Encrypts the inpout to the output.
+ *
+ * Encrypts one input block to one output block. Each block
+ * is 16 bytes according to the AES encryption algorithm 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 );
+
+ /**
+ * 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);
+
+ /**
+ * 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);
+
+ /**
+ * Counter-mode encryption.
+ *
+ * This method performs the AES 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 );
+
+ /**
+ * Counter-mode encryption, in place.
+ *
+ * This method performs the AES 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 );
+
+ /**
+ * Derive a AES context to compute the IV'.
+ *
+ * See chapter 4.1.2.1 in RFC 3711.
+ *
+ * @param f8Cipher
+ * Pointer to the AES 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);
+
+ /**
+ * AES F8 mode encryption, in place.
+ *
+ * This method performs the AES 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);
+
+ /**
+ * AES F8 mode encryption.
+ *
+ * This method performs the AES 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 define the MAKE_F8_TEST */
+#ifdef MAKE_F8_TEST
+
+#include <cstring>
+#include <iostream>
+#include <cstdio>
+#include <arpa/inet.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] = htonl(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
+
+/** EMACS **
+ * Local variables:
+ * mode: c++
+ * c-default-style: ellemtel
+ * c-basic-offset: 4
+ * End:
+ */
+