AudioSrtpSession.cpp 8.71 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/*
 *  Copyright (C) 2009 Savoir-Faire Linux inc.
 *  Author: Alexandre Savard <alexandre.savard@savoirfairelinux.com>
 *  Author: Pierre-Luc Bacon <pierre-luc.bacon@savoirfairelinux.com>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 3 of the License, or
 *  (at your option) any later version.
 *  This program 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 General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
#include "AudioSrtpSession.h"
#include "user_cfg.h"

#include "sip/sipcall.h"

Alexandre Savard's avatar
Alexandre Savard committed
24
25
#include <openssl/sha.h>
#include <openssl/hmac.h>
26
#include <openssl/evp.h>
Alexandre Savard's avatar
Alexandre Savard committed
27
28
#include <openssl/bio.h>
#include <openssl/buffer.h>
29
#include <openssl/rand.h>
30
31


32
33
34
35
#include <cstdio>
#include <cstring>
#include <cerrno>

36

37
38
39
40
41
namespace sfl
{

AudioSrtpSession::AudioSrtpSession (ManagerImpl * manager, SIPCall * sipcall) :
        ost::SymmetricRTPSession (ost::InetHostAddress (sipcall->getLocalIp().c_str()), sipcall->getLocalAudioPort()),
Alexandre Savard's avatar
Alexandre Savard committed
42
43
44
45
46
47
48
49
        AudioRtpSession<AudioSrtpSession> (manager, sipcall),
        _localCryptoSuite(0),
        _remoteCryptoSuite(0),
        _localMasterKeyLength(0),
        _localMasterSaltLength(0),
        _remoteMasterKeyLength(0),
        _remoteMasterSaltLength(0)

50
{
51
52

    // Initialize local Crypto context
53
54
55
    initializeLocalMasterKey();
    initializeLocalMasterSalt();
    initializeLocalCryptoContext();
56

57
    // Set local crypto context in ccrtp
58
    _localCryptoCtx->deriveSrtpKeys(0);
59

60
    setOutQueueCryptoContext(_localCryptoCtx);
61
62
}

63
 
64
std::vector<std::string> AudioSrtpSession::getLocalCryptoInfo() {
65

66
67
    _debug("Get Cryptographic info from this rtp session");

68
69
    std::vector<std::string> crypto_vector;

70
71
    // @TODO we should return a vector containing supported 
    // cryptographic context tagged 1, 2, 3...
72
    std::string tag = "1";
73

74
    std::string crypto_suite = sfl::CryptoSuites[_localCryptoSuite].name;
75

76
    // srtp keys formated as the following  as the following
77
    // inline:keyParameters|keylifetime|MasterKeyIdentifier
78
    // inline:NzB4d1BINUAvLEw6UzF3WSJ+PSdFcGdUJShpX1Zj|2^20|1:32
79
80
    std::string srtp_keys = "inline:";
    srtp_keys += getBase64ConcatenatedKeys();
81
    // srtp_keys.append("|2^20|1:32");
82

83
    // generate crypto attribute
84
85
86
87
88
    std::string crypto_attr = tag.append(" ");
    crypto_attr += crypto_suite.append(" ");
    crypto_attr += srtp_keys;

    _debug("%s", crypto_attr.c_str());
89

90
    crypto_vector.push_back(crypto_attr);
91

92
    return crypto_vector;
93
}
94

95

96
void AudioSrtpSession::setRemoteCryptoInfo(sfl::SdesNegotiator& nego) {
97

98
    _debug("Set remote Cryptographic info for Srtp");
99

100
    // decode keys
101
    unBase64ConcatenatedKeys(nego.getKeyInfo());
102
103

    // init crypto content int Srtp session
104
    initializeRemoteCryptoContext();
105
    setInQueueCryptoContext(_remoteCryptoCtx);
106
107
108
}


109
void AudioSrtpSession::initializeLocalMasterKey(void)
110
{
111

112
    // @TODO key may have different length depending on cipher suite
113
    _localMasterKeyLength = sfl::CryptoSuites[_localCryptoSuite].masterKeyLength / 8;
114

115
    // Allocate memory for key
116
117
    unsigned char *random_key = new unsigned char[_localMasterKeyLength];

118
    // Generate ryptographically strong pseudo-random bytes
119
120
121
122
    int err;
    if((err = RAND_bytes(random_key, _localMasterKeyLength)) != 1)
        _debug("Error occured while generating cryptographically strong pseudo-random key");

123
    memcpy(_localMasterKey, random_key, _localMasterKeyLength);
124

125
    /*
Alexandre Savard's avatar
Alexandre Savard committed
126
    printf("Local Master: ");
127
    for(int i = 0; i < _localMasterKeyLength; i++){
Alexandre Savard's avatar
Alexandre Savard committed
128
        printf("%d", _localMasterKey[i]);
129
    }
Alexandre Savard's avatar
Alexandre Savard committed
130
    printf("\n");
131
    */
132
133
134
135
    return;
}


136
void AudioSrtpSession::initializeLocalMasterSalt(void)
137
{
138

139
    // @TODO key may have different length depending on cipher suite 
140
  _localMasterSaltLength = sfl::CryptoSuites[_localCryptoSuite].masterSaltLength / 8;
Alexandre Savard's avatar
Alexandre Savard committed
141

142
    // Allocate memory for key
143
144
    unsigned char *random_key = new unsigned char[_localMasterSaltLength];

145
    // Generate ryptographically strong pseudo-random bytes
146
147
148
149
    int err;
    if((err = RAND_bytes(random_key, _localMasterSaltLength)) != 1)
        _debug("Error occured while generating cryptographically strong pseudo-random key");

150
    memcpy(_localMasterSalt, random_key, _localMasterSaltLength);
151

152
153
154
155
    return;

}

Alexandre Savard's avatar
Alexandre Savard committed
156
157
158
159

std::string AudioSrtpSession::getBase64ConcatenatedKeys()
{

160
    // compute concatenated master and salt length
161
    int concatLength = _localMasterKeyLength + _localMasterSaltLength;
162

163
    uint8 concatKeys[concatLength];
164
165

    // concatenate keys
166
167
    memcpy((void*)concatKeys, (void*)_localMasterKey, _localMasterKeyLength);
    memcpy((void*)(concatKeys + _localMasterKeyLength), (void*)_localMasterSalt, _localMasterSaltLength);
Alexandre Savard's avatar
Alexandre Savard committed
168

169
    // encode concatenated keys in base64
170
    char *output = encodeBase64((unsigned char*)concatKeys, concatLength);
Alexandre Savard's avatar
Alexandre Savard committed
171

172
    // init string containing encoded data
Alexandre Savard's avatar
Alexandre Savard committed
173
174
175
176
177
178
179
180
    std::string keys(output);

    free(output);

    return keys;
}


181
void AudioSrtpSession::unBase64ConcatenatedKeys(std::string base64keys)
182
183
{

184
185
    _remoteMasterKeyLength = sfl::CryptoSuites[1].masterKeyLength / 8;
    _remoteMasterSaltLength = sfl::CryptoSuites[1].masterSaltLength / 8;
Alexandre Savard's avatar
Alexandre Savard committed
186

187
    // length of decoded data data
188
189
    int length;

190
    // pointer to binary data
191
192
    char *dataptr = (char*)base64keys.data();

193
    // decode concatenated binary keys
194
195
    char *output = decodeBase64((unsigned char*)dataptr, strlen(dataptr), &length);

196
    // copy master and slt respectively
Alexandre Savard's avatar
Alexandre Savard committed
197
198
199
    memcpy((void*)_remoteMasterKey, (void*)output, _remoteMasterKeyLength);
    memcpy((void*)_remoteMasterSalt, (void*)(output + _remoteMasterKeyLength), _remoteMasterSaltLength);

200
201
202
203
204
    free(output);
}


void AudioSrtpSession::initializeRemoteCryptoContext(void)
205
{
206
    CryptoSuiteDefinition crypto = sfl::CryptoSuites[_localCryptoSuite];
207

208
    _remoteCryptoCtx = new ost::CryptoContext(0x0,
209
210
211
212
213
214
215
216
217
218
219
220
					     0,                               // roc,
					     0L,                              // keydr,
					     SrtpEncryptionAESCM,             // encryption algo
					     SrtpAuthenticationSha1Hmac,      // authtication algo
					     _remoteMasterKey,            
					     _remoteMasterKeyLength,      
					     _remoteMasterSalt,           
					     _remoteMasterSaltLength,       
					     crypto.encryptionKeyLength / 8, 
					     crypto.srtpAuthKeyLength / 8,
					     112 / 8,                         // session salt len
					     crypto.srtpAuthTagLength / 8);
221
222
223
    
}

224
void AudioSrtpSession::initializeLocalCryptoContext(void)
225
{
226
    CryptoSuiteDefinition crypto = sfl::CryptoSuites[_localCryptoSuite];
227

228
    _localCryptoCtx = new ost::CryptoContext(OutgoingDataQueue::getLocalSSRC(),
229
230
231
232
233
234
235
236
237
238
239
240
					      0,                               // roc,
					      0L,                              // keydr,
					      SrtpEncryptionAESCM,             // encryption algo
					      SrtpAuthenticationSha1Hmac,      // authtication algo
					      _localMasterKey,             
					      _localMasterKeyLength,       
					      _localMasterSalt,            
					      _localMasterSaltLength,      
					      crypto.encryptionKeyLength / 8,
					      crypto.srtpAuthKeyLength / 8,
					      112 / 8,                         // session salt len
					      crypto.srtpAuthTagLength / 8);
241
242
243
244
245
246
247

}


char* AudioSrtpSession::encodeBase64(unsigned char *input, int length)
{
    BIO *b64, *bmem;
Alexandre Savard's avatar
Alexandre Savard committed
248
    BUF_MEM *bptr ;
249

Alexandre Savard's avatar
Alexandre Savard committed
250
251
    char *buffer = (char *)malloc(2*length);
    memset(buffer, 0, 2*length);
252

253
    // init decoder
254
    b64 = BIO_new(BIO_f_base64());
255
    BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
256
257

    // init internal buffer
Alexandre Savard's avatar
Alexandre Savard committed
258
    bmem = BIO_new(BIO_s_mem());
259

Alexandre Savard's avatar
Alexandre Savard committed
260
261
262
263
264
265
266
267
268
    // create decoder chain
    b64 = BIO_push(b64, bmem);

    BIO_write(b64, input, length);
    BIO_flush(b64);

    // get pointer to data
    BIO_get_mem_ptr(b64, &bptr);

269
    // copy result in output buffer (-1 since we do not want the EOF character)
270
    strncpy(buffer, (char*)(bptr->data), bptr->length);
271
272
273

    BIO_free_all(bmem);

Alexandre Savard's avatar
Alexandre Savard committed
274
    return buffer;    
275
276
}

277
char* AudioSrtpSession::decodeBase64(unsigned char *input, int length, int *length_out)
278
279
280
281
282
{
    BIO *b64, *bmem;

    char *buffer = (char *)malloc(length);
    memset(buffer, 0, length);
Alexandre Savard's avatar
Alexandre Savard committed
283
284

    // init decoder and read-only BIO buffer
285
    b64 = BIO_new(BIO_f_base64());
286
    BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
287
288

    // init internal buffer
289
    bmem = BIO_new_mem_buf(input, length);
Alexandre Savard's avatar
Alexandre Savard committed
290
291

    // create encoder chain
292
    bmem = BIO_push(b64, bmem);
293

294
    *length_out = BIO_read(bmem, buffer, length);
295
296
297
298

    BIO_free_all(bmem);

    return buffer;
Alexandre Savard's avatar
Alexandre Savard committed
299

300
}
301

302
}