Alexandre Lision | 7fd5d3d | 2013-12-04 13:06:40 -0500 | [diff] [blame] | 1 | /* |
| 2 | Copyright (C) 2012-2013 Werner Dittmann |
| 3 | |
| 4 | This program is free software: you can redistribute it and/or modify |
| 5 | it under the terms of the GNU Lesser General Public License as published by |
| 6 | the Free Software Foundation, either version 3 of the License, or |
| 7 | (at your option) any later version. |
| 8 | |
| 9 | This program 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 |
| 12 | GNU General Public License for more details. |
| 13 | |
| 14 | You should have received a copy of the GNU General Public License |
| 15 | along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 16 | */ |
| 17 | |
| 18 | #include <stdio.h> |
| 19 | #include <stdint.h> |
| 20 | #include <stdlib.h> |
| 21 | #include <string.h> |
| 22 | |
| 23 | #include <string> |
| 24 | #include <sstream> |
| 25 | |
| 26 | #include <libzrtpcpp/ZrtpSdesStream.h> |
| 27 | #include <libzrtpcpp/ZrtpTextData.h> |
| 28 | #include <libzrtpcpp/ZrtpConfigure.h> |
| 29 | #include <libzrtpcpp/zrtpB64Decode.h> |
| 30 | #include <libzrtpcpp/zrtpB64Encode.h> |
| 31 | #include <srtp/SrtpHandler.h> |
| 32 | #include <srtp/CryptoContext.h> |
| 33 | #include <srtp/CryptoContextCtrl.h> |
| 34 | #include <cryptcommon/ZrtpRandom.h> |
| 35 | #include <crypto/hmac384.h> |
| 36 | |
| 37 | |
| 38 | #if defined(_WIN32) || defined(_WIN64) |
| 39 | # define snprintf _snprintf |
| 40 | #endif |
| 41 | |
| 42 | // SRTP authentication tag length is 80 bits = 10 bytes |
| 43 | #define ZRTP_TUNNEL_AUTH_LEN 10 |
| 44 | #define ZRTP_TUNNEL_LABEL 10 |
| 45 | /* |
| 46 | * The ABNF grammar for the crypto attribute is defined below (from RFC 4568): |
| 47 | * |
| 48 | * "a=crypto:" tag 1*WSP crypto-suite 1*WSP key-params *(1*WSP session-param) |
| 49 | * |
| 50 | * tag = 1*9DIGIT |
| 51 | */ |
| 52 | |
| 53 | /* |
| 54 | * Buffer size for names and other strings inside the crypto string. The parse |
| 55 | * format below restricts parsing to 99 char to provide space for the @c nul byte. |
| 56 | */ |
| 57 | #define MAX_INNER_LEN 100 |
| 58 | |
| 59 | /* |
| 60 | * This format scans a received SDES crypto attribute string according to the |
| 61 | * grammer shown above but without a "a=crypto:" prefix. |
| 62 | * |
| 63 | * The format string parses: |
| 64 | * - %d - the tag as decimal value |
| 65 | * - %s - the crypto suite name, limited to 99 chars (see MAX_INNER_LEN) |
| 66 | * - %s - the key parameters, limited to 99 chars |
| 67 | * - %n - the number of parsed characters to far. The pointer to the session |
| 68 | * parameters is: cryptoString + numParsedChars. |
| 69 | */ |
| 70 | static const char parseCrypto[] = "%d %99s %99s %n"; |
| 71 | |
| 72 | static const int64_t maxTagValue = 999999999; |
| 73 | |
| 74 | static const int minElementsCrypto = 3; |
| 75 | |
| 76 | /* |
| 77 | * The ABNF grammar for the key-param (from RFC 4568): |
| 78 | * |
| 79 | * key-param = key-method ":" key-info |
| 80 | * |
| 81 | * The SRTP specific definitions: |
| 82 | * |
| 83 | * key-method = srtp-key-method |
| 84 | * key-info = srtp-key-info |
| 85 | * |
| 86 | * srtp-key-method = "inline" |
| 87 | * srtp-key-info = key-salt ["|" lifetime] ["|" mki] |
| 88 | * |
| 89 | */ |
| 90 | |
| 91 | /* |
| 92 | * This format parses the key parameter string which is never longer than |
| 93 | * 99 chars (see parse string above): |
| 94 | * - the fixed string "inline:" |
| 95 | * - %[A-Za-z0-9+/=] - base 64 characters of master key||master salt |
| 96 | * - the fixed separator character '|' |
| 97 | * - %[0-9^] - the lifetime infomration as string that contains digits and ^ |
| 98 | * - the fixed separator character '|' |
| 99 | * - %[0-9]:%d - parses and strore MKI value and MKI length, separated by ':' |
| 100 | * |
| 101 | * If the key parameter string does not contain the operional fields lifetime |
| 102 | * and MKI information the respective parameters are not filled. |
| 103 | */ |
| 104 | static const char parseKeyParam[] = " inline:%[A-Za-z0-9+/=]|%[0-9^]|%[0-9]:%d"; |
| 105 | |
| 106 | static const int minElementsKeyParam = 1; |
| 107 | |
| 108 | typedef struct _cryptoMix { |
| 109 | const char* name; |
| 110 | int32_t hashLength; |
| 111 | ZrtpSdesStream::sdesHmacTypeMix hashType; |
| 112 | } cryptoMix; |
| 113 | |
| 114 | static const size_t MIX_HMAC_STRING_MIN_LEN = sizeof("HMAC-SHA-384"); |
| 115 | |
| 116 | static cryptoMix knownMixAlgos[] = { |
| 117 | {"HMAC-SHA-384", 384, ZrtpSdesStream::MIX_HMAC_SHA}, |
| 118 | {NULL, 0, ZrtpSdesStream::MIX_NONE} |
| 119 | }; |
| 120 | |
| 121 | typedef struct _suite { |
| 122 | ZrtpSdesStream::sdesSuites suite; |
| 123 | const char *name; |
| 124 | int32_t keyLength; // key length in bits |
| 125 | int32_t saltLength; // salt lenght in bits |
| 126 | int32_t authKeyLength; // authentication key length in bits |
| 127 | const char *tagLength; // tag type hs80 or hs32 |
| 128 | const char *cipher; // aes1 or aes3 |
| 129 | uint32_t b64length; // length of b64 encoded key/saltstring |
| 130 | uint64_t defaultSrtpLifetime; // key lifetimes in number of packets |
| 131 | uint64_t defaultSrtcpLifetime; |
| 132 | } suiteParam; |
| 133 | |
| 134 | /* NOTE: the b64len of a 128 bit suite is 40, a 256bit suite uses 64 characters */ |
| 135 | static suiteParam knownSuites[] = { |
| 136 | {ZrtpSdesStream::AES_CM_128_HMAC_SHA1_32, "AES_CM_128_HMAC_SHA1_32", 128, 112, 160, |
| 137 | hs32, "AES-128", 40, (uint64_t)1<<48, (uint64_t)1<<31 |
| 138 | }, |
| 139 | {ZrtpSdesStream::AES_CM_128_HMAC_SHA1_80, "AES_CM_128_HMAC_SHA1_80", 128, 112, 160, |
| 140 | hs80, "AES-128", 40, (uint64_t)1<<48, (uint64_t)1<<31 |
| 141 | }, |
| 142 | {(ZrtpSdesStream::sdesSuites)0, NULL, 0, 0, 0, 0, 0, 0, 0, 0} |
| 143 | }; |
| 144 | |
| 145 | ZrtpSdesStream::ZrtpSdesStream(const sdesSuites s) : |
| 146 | state(STREAM_INITALIZED), suite(s), recvSrtp(NULL), recvSrtcp(NULL), sendSrtp(NULL), |
| 147 | sendSrtcp(NULL), srtcpIndex(0), recvZrtpTunnel(0), sendZrtpTunnel(0), cryptoMixHashLength(0), |
| 148 | cryptoMixHashType(MIX_NONE) { |
| 149 | } |
| 150 | |
| 151 | ZrtpSdesStream::~ZrtpSdesStream() { |
| 152 | close(); |
| 153 | } |
| 154 | |
| 155 | void ZrtpSdesStream::close() { |
| 156 | delete sendSrtp; |
| 157 | sendSrtp = NULL; |
| 158 | |
| 159 | delete recvSrtp; |
| 160 | recvSrtp = NULL; |
| 161 | |
| 162 | delete sendSrtcp; |
| 163 | sendSrtp = NULL; |
| 164 | |
| 165 | delete recvSrtcp; |
| 166 | recvSrtp = NULL; |
| 167 | |
| 168 | delete recvZrtpTunnel; |
| 169 | recvZrtpTunnel = NULL; |
| 170 | |
| 171 | delete sendZrtpTunnel; |
| 172 | sendZrtpTunnel = NULL; |
| 173 | } |
| 174 | |
| 175 | bool ZrtpSdesStream::createSdes(char *cryptoString, size_t *maxLen, bool sipInvite) { |
| 176 | |
| 177 | if (sipInvite) { |
| 178 | if (state != STREAM_INITALIZED) |
| 179 | return false; |
| 180 | tag = 1; |
| 181 | } |
| 182 | else { |
| 183 | if (state != IN_PROFILE_READY) |
| 184 | return false; |
| 185 | } |
| 186 | |
| 187 | bool s = createSdesProfile(cryptoString, maxLen); |
| 188 | if (!s) |
| 189 | return s; |
| 190 | |
| 191 | if (sipInvite) { |
| 192 | state = OUT_PROFILE_READY; |
| 193 | } |
| 194 | else { |
| 195 | createSrtpContexts(sipInvite); |
| 196 | state = SDES_SRTP_ACTIVE; |
| 197 | } |
| 198 | return s; |
| 199 | } |
| 200 | |
| 201 | bool ZrtpSdesStream::parseSdes(const char *cryptoString, size_t length, bool sipInvite) { |
| 202 | |
| 203 | if (sipInvite) { |
| 204 | if (state != OUT_PROFILE_READY) |
| 205 | return false; |
| 206 | } |
| 207 | else { |
| 208 | if (state != STREAM_INITALIZED) |
| 209 | return false; |
| 210 | } |
| 211 | sdesSuites tmpSuite; |
| 212 | int32_t tmpTag; |
| 213 | |
| 214 | bool s = parseCreateSdesProfile(cryptoString, length, &tmpSuite, &tmpTag); |
| 215 | if (!s) |
| 216 | return s; |
| 217 | |
| 218 | if (sipInvite) { |
| 219 | // Check if answerer used same tag and suite as the offerer |
| 220 | if (tmpTag != tag || suite != tmpSuite) |
| 221 | return false; |
| 222 | createSrtpContexts(sipInvite); |
| 223 | state = SDES_SRTP_ACTIVE; |
| 224 | } |
| 225 | else { |
| 226 | // Answerer stores tag and suite and uses it in createSdesProfile |
| 227 | suite = tmpSuite; |
| 228 | tag = tmpTag; |
| 229 | state = IN_PROFILE_READY; |
| 230 | } |
| 231 | return s; |
| 232 | } |
| 233 | |
| 234 | bool ZrtpSdesStream::outgoingRtp(uint8_t *packet, size_t length, size_t *newLength) { |
| 235 | |
| 236 | if (state != SDES_SRTP_ACTIVE || sendSrtp == NULL) { |
| 237 | *newLength = length; |
| 238 | return true; |
| 239 | } |
| 240 | bool rc = SrtpHandler::protect(sendSrtp, packet, length, newLength); |
| 241 | if (rc) |
| 242 | ;//protect++; |
| 243 | return rc; |
| 244 | } |
| 245 | |
| 246 | int ZrtpSdesStream::incomingRtp(uint8_t *packet, size_t length, size_t *newLength) { |
| 247 | if (state != SDES_SRTP_ACTIVE || recvSrtp == NULL) { // SRTP inactive, just return with newLength set |
| 248 | *newLength = length; |
| 249 | return 1; |
| 250 | } |
| 251 | int32_t rc = SrtpHandler::unprotect(recvSrtp, packet, length, newLength); |
| 252 | if (rc == 1) { |
| 253 | // unprotect++ |
| 254 | } |
| 255 | else { |
| 256 | // unprotectFailed++; |
| 257 | } |
| 258 | return rc; |
| 259 | } |
| 260 | |
| 261 | |
| 262 | bool ZrtpSdesStream::outgoingZrtpTunnel(uint8_t *packet, size_t length, size_t *newLength) { |
| 263 | |
| 264 | if (state != SDES_SRTP_ACTIVE || sendZrtpTunnel == NULL) { |
| 265 | *newLength = length; |
| 266 | return true; |
| 267 | } |
| 268 | bool rc = SrtpHandler::protect(sendZrtpTunnel, packet, length, newLength); |
| 269 | if (rc) |
| 270 | ;//protect++; |
| 271 | return rc; |
| 272 | } |
| 273 | |
| 274 | int ZrtpSdesStream::incomingZrtpTunnel(uint8_t *packet, size_t length, size_t *newLength) { |
| 275 | if (state != SDES_SRTP_ACTIVE || recvZrtpTunnel == NULL) { // SRTP inactive, just return with newLength set |
| 276 | *newLength = length; |
| 277 | return 1; |
| 278 | } |
| 279 | int32_t rc = SrtpHandler::unprotect(recvZrtpTunnel, packet, length, newLength); |
| 280 | if (rc == 1) { |
| 281 | // unprotect++ |
| 282 | } |
| 283 | else { |
| 284 | // unprotectFailed++; |
| 285 | } |
| 286 | return rc; |
| 287 | } |
| 288 | |
| 289 | |
| 290 | |
| 291 | bool ZrtpSdesStream::outgoingRtcp(uint8_t *packet, size_t length, size_t *newLength) { |
| 292 | #if 0 |
| 293 | SrtpHandler::protectCtrl(CryptoContextCtrl* pcc, uint8_t* buffer, size_t length, size_t* newLength, uint32_t *srtcpIndex) |
| 294 | #endif |
| 295 | return false; |
| 296 | } |
| 297 | |
| 298 | int ZrtpSdesStream::incomingSrtcp(uint8_t *packet, size_t length, size_t *newLength) { |
| 299 | #if 0 |
| 300 | int32_t SrtpHandler::unprotectCtrl(CryptoContextCtrl* pcc, uint8_t* buffer, size_t length, size_t* newLength) |
| 301 | #endif |
| 302 | return 0; |
| 303 | } |
| 304 | |
| 305 | const char* ZrtpSdesStream::getCipher() { |
| 306 | return knownSuites[suite].cipher; |
| 307 | } |
| 308 | |
| 309 | const char* ZrtpSdesStream::getAuthAlgo() { |
| 310 | if (strcmp(knownSuites[suite].tagLength, hs80) == 0) |
| 311 | return "HMAC-SHA1 80 bit"; |
| 312 | else |
| 313 | return "HMAC-SHA1 32 bit"; |
| 314 | } |
| 315 | |
| 316 | int ZrtpSdesStream::getCryptoMixAttribute(char *algoNames, size_t length) { |
| 317 | |
| 318 | if (length < MIX_HMAC_STRING_MIN_LEN) |
| 319 | return 0; |
| 320 | |
| 321 | // In case we support more than one MIX profile select the correct one if the |
| 322 | // application called setCryptoMixAttribute(...) and we already selected the one to use. |
| 323 | if (cryptoMixHashType != MIX_NONE) { |
| 324 | for (cryptoMix* cp = knownMixAlgos; cp->name != NULL; cp++) { |
| 325 | if (cp->hashLength == cryptoMixHashLength && cp->hashType == cryptoMixHashType) { |
| 326 | strcpy(algoNames, cp->name); |
| 327 | return strlen(cp->name); |
| 328 | } |
| 329 | } |
| 330 | } |
| 331 | // TODO: enhance here to support multiple algorithms (concatenate strings into the buffer until buffer full) |
| 332 | else { |
| 333 | strcpy(algoNames, knownMixAlgos[0].name); |
| 334 | return strlen(algoNames); |
| 335 | } |
| 336 | return 0; |
| 337 | } |
| 338 | |
| 339 | bool ZrtpSdesStream::setCryptoMixAttribute(const char *algoNames) { |
| 340 | |
| 341 | int len = strlen(algoNames); |
| 342 | if (len <= 0) |
| 343 | return false; |
| 344 | |
| 345 | std::string algoIn(algoNames); |
| 346 | algoIn += ' '; |
| 347 | |
| 348 | // split input name string and lookup if we support one of the offered algorithms |
| 349 | // We take the first match. |
| 350 | std::string delimiters = " "; |
| 351 | size_t current; |
| 352 | size_t next = -1; |
| 353 | |
| 354 | do { |
| 355 | current = next + 1; |
| 356 | next = algoIn.find_first_of(delimiters, current); |
| 357 | if (next == std::string::npos) |
| 358 | break; |
| 359 | |
| 360 | std::string tmps = algoIn.substr(current, next - current ); |
| 361 | const char* nm = tmps.c_str(); |
| 362 | |
| 363 | for (cryptoMix* cp = knownMixAlgos; cp->name != NULL; cp++) { |
| 364 | if (strncmp(cp->name, nm, strlen(cp->name)) == 0) { |
| 365 | cryptoMixHashLength = cp->hashLength; |
| 366 | cryptoMixHashType = cp->hashType; |
| 367 | return true; |
| 368 | } |
| 369 | } |
| 370 | } while (true); |
| 371 | |
| 372 | return false; |
| 373 | } |
| 374 | |
| 375 | #ifdef WEAKRANDOM |
| 376 | /* |
| 377 | * A standard random number generator that uses the portable random() system function. |
| 378 | * |
| 379 | * This should be enhanced to use a better random generator |
| 380 | */ |
| 381 | static int _random(unsigned char *output, size_t len) |
| 382 | { |
| 383 | size_t i; |
| 384 | |
| 385 | for(i = 0; i < len; ++i ) |
| 386 | output[i] = random(); |
| 387 | |
| 388 | return( 0 ); |
| 389 | } |
| 390 | #else |
| 391 | #include <cryptcommon/ZrtpRandom.h> |
| 392 | static int _random(unsigned char *output, size_t len) |
| 393 | { |
| 394 | return ZrtpRandom::getRandomData(output, len); |
| 395 | } |
| 396 | #endif |
| 397 | |
| 398 | static int b64Encode(const uint8_t *binData, int32_t binLength, char *b64Data, int32_t b64Length) |
| 399 | { |
| 400 | base64_encodestate _state; |
| 401 | int codelength; |
| 402 | |
| 403 | base64_init_encodestate(&_state, 0); |
| 404 | codelength = base64_encode_block(binData, binLength, b64Data, &_state); |
| 405 | codelength += base64_encode_blockend(b64Data+codelength, &_state); |
| 406 | |
| 407 | return codelength; |
| 408 | } |
| 409 | |
| 410 | static int b64Decode(const char *b64Data, int32_t b64length, uint8_t *binData, int32_t binLength) |
| 411 | { |
| 412 | base64_decodestate _state; |
| 413 | int codelength; |
| 414 | |
| 415 | base64_init_decodestate(&_state); |
| 416 | codelength = base64_decode_block(b64Data, b64length, binData, &_state); |
| 417 | return codelength; |
| 418 | } |
| 419 | |
| 420 | void* createSha384HmacContext(uint8_t* key, int32_t keyLength); |
| 421 | void freeSha384HmacContext(void* ctx); |
| 422 | void hmacSha384Ctx(void* ctx, const uint8_t* data[], uint32_t dataLength[], uint8_t* mac, int32_t* macLength ); |
| 423 | |
| 424 | static int expand(uint8_t* prk, uint32_t prkLen, uint8_t* info, int32_t infoLen, int32_t L, uint32_t hashLen, uint8_t* outbuffer) |
| 425 | { |
| 426 | int32_t n; |
| 427 | uint8_t *T; |
| 428 | void* hmacCtx; |
| 429 | |
| 430 | const uint8_t* data[4]; // 3 data pointers for HMAC data plus terminating NULL |
| 431 | uint32_t dataLen[4]; |
| 432 | int32_t dataIdx = 0; |
| 433 | |
| 434 | uint8_t counter; |
| 435 | int32_t macLength; |
| 436 | |
| 437 | if (prkLen < hashLen) |
| 438 | return -1; |
| 439 | |
| 440 | n = (L + (hashLen-1)) / hashLen; |
| 441 | |
| 442 | // T points to buffer that holds concatenated T(1) || T(2) || ... T(N)) |
| 443 | T = reinterpret_cast<uint8_t*>(malloc(n * hashLen)); |
| 444 | |
| 445 | if (hashLen == 384/8) |
| 446 | hmacCtx = createSha384HmacContext(prk, prkLen); |
| 447 | else |
| 448 | return -1; |
| 449 | |
| 450 | // Prepare first HMAC. T(0) has zero length, thus we ignore it in first run. |
| 451 | // After first run use its output (T(1)) as first data in next HMAC run. |
| 452 | for (int i = 1; i <= n; i++) { |
| 453 | if (infoLen > 0 && info != NULL) { |
| 454 | data[dataIdx] = info; |
| 455 | dataLen[dataIdx++] = infoLen; |
| 456 | } |
| 457 | counter = i & 0xff; |
| 458 | data[dataIdx] = &counter; |
| 459 | dataLen[dataIdx++] = 1; |
| 460 | |
| 461 | data[dataIdx] = NULL; |
| 462 | dataLen[dataIdx++] = 0; |
| 463 | |
| 464 | if (hashLen == 384/8) |
| 465 | hmacSha384Ctx(hmacCtx, data, dataLen, T + ((i-1) * hashLen), &macLength); |
| 466 | |
| 467 | // Use output of previous hash run as first input of next hash run |
| 468 | dataIdx = 0; |
| 469 | data[dataIdx] = T + ((i-1) * hashLen); |
| 470 | dataLen[dataIdx++] = hashLen; |
| 471 | } |
| 472 | freeSha384HmacContext(hmacCtx); |
| 473 | memcpy(outbuffer, T, L); |
| 474 | free(T); |
| 475 | return 0; |
| 476 | } |
| 477 | |
| 478 | void ZrtpSdesStream::computeMixedKeys(bool sipInvite) { |
| 479 | uint8_t salt[MAX_SALT_LEN*2]; |
| 480 | uint8_t ikm[MAX_KEY_LEN*2]; |
| 481 | |
| 482 | // Concatenate the existing salt and key data. Depending on our role we have to change |
| 483 | // the order of the data. |
| 484 | if (sipInvite) { // We are offerer, use local created data as mso and mko, so they go first |
| 485 | memcpy(salt, &localKeySalt[localKeyLenBytes], localSaltLenBytes); |
| 486 | memcpy(&salt[localSaltLenBytes], &remoteKeySalt[remoteKeyLenBytes], remoteSaltLenBytes); |
| 487 | |
| 488 | memcpy(ikm, localKeySalt, localKeyLenBytes); |
| 489 | memcpy(&ikm[localKeyLenBytes], remoteKeySalt, remoteKeyLenBytes); |
| 490 | } |
| 491 | else { |
| 492 | memcpy(salt, &remoteKeySalt[remoteKeyLenBytes], remoteSaltLenBytes); |
| 493 | memcpy(&salt[remoteSaltLenBytes], &localKeySalt[localKeyLenBytes], localSaltLenBytes); |
| 494 | |
| 495 | memcpy(ikm, remoteKeySalt, remoteKeyLenBytes); |
| 496 | memcpy(&ikm[remoteKeyLenBytes], localKeySalt, localKeyLenBytes); |
| 497 | } |
| 498 | uint32_t saltLen = localSaltLenBytes + remoteSaltLenBytes; |
| 499 | uint32_t keyLen = localKeyLenBytes + remoteKeyLenBytes; |
| 500 | uint32_t L = saltLen + keyLen; |
| 501 | |
| 502 | uint8_t prk[MAX_DIGEST_LENGTH]; |
| 503 | uint32_t prkLen; |
| 504 | |
| 505 | switch(cryptoMixHashType) { |
| 506 | case MIX_HMAC_SHA: |
| 507 | if (cryptoMixHashLength == 384) |
| 508 | hmac_sha384(salt, saltLen, ikm, keyLen, prk, &prkLen); |
| 509 | else |
| 510 | return; |
| 511 | break; |
| 512 | |
| 513 | case MIX_MAC_SKEIN: |
| 514 | return; |
| 515 | |
| 516 | default: |
| 517 | return; |
| 518 | } |
| 519 | |
| 520 | uint8_t T[(MAX_SALT_LEN + MAX_KEY_LEN)*2] = {0}; |
| 521 | expand(prk, prkLen, NULL, 0, L, cryptoMixHashLength/8, T); |
| 522 | |
| 523 | // We have a new set of SRTP key data now, replace the old with the new. |
| 524 | int32_t offset = 0; |
| 525 | if (sipInvite) { // We are offerer, replace local created data with mso and mko, remote with msa, mka |
| 526 | memcpy(&localKeySalt[localKeyLenBytes], T, localSaltLenBytes); |
| 527 | offset += localSaltLenBytes; |
| 528 | memcpy(&remoteKeySalt[remoteKeyLenBytes], &T[offset], remoteSaltLenBytes); |
| 529 | offset += remoteSaltLenBytes; |
| 530 | |
| 531 | memcpy(localKeySalt, &T[offset], localKeyLenBytes); |
| 532 | offset += localKeyLenBytes; |
| 533 | memcpy(remoteKeySalt, &T[offset], remoteKeyLenBytes); |
| 534 | } |
| 535 | else { // We are answerer, replace remote data with mso and mko, local data with msa, mka |
| 536 | memcpy(&remoteKeySalt[remoteKeyLenBytes], T, remoteSaltLenBytes); |
| 537 | offset += remoteSaltLenBytes; |
| 538 | memcpy(&localKeySalt[localKeyLenBytes], &T[offset], localSaltLenBytes); |
| 539 | offset += localSaltLenBytes; |
| 540 | |
| 541 | memcpy(remoteKeySalt, &T[offset], remoteKeyLenBytes); |
| 542 | offset += remoteKeyLenBytes; |
| 543 | memcpy(localKeySalt, &T[offset], localKeyLenBytes); |
| 544 | } |
| 545 | } |
| 546 | |
| 547 | void ZrtpSdesStream::createSrtpContexts(bool sipInvite) { |
| 548 | |
| 549 | if (cryptoMixHashType != MIX_NONE) { |
| 550 | computeMixedKeys(sipInvite); |
| 551 | } |
| 552 | |
| 553 | sendSrtp = new CryptoContext(0, // SSRC (used for lookup) |
| 554 | 0, // Roll-Over-Counter (ROC) |
| 555 | 0L, // keyderivation << 48, |
| 556 | localCipher, // encryption algo |
| 557 | localAuthn, // authtentication algo |
| 558 | localKeySalt, // Master Key |
| 559 | localKeyLenBytes, // Master Key length |
| 560 | &localKeySalt[localKeyLenBytes], // Master Salt |
| 561 | localSaltLenBytes, // Master Salt length |
| 562 | localKeyLenBytes, // encryption keylen |
| 563 | localAuthKeyLen, // authentication key len (HMAC key lenght) |
| 564 | localSaltLenBytes, // session salt len |
| 565 | localTagLength); // authentication tag len |
| 566 | sendSrtp->deriveSrtpKeys(0L); |
| 567 | |
| 568 | sendZrtpTunnel = new CryptoContext(0, // SSRC (used for lookup) |
| 569 | 0, // Roll-Over-Counter (ROC) |
| 570 | 0L, // keyderivation << 48, |
| 571 | localCipher, // encryption algo |
| 572 | localAuthn, // authtentication algo |
| 573 | localKeySalt, // Master Key |
| 574 | localKeyLenBytes, // Master Key length |
| 575 | &localKeySalt[localKeyLenBytes], // Master Salt |
| 576 | localSaltLenBytes, // Master Salt length |
| 577 | localKeyLenBytes, // encryption keylen |
| 578 | localAuthKeyLen, // authentication key len (HMAC key lenght) |
| 579 | localSaltLenBytes, // session salt len |
| 580 | ZRTP_TUNNEL_AUTH_LEN); // authentication tag len |
| 581 | |
| 582 | sendZrtpTunnel->setLabelbase(ZRTP_TUNNEL_LABEL); |
| 583 | sendZrtpTunnel->deriveSrtpKeys(0L); |
| 584 | memset(localKeySalt, 0, sizeof(localKeySalt)); |
| 585 | |
| 586 | recvSrtp = new CryptoContext(0, // SSRC (used for lookup) |
| 587 | 0, // Roll-Over-Counter (ROC) |
| 588 | 0L, // keyderivation << 48, |
| 589 | remoteCipher, // encryption algo |
| 590 | remoteAuthn, // authtentication algo |
| 591 | remoteKeySalt, // Master Key |
| 592 | remoteKeyLenBytes, // Master Key length |
| 593 | &remoteKeySalt[remoteKeyLenBytes], // Master Salt |
| 594 | remoteSaltLenBytes, // Master Salt length |
| 595 | remoteKeyLenBytes, // encryption keylen |
| 596 | remoteAuthKeyLen, // authentication key len (HMAC key lenght) |
| 597 | remoteSaltLenBytes, // session salt len |
| 598 | remoteTagLength); // authentication tag len |
| 599 | recvSrtp->deriveSrtpKeys(0L); |
| 600 | |
| 601 | recvZrtpTunnel = new CryptoContext(0, // SSRC (used for lookup) |
| 602 | 0, // Roll-Over-Counter (ROC) |
| 603 | 0L, // keyderivation << 48, |
| 604 | remoteCipher, // encryption algo |
| 605 | remoteAuthn, // authtentication algo |
| 606 | remoteKeySalt, // Master Key |
| 607 | remoteKeyLenBytes, // Master Key length |
| 608 | &remoteKeySalt[remoteKeyLenBytes], // Master Salt |
| 609 | remoteSaltLenBytes, // Master Salt length |
| 610 | remoteKeyLenBytes, // encryption keylen |
| 611 | remoteAuthKeyLen, // authentication key len (HMAC key lenght) |
| 612 | remoteSaltLenBytes, // session salt len |
| 613 | ZRTP_TUNNEL_AUTH_LEN); // authentication tag len |
| 614 | |
| 615 | recvZrtpTunnel->setLabelbase(ZRTP_TUNNEL_LABEL); |
| 616 | recvZrtpTunnel->deriveSrtpKeys(0L); |
| 617 | memset(remoteKeySalt, 0, sizeof(remoteKeySalt)); |
| 618 | } |
| 619 | |
| 620 | bool ZrtpSdesStream::createSdesProfile(char *cryptoString, size_t *maxLen) { |
| 621 | |
| 622 | char b64keySalt[(MAX_KEY_LEN + MAX_SALT_LEN) * 2] = {'\0'}; |
| 623 | uint32_t sidx; |
| 624 | int32_t b64Len; |
| 625 | |
| 626 | for (sidx = 0; knownSuites[sidx].name != NULL; sidx++) { // Lookup crypto suite parameters |
| 627 | if (knownSuites[sidx].suite == suite) |
| 628 | break; |
| 629 | } |
| 630 | if (sidx >= sizeof(knownSuites)/sizeof(struct _suite)) { |
| 631 | return false; |
| 632 | } |
| 633 | suiteParam *pSuite = &knownSuites[sidx]; |
| 634 | _random(localKeySalt, sizeof(localKeySalt)); |
| 635 | |
| 636 | AlgorithmEnum& auth = zrtpAuthLengths.getByName(pSuite->tagLength); |
| 637 | localAuthn = SrtpAuthenticationSha1Hmac; |
| 638 | localAuthKeyLen = pSuite->authKeyLength / 8; |
| 639 | localTagLength = auth.getKeylen() / 8; |
| 640 | |
| 641 | // If SDES will support other encryption algos - get it here based on |
| 642 | // the algorithm name in suite |
| 643 | localCipher = SrtpEncryptionAESCM; |
| 644 | |
| 645 | localKeyLenBytes = pSuite->keyLength / 8; |
| 646 | localSaltLenBytes = pSuite->saltLength / 8; |
| 647 | |
| 648 | if (tag == -1) |
| 649 | tag = 1; |
| 650 | |
| 651 | // Get B64 code for master key and master salt and then construct the SDES crypto string |
| 652 | b64Len = b64Encode(localKeySalt, localKeyLenBytes + localSaltLenBytes, b64keySalt, sizeof(b64keySalt)); |
| 653 | b64keySalt[b64Len] = '\0'; |
| 654 | memset(cryptoString, 0, *maxLen); |
| 655 | *maxLen = snprintf(cryptoString, *maxLen-1, "%d %s inline:%s", tag, pSuite->name, b64keySalt); |
| 656 | |
| 657 | return true; |
| 658 | } |
| 659 | |
| 660 | bool ZrtpSdesStream::parseCreateSdesProfile(const char *cryptoStr, size_t length, sdesSuites *parsedSuite, int32_t *outTag) { |
| 661 | int elements, i; |
| 662 | int charsScanned; |
| 663 | int mkiLength = 0; |
| 664 | uint32_t sidx; |
| 665 | |
| 666 | char cryptoString[MAX_CRYPT_STRING_LEN+1] = {'\0'}; |
| 667 | |
| 668 | /* Parsed strings */ |
| 669 | char suiteName[MAX_INNER_LEN] = {'\0'}; |
| 670 | char keyParams[MAX_INNER_LEN] = {'\0'}; |
| 671 | char keySaltB64[MAX_INNER_LEN] = {'\0'}; |
| 672 | char lifetime[MAX_INNER_LEN] = {'\0'}; |
| 673 | char mkiVal[MAX_INNER_LEN] = {'\0'}; |
| 674 | |
| 675 | if (length == 0) |
| 676 | length = strlen(cryptoStr); |
| 677 | |
| 678 | if (length > MAX_CRYPT_STRING_LEN) { |
| 679 | return false; |
| 680 | } |
| 681 | memcpy(cryptoString, cryptoStr, length); // make own copy, null terminated |
| 682 | |
| 683 | *outTag = -1; |
| 684 | elements = sscanf(cryptoString, parseCrypto, outTag, suiteName, keyParams, &charsScanned); |
| 685 | |
| 686 | if (elements < minElementsCrypto) { // Do we have enough elements in the string |
| 687 | return false; |
| 688 | } |
| 689 | |
| 690 | for (sidx = 0; knownSuites[sidx].name != NULL; sidx++) { // Lookup crypto suite |
| 691 | if (!strcmp(knownSuites[sidx].name, suiteName)) |
| 692 | break; |
| 693 | } |
| 694 | if (sidx >= sizeof(knownSuites)/sizeof(struct _suite)) { |
| 695 | return false; |
| 696 | } |
| 697 | suiteParam *pSuite = &knownSuites[sidx]; |
| 698 | *parsedSuite = pSuite->suite; |
| 699 | |
| 700 | /* Now scan the key parameters */ |
| 701 | elements = sscanf(keyParams, parseKeyParam, keySaltB64, lifetime, mkiVal, &mkiLength); |
| 702 | |
| 703 | if (elements != minElementsKeyParam) { // Currently we only accept key||salt B64 string, no other parameters |
| 704 | return false; |
| 705 | } |
| 706 | |
| 707 | remoteKeyLenBytes = pSuite->keyLength / 8; |
| 708 | remoteSaltLenBytes = pSuite->saltLength / 8; |
| 709 | |
| 710 | if (strlen(keySaltB64) != pSuite->b64length) { // Check if key||salt B64 string hast the correct length |
| 711 | return false; |
| 712 | } |
| 713 | i = b64Decode(keySaltB64, pSuite->b64length, remoteKeySalt, remoteKeyLenBytes + remoteSaltLenBytes); |
| 714 | |
| 715 | if (i != (remoteKeyLenBytes + remoteSaltLenBytes)) { // Did the B64 decode delivered enough data for key||salt |
| 716 | return false; |
| 717 | } |
| 718 | |
| 719 | AlgorithmEnum& auth = zrtpAuthLengths.getByName(pSuite->tagLength); |
| 720 | remoteAuthn = SrtpAuthenticationSha1Hmac; |
| 721 | remoteAuthKeyLen = pSuite->authKeyLength / 8; |
| 722 | remoteTagLength = auth.getKeylen() / 8; |
| 723 | |
| 724 | // If SDES will support other encryption algos - get it here based on |
| 725 | // the algorithm name in suite |
| 726 | remoteCipher = SrtpEncryptionAESCM; |
| 727 | |
| 728 | return true; |
| 729 | } |