Alexandre Lision | 51140e1 | 2013-12-02 10:54:09 -0500 | [diff] [blame] | 1 | /*
|
Alexandre Lision | e24852d | 2014-02-04 13:13:02 -0500 | [diff] [blame] | 2 | Copyright (C) 2005, 2004, 2010, 2012 Erik Eliasson, Johan Bilien, Werner Dittmann
|
Alexandre Lision | 51140e1 | 2013-12-02 10:54:09 -0500 | [diff] [blame] | 3 |
|
| 4 | This library is free software; you can redistribute it and/or
|
| 5 | modify it under the terms of the GNU Lesser General Public
|
| 6 | License as published by the Free Software Foundation; either
|
| 7 | version 2.1 of the License, or (at your option) any later version.
|
| 8 |
|
| 9 | This library is distributed in the hope that it will be useful,
|
| 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
| 12 | Lesser General Public License for more details.
|
| 13 |
|
| 14 | You should have received a copy of the GNU Lesser General Public
|
| 15 | License along with this library; if not, write to the Free Software
|
| 16 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
| 17 |
|
| 18 | * In addition, as a special exception, the copyright holders give
|
| 19 | * permission to link the code of portions of this program with the
|
| 20 | * OpenSSL library under certain conditions as described in each
|
| 21 | * individual source file, and distribute linked combinations
|
| 22 | * including the two.
|
| 23 | * You must obey the GNU General Public License in all respects
|
| 24 | * for all of the code used other than OpenSSL. If you modify
|
| 25 | * file(s) with this exception, you may extend this exception to your
|
| 26 | * version of the file(s), but you are not obligated to do so. If you
|
| 27 | * do not wish to do so, delete this exception statement from your
|
| 28 | * version. If you delete this exception statement from all source
|
| 29 | * files in the program, then also delete it here.
|
| 30 | */
|
| 31 |
|
| 32 |
|
| 33 |
|
| 34 | #ifndef SRTPSYMCRYPTO_H
|
| 35 | #define SRTPSYMCRYPTO_H
|
| 36 |
|
| 37 | /**
|
| 38 | * @file SrtpSymCrypto.h
|
Alexandre Lision | e24852d | 2014-02-04 13:13:02 -0500 | [diff] [blame] | 39 | * @brief Class which implements SRTP AES cryptographic functions
|
Alexandre Lision | 51140e1 | 2013-12-02 10:54:09 -0500 | [diff] [blame] | 40 | *
|
| 41 | * @ingroup GNU_ZRTP
|
| 42 | * @{
|
| 43 | */
|
| 44 |
|
| 45 | #include <stdint.h>
|
| 46 | #include <CryptoContext.h>
|
| 47 |
|
| 48 | #ifndef SRTP_BLOCK_SIZE
|
| 49 | #define SRTP_BLOCK_SIZE 16
|
| 50 | #endif
|
| 51 |
|
| 52 | typedef struct _f8_ctx {
|
| 53 | unsigned char *S; ///< Intermetiade buffer
|
| 54 | unsigned char *ivAccent; ///< second IV
|
| 55 | uint32_t J; ///< Counter
|
| 56 | } F8_CIPHER_CTX;
|
| 57 |
|
| 58 | /**
|
Alexandre Lision | e24852d | 2014-02-04 13:13:02 -0500 | [diff] [blame] | 59 | * Implments the SRTP encryption modes as defined in RFC3711
|
Alexandre Lision | 51140e1 | 2013-12-02 10:54:09 -0500 | [diff] [blame] | 60 | *
|
| 61 | * The SRTP specification defines two encryption modes, AES-CTR
|
| 62 | * (AES Counter mode) and AES-F8 mode. The AES-CTR is required,
|
| 63 | * AES-F8 is optional.
|
| 64 | *
|
| 65 | * Both modes are desinged to encrypt/decrypt data of arbitrary length
|
| 66 | * (with a specified upper limit, refer to RFC 3711). These modes do
|
| 67 | * <em>not</em> require that the amount of data to encrypt is a multiple
|
| 68 | * of the AES blocksize (16 bytes), no padding is necessary.
|
| 69 | *
|
| 70 | * The implementation uses the openSSL library as its cryptographic
|
| 71 | * backend.
|
| 72 | *
|
Alexandre Lision | e24852d | 2014-02-04 13:13:02 -0500 | [diff] [blame] | 73 | * @author Erik Eliasson <eliasson@it.kth.se>
|
| 74 | * @author Johan Bilien <jobi@via.ecp.fr>
|
Alexandre Lision | 51140e1 | 2013-12-02 10:54:09 -0500 | [diff] [blame] | 75 | * @author Werner Dittmann <Werner.Dittmann@t-online.de>
|
| 76 | */
|
| 77 | class SrtpSymCrypto {
|
| 78 | public:
|
| 79 | SrtpSymCrypto(int algo = SrtpEncryptionAESCM);
|
| 80 |
|
| 81 | /**
|
Alexandre Lision | e24852d | 2014-02-04 13:13:02 -0500 | [diff] [blame] | 82 | * Constructor that initializes key data
|
Alexandre Lision | 51140e1 | 2013-12-02 10:54:09 -0500 | [diff] [blame] | 83 | *
|
| 84 | * @param key
|
| 85 | * Pointer to key bytes.
|
| 86 | * @param key_length
|
| 87 | * Number of key bytes.
|
| 88 | */
|
| 89 | SrtpSymCrypto(uint8_t* key, int32_t key_length, int algo = SrtpEncryptionAESCM);
|
| 90 |
|
| 91 | ~SrtpSymCrypto();
|
| 92 |
|
| 93 | /**
|
Alexandre Lision | e24852d | 2014-02-04 13:13:02 -0500 | [diff] [blame] | 94 | * Encrypts the inpout to the output.
|
Alexandre Lision | 51140e1 | 2013-12-02 10:54:09 -0500 | [diff] [blame] | 95 | *
|
| 96 | * Encrypts one input block to one output block. Each block
|
Alexandre Lision | e24852d | 2014-02-04 13:13:02 -0500 | [diff] [blame] | 97 | * is 16 bytes according to the AES encryption algorithm used.
|
Alexandre Lision | 51140e1 | 2013-12-02 10:54:09 -0500 | [diff] [blame] | 98 | *
|
| 99 | * @param input
|
| 100 | * Pointer to input block, must be 16 bytes
|
| 101 | *
|
| 102 | * @param output
|
| 103 | * Pointer to output block, must be 16 bytes
|
| 104 | */
|
| 105 | void encrypt( const uint8_t* input, uint8_t* output );
|
| 106 |
|
| 107 | /**
|
Alexandre Lision | e24852d | 2014-02-04 13:13:02 -0500 | [diff] [blame] | 108 | * Set new key
|
Alexandre Lision | 51140e1 | 2013-12-02 10:54:09 -0500 | [diff] [blame] | 109 | *
|
| 110 | * @param key
|
| 111 | * Pointer to key data, must have at least a size of keyLength
|
| 112 | *
|
| 113 | * @param keyLength
|
| 114 | * Length of the key in bytes, must be 16, 24, or 32
|
| 115 | *
|
| 116 | * @return
|
| 117 | * false if key could not set.
|
| 118 | */
|
| 119 | bool setNewKey(const uint8_t* key, int32_t keyLength);
|
| 120 |
|
| 121 | /**
|
Alexandre Lision | e24852d | 2014-02-04 13:13:02 -0500 | [diff] [blame] | 122 | * Computes the cipher stream for AES CM mode.
|
Alexandre Lision | 51140e1 | 2013-12-02 10:54:09 -0500 | [diff] [blame] | 123 | *
|
| 124 | * @param output
|
| 125 | * Pointer to a buffer that receives the cipher stream. Must be
|
| 126 | * at least <code>length</code> bytes long.
|
| 127 | *
|
| 128 | * @param length
|
| 129 | * Number of cipher stream bytes to produce. Usually the same
|
| 130 | * length as the data to be encrypted.
|
| 131 | *
|
| 132 | * @param iv
|
| 133 | * The initialization vector as input to create the cipher stream.
|
| 134 | * Refer to chapter 4.1.1 in RFC 3711.
|
| 135 | */
|
| 136 | void get_ctr_cipher_stream(uint8_t* output, uint32_t length, uint8_t* iv);
|
| 137 |
|
| 138 | /**
|
Alexandre Lision | e24852d | 2014-02-04 13:13:02 -0500 | [diff] [blame] | 139 | * Counter-mode encryption.
|
Alexandre Lision | 51140e1 | 2013-12-02 10:54:09 -0500 | [diff] [blame] | 140 | *
|
Alexandre Lision | e24852d | 2014-02-04 13:13:02 -0500 | [diff] [blame] | 141 | * This method performs the AES CM encryption.
|
Alexandre Lision | 51140e1 | 2013-12-02 10:54:09 -0500 | [diff] [blame] | 142 | *
|
| 143 | * @param input
|
| 144 | * Pointer to input buffer, must be <code>inputLen</code> bytes.
|
| 145 | *
|
| 146 | * @param inputLen
|
| 147 | * Number of bytes to process.
|
| 148 | *
|
| 149 | * @param output
|
| 150 | * Pointer to output buffer, must be <code>inputLen</code> bytes.
|
| 151 | *
|
| 152 | * @param iv
|
| 153 | * The initialization vector as input to create the cipher stream.
|
| 154 | * Refer to chapter 4.1.1 in RFC 3711.
|
| 155 | */
|
| 156 | void ctr_encrypt(const uint8_t* input, uint32_t inputLen, uint8_t* output, uint8_t* iv );
|
| 157 |
|
| 158 | /**
|
Alexandre Lision | e24852d | 2014-02-04 13:13:02 -0500 | [diff] [blame] | 159 | * Counter-mode encryption, in place.
|
Alexandre Lision | 51140e1 | 2013-12-02 10:54:09 -0500 | [diff] [blame] | 160 | *
|
Alexandre Lision | e24852d | 2014-02-04 13:13:02 -0500 | [diff] [blame] | 161 | * This method performs the AES CM encryption.
|
Alexandre Lision | 51140e1 | 2013-12-02 10:54:09 -0500 | [diff] [blame] | 162 | *
|
| 163 | * @param data
|
| 164 | * Pointer to input and output block, must be <code>dataLen</code>
|
| 165 | * bytes.
|
| 166 | *
|
| 167 | * @param data_length
|
| 168 | * Number of bytes to process.
|
| 169 | *
|
| 170 | * @param iv
|
| 171 | * The initialization vector as input to create the cipher stream.
|
| 172 | * Refer to chapter 4.1.1 in RFC 3711.
|
| 173 | */
|
| 174 | void ctr_encrypt(uint8_t* data, uint32_t data_length, uint8_t* iv );
|
| 175 |
|
| 176 | /**
|
Alexandre Lision | e24852d | 2014-02-04 13:13:02 -0500 | [diff] [blame] | 177 | * Derive a AES context to compute the IV'.
|
Alexandre Lision | 51140e1 | 2013-12-02 10:54:09 -0500 | [diff] [blame] | 178 | *
|
| 179 | * See chapter 4.1.2.1 in RFC 3711.
|
| 180 | *
|
| 181 | * @param f8Cipher
|
Alexandre Lision | e24852d | 2014-02-04 13:13:02 -0500 | [diff] [blame] | 182 | * Pointer to the AES context that will be used to encrypt IV to IV'
|
Alexandre Lision | 51140e1 | 2013-12-02 10:54:09 -0500 | [diff] [blame] | 183 | *
|
| 184 | * @param key
|
| 185 | * The master key
|
| 186 | *
|
| 187 | * @param keyLen
|
| 188 | * Length of the master key.
|
| 189 | *
|
| 190 | * @param salt
|
| 191 | * Master salt.
|
| 192 | *
|
| 193 | * @param saltLen
|
| 194 | * length of master salt.
|
| 195 | */
|
| 196 | void f8_deriveForIV(SrtpSymCrypto* f8Cipher, uint8_t* key, int32_t keyLen, uint8_t* salt, int32_t saltLen);
|
| 197 |
|
| 198 | /**
|
Alexandre Lision | e24852d | 2014-02-04 13:13:02 -0500 | [diff] [blame] | 199 | * AES F8 mode encryption, in place.
|
Alexandre Lision | 51140e1 | 2013-12-02 10:54:09 -0500 | [diff] [blame] | 200 | *
|
Alexandre Lision | e24852d | 2014-02-04 13:13:02 -0500 | [diff] [blame] | 201 | * This method performs the AES F8 encryption, see chapter 4.1.2
|
| 202 | * in RFC 3711.
|
Alexandre Lision | 51140e1 | 2013-12-02 10:54:09 -0500 | [diff] [blame] | 203 | *
|
| 204 | * @param data
|
| 205 | * Pointer to input and output block, must be <code>dataLen</code>
|
| 206 | * bytes.
|
| 207 | *
|
| 208 | * @param dataLen
|
| 209 | * Number of bytes to process.
|
| 210 | *
|
| 211 | * @param iv
|
| 212 | * The initialization vector as input to create the cipher stream.
|
| 213 | * Refer to chapter 4.1.1 in RFC 3711.
|
| 214 | *
|
| 215 | * @param f8Cipher
|
| 216 | * An AES cipher context used to encrypt IV to IV'.
|
| 217 | */
|
| 218 | void f8_encrypt(const uint8_t* data, uint32_t dataLen, uint8_t* iv, SrtpSymCrypto* f8Cipher);
|
| 219 |
|
| 220 | /**
|
Alexandre Lision | e24852d | 2014-02-04 13:13:02 -0500 | [diff] [blame] | 221 | * AES F8 mode encryption.
|
Alexandre Lision | 51140e1 | 2013-12-02 10:54:09 -0500 | [diff] [blame] | 222 | *
|
Alexandre Lision | e24852d | 2014-02-04 13:13:02 -0500 | [diff] [blame] | 223 | * This method performs the AES F8 encryption, see chapter 4.1.2
|
| 224 | * in RFC 3711.
|
Alexandre Lision | 51140e1 | 2013-12-02 10:54:09 -0500 | [diff] [blame] | 225 | *
|
| 226 | * @param data
|
| 227 | * Pointer to input and output block, must be <code>dataLen</code>
|
| 228 | * bytes.
|
| 229 | *
|
| 230 | * @param dataLen
|
| 231 | * Number of bytes to process.
|
| 232 | *
|
| 233 | * @param out
|
| 234 | * Pointer to output buffer, must be <code>dataLen</code> bytes.
|
| 235 | *
|
| 236 | * @param iv
|
| 237 | * The initialization vector as input to create the cipher stream.
|
| 238 | * Refer to chapter 4.1.1 in RFC 3711.
|
| 239 | *
|
| 240 | * @param f8Cipher
|
| 241 | * An AES cipher context used to encrypt IV to IV'.
|
| 242 | */
|
| 243 | void f8_encrypt(const uint8_t* data, uint32_t dataLen, uint8_t* out, uint8_t* iv, SrtpSymCrypto* f8Cipher);
|
| 244 |
|
| 245 | private:
|
| 246 | int processBlock(F8_CIPHER_CTX* f8ctx, const uint8_t* in, int32_t length, uint8_t* out);
|
| 247 | void* key;
|
| 248 | int32_t algorithm;
|
| 249 | };
|
| 250 |
|
| 251 | #pragma GCC visibility push(default)
|
| 252 | int testF8();
|
| 253 | #pragma GCC visibility pop
|
| 254 |
|
Alexandre Lision | e24852d | 2014-02-04 13:13:02 -0500 | [diff] [blame] | 255 | /* Only SrtpSymCrypto functions define the MAKE_F8_TEST */
|
Alexandre Lision | 51140e1 | 2013-12-02 10:54:09 -0500 | [diff] [blame] | 256 | #ifdef MAKE_F8_TEST
|
| 257 |
|
| 258 | #include <cstring>
|
| 259 | #include <iostream>
|
| 260 | #include <cstdio>
|
Alexandre Lision | e24852d | 2014-02-04 13:13:02 -0500 | [diff] [blame] | 261 | #include <arpa/inet.h>
|
Alexandre Lision | 51140e1 | 2013-12-02 10:54:09 -0500 | [diff] [blame] | 262 |
|
| 263 | using namespace std;
|
| 264 |
|
| 265 | static void hexdump(const char* title, const unsigned char *s, int l)
|
| 266 | {
|
| 267 | int n=0;
|
| 268 |
|
| 269 | if (s == NULL) return;
|
| 270 |
|
| 271 | fprintf(stderr, "%s",title);
|
| 272 | for( ; n < l ; ++n) {
|
| 273 | if((n%16) == 0)
|
| 274 | fprintf(stderr, "\n%04x",n);
|
| 275 | fprintf(stderr, " %02x",s[n]);
|
| 276 | }
|
| 277 | fprintf(stderr, "\n");
|
| 278 | }
|
| 279 |
|
| 280 | /*
|
| 281 | * The F8 test vectors according to RFC3711
|
| 282 | */
|
| 283 | static unsigned char salt[] = {0x32, 0xf2, 0x87, 0x0d};
|
| 284 |
|
| 285 | static unsigned char iv[] = { 0x00, 0x6e, 0x5c, 0xba, 0x50, 0x68, 0x1d, 0xe5,
|
| 286 | 0x5c, 0x62, 0x15, 0x99, 0xd4, 0x62, 0x56, 0x4a};
|
| 287 |
|
| 288 | static unsigned char key[]= { 0x23, 0x48, 0x29, 0x00, 0x84, 0x67, 0xbe, 0x18,
|
| 289 | 0x6c, 0x3d, 0xe1, 0x4a, 0xae, 0x72, 0xd6, 0x2c};
|
| 290 |
|
| 291 | static unsigned char payload[] = {
|
| 292 | 0x70, 0x73, 0x65, 0x75, 0x64, 0x6f, 0x72, 0x61,
|
| 293 | 0x6e, 0x64, 0x6f, 0x6d, 0x6e, 0x65, 0x73, 0x73,
|
| 294 | 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20,
|
| 295 | 0x6e, 0x65, 0x78, 0x74, 0x20, 0x62, 0x65, 0x73,
|
| 296 | 0x74, 0x20, 0x74, 0x68, 0x69, 0x6e, 0x67}; // 39 bytes
|
| 297 |
|
| 298 | static unsigned char cipherText[] = {
|
| 299 | 0x01, 0x9c, 0xe7, 0xa2, 0x6e, 0x78, 0x54, 0x01,
|
| 300 | 0x4a, 0x63, 0x66, 0xaa, 0x95, 0xd4, 0xee, 0xfd,
|
| 301 | 0x1a, 0xd4, 0x17, 0x2a, 0x14, 0xf9, 0xfa, 0xf4,
|
| 302 | 0x55, 0xb7, 0xf1, 0xd4, 0xb6, 0x2b, 0xd0, 0x8f,
|
| 303 | 0x56, 0x2c, 0x0e, 0xef, 0x7c, 0x48, 0x02}; // 39 bytes
|
| 304 |
|
| 305 | // static unsigned char rtpPacketHeader[] = {
|
| 306 | // 0x80, 0x6e, 0x5c, 0xba, 0x50, 0x68, 0x1d, 0xe5,
|
| 307 | // 0x5c, 0x62, 0x15, 0x99};
|
| 308 |
|
| 309 | static unsigned char rtpPacket[] = {
|
| 310 | 0x80, 0x6e, 0x5c, 0xba, 0x50, 0x68, 0x1d, 0xe5,
|
| 311 | 0x5c, 0x62, 0x15, 0x99, // header
|
| 312 | 0x70, 0x73, 0x65, 0x75, 0x64, 0x6f, 0x72, 0x61, // payload
|
| 313 | 0x6e, 0x64, 0x6f, 0x6d, 0x6e, 0x65, 0x73, 0x73,
|
| 314 | 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20,
|
| 315 | 0x6e, 0x65, 0x78, 0x74, 0x20, 0x62, 0x65, 0x73,
|
| 316 | 0x74, 0x20, 0x74, 0x68, 0x69, 0x6e, 0x67};
|
| 317 | static uint32_t ROC = 0xd462564a;
|
| 318 |
|
| 319 | int testF8()
|
| 320 | {
|
| 321 | SrtpSymCrypto* aesCipher = new SrtpSymCrypto(SrtpEncryptionAESF8);
|
| 322 | SrtpSymCrypto* f8AesCipher = new SrtpSymCrypto(SrtpEncryptionAESF8);
|
| 323 |
|
| 324 | aesCipher->setNewKey(key, sizeof(key));
|
| 325 |
|
| 326 | /* Create the F8 IV (refer to chapter 4.1.2.2 in RFC 3711):
|
| 327 | *
|
| 328 | * IV = 0x00 || M || PT || SEQ || TS || SSRC || ROC
|
| 329 | * 8Bit 1bit 7bit 16bit 32bit 32bit 32bit
|
| 330 | * ------------\ /--------------------------------------------------
|
| 331 | * XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX
|
| 332 | */
|
| 333 |
|
| 334 | unsigned char derivedIv[16];
|
| 335 | uint32_t* ui32p = (uint32_t*)derivedIv;
|
| 336 |
|
| 337 | memcpy(derivedIv, rtpPacket, 12);
|
| 338 | derivedIv[0] = 0;
|
| 339 |
|
| 340 | // set ROC in network order into IV
|
Alexandre Lision | e24852d | 2014-02-04 13:13:02 -0500 | [diff] [blame] | 341 | ui32p[3] = htonl(ROC);
|
Alexandre Lision | 51140e1 | 2013-12-02 10:54:09 -0500 | [diff] [blame] | 342 |
|
| 343 | int32_t pad = 0;
|
| 344 |
|
| 345 | if (memcmp(iv, derivedIv, 16) != 0) {
|
| 346 | cerr << "Wrong IV constructed" << endl;
|
| 347 | hexdump("derivedIv", derivedIv, 16);
|
| 348 | hexdump("test vector Iv", iv, 16);
|
| 349 | return -1;
|
| 350 | }
|
| 351 |
|
| 352 | aesCipher->f8_deriveForIV(f8AesCipher, key, sizeof(key), salt, sizeof(salt));
|
| 353 |
|
| 354 | // now encrypt the RTP payload data
|
| 355 | aesCipher->f8_encrypt(rtpPacket + 12, sizeof(rtpPacket)-12+pad,
|
| 356 | derivedIv, f8AesCipher);
|
| 357 |
|
| 358 | // compare with test vector cipher data
|
| 359 | if (memcmp(rtpPacket+12, cipherText, sizeof(rtpPacket)-12+pad) != 0) {
|
| 360 | cerr << "cipher data mismatch" << endl;
|
| 361 | hexdump("computed cipher data", rtpPacket+12, sizeof(rtpPacket)-12+pad);
|
| 362 | hexdump("Test vcetor cipher data", cipherText, sizeof(cipherText));
|
| 363 | return -1;
|
| 364 | }
|
| 365 |
|
| 366 | // Now decrypt the data to get the payload data again
|
| 367 | aesCipher->f8_encrypt(rtpPacket+12, sizeof(rtpPacket)-12+pad, derivedIv, f8AesCipher);
|
| 368 |
|
| 369 | // compare decrypted data with test vector payload data
|
| 370 | if (memcmp(rtpPacket+12, payload, sizeof(rtpPacket)-12+pad) != 0) {
|
| 371 | cerr << "payload data mismatch" << endl;
|
| 372 | hexdump("computed payload data", rtpPacket+12, sizeof(rtpPacket)-12+pad);
|
| 373 | hexdump("Test vector payload data", payload, sizeof(payload));
|
| 374 | return -1;
|
| 375 | }
|
| 376 | return 0;
|
| 377 | }
|
| 378 | #endif
|
| 379 |
|
| 380 | /**
|
| 381 | * @}
|
| 382 | */
|
| 383 |
|
| 384 | #endif
|
| 385 |
|
Alexandre Lision | e24852d | 2014-02-04 13:13:02 -0500 | [diff] [blame] | 386 | /** EMACS **
|
| 387 | * Local variables:
|
| 388 | * mode: c++
|
| 389 | * c-default-style: ellemtel
|
| 390 | * c-basic-offset: 4
|
| 391 | * End:
|
| 392 | */
|
| 393 |
|