blob: a6756af75b531c153691b2073ed5715814b2a6b8 [file] [log] [blame]
Alexandre Lision7fd5d3d2013-12-04 13:06:40 -05001/*
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 */
70static const char parseCrypto[] = "%d %99s %99s %n";
71
72static const int64_t maxTagValue = 999999999;
73
74static 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 */
104static const char parseKeyParam[] = " inline:%[A-Za-z0-9+/=]|%[0-9^]|%[0-9]:%d";
105
106static const int minElementsKeyParam = 1;
107
108typedef struct _cryptoMix {
109 const char* name;
110 int32_t hashLength;
111 ZrtpSdesStream::sdesHmacTypeMix hashType;
112} cryptoMix;
113
114static const size_t MIX_HMAC_STRING_MIN_LEN = sizeof("HMAC-SHA-384");
115
116static cryptoMix knownMixAlgos[] = {
117 {"HMAC-SHA-384", 384, ZrtpSdesStream::MIX_HMAC_SHA},
118 {NULL, 0, ZrtpSdesStream::MIX_NONE}
119};
120
121typedef 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 */
135static 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
145ZrtpSdesStream::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
151ZrtpSdesStream::~ZrtpSdesStream() {
152 close();
153}
154
155void 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
175bool 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
201bool 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
234bool 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
246int 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
262bool 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
274int 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
291bool ZrtpSdesStream::outgoingRtcp(uint8_t *packet, size_t length, size_t *newLength) {
292#if 0
293SrtpHandler::protectCtrl(CryptoContextCtrl* pcc, uint8_t* buffer, size_t length, size_t* newLength, uint32_t *srtcpIndex)
294#endif
295 return false;
296}
297
298int ZrtpSdesStream::incomingSrtcp(uint8_t *packet, size_t length, size_t *newLength) {
299#if 0
300int32_t SrtpHandler::unprotectCtrl(CryptoContextCtrl* pcc, uint8_t* buffer, size_t length, size_t* newLength)
301#endif
302 return 0;
303}
304
305const char* ZrtpSdesStream::getCipher() {
306 return knownSuites[suite].cipher;
307}
308
309const 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
316int 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
339bool 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 */
381static 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>
392static int _random(unsigned char *output, size_t len)
393{
394 return ZrtpRandom::getRandomData(output, len);
395}
396#endif
397
398static 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
410static 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
420void* createSha384HmacContext(uint8_t* key, int32_t keyLength);
421void freeSha384HmacContext(void* ctx);
422void hmacSha384Ctx(void* ctx, const uint8_t* data[], uint32_t dataLength[], uint8_t* mac, int32_t* macLength );
423
424static 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
478void 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
547void 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
620bool 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
660bool 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}