forked from wernerd/ZRTPCPP
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathSrtpHandler.cpp
275 lines (212 loc) · 8.72 KB
/
SrtpHandler.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
/*
Copyright (C) 2012 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
*/
/*
* @author Werner Dittmann <Werner.Dittmann@t-online.de>
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <common/osSpecifics.h>
#include <SrtpHandler.h>
#include <CryptoContext.h>
#include <CryptoContextCtrl.h>
bool SrtpHandler::decodeRtp(uint8_t* buffer, int32_t length, uint32_t *ssrc, uint16_t *seq, uint8_t** payload, int32_t *payloadlen)
{
int offset;
uint16_t *pus;
uint32_t *pui;
/* Assume RTP header at the start of buffer. */
if ((*buffer & 0xC0) != 0x80) { // check version bits
return false;
}
if (length < RTP_HEADER_LENGTH)
return false;
/* Get some handy pointers */
pus = (uint16_t*)buffer;
pui = (uint32_t*)buffer;
uint16_t tmp16 = pus[1]; // get seq number
*seq = zrtpNtohs(tmp16); // and return in host oder
uint32_t tmp32 = pui[2]; // get SSRC
*ssrc = zrtpNtohl(tmp32); // and return in host order
/* Payload is located right after header plus CSRC */
int32_t numCC = buffer[0] & 0x0f; // lower 4 bits in first byte is num of contrib SSRC
offset = RTP_HEADER_LENGTH + (numCC * sizeof(uint32_t));
// Sanity check
if (offset > length)
return false;
/* Adjust payload offset if RTP extension is used. */
if ((*buffer & 0x10) == 0x10) { // packet contains RTP extension
pus = (uint16_t*)(buffer + offset); // pus points to extension as 16bit pointer
tmp16 = pus[1]; // the second 16 bit word is the length
tmp16 = zrtpNtohs(tmp16); // to host order
offset += (tmp16 + 1) * sizeof(uint32_t);
}
/* Sanity check */
if (offset > length)
return false;
/* Set payload and payload length. */
*payload = buffer + offset;
*payloadlen = length - offset;
return true;
}
static void fillErrorData(SrtpErrorData* data, SrtpErrorType type, uint8_t* buffer, size_t length, uint64_t guessedIndex)
{
data->errorType = type;
memcpy((void*)data->rtpHeader, (void*)buffer, RTP_HEADER_LENGTH);
data->length = length;
data->guessedIndex = guessedIndex;
}
bool SrtpHandler::protect(CryptoContext* pcc, uint8_t* buffer, size_t length, size_t* newLength)
{
uint8_t* payload = NULL;
int32_t payloadlen = 0;
uint16_t seqnum;
uint32_t ssrc;
if (pcc == NULL) {
return false;
}
if (!decodeRtp(buffer, length, &ssrc, &seqnum, &payload, &payloadlen))
return false;
/* Encrypt the packet */
uint64_t index = ((uint64_t)pcc->getRoc() << 16) | (uint64_t)seqnum;
pcc->srtpEncrypt(buffer, payload, payloadlen, index, ssrc);
// NO MKI support yet - here we assume MKI is zero. To build in MKI
// take MKI length into account when storing the authentication tag.
/* Compute MAC and store at end of RTP packet data */
if (pcc->getTagLength() > 0) {
pcc->srtpAuthenticate(buffer, length, pcc->getRoc(), buffer+length);
}
*newLength = length + pcc->getTagLength();
/* Update the ROC if necessary */
if (seqnum == 0xFFFF ) {
pcc->setRoc(pcc->getRoc() + 1);
}
return true;
}
int32_t SrtpHandler::unprotect(CryptoContext* pcc, uint8_t* buffer, size_t length, size_t* newLength, SrtpErrorData* errorData)
{
uint8_t* payload = NULL;
int32_t payloadlen = 0;
uint16_t seqnum;
uint32_t ssrc;
if (pcc == NULL) {
return 0;
}
if (!decodeRtp(buffer, length, &ssrc, &seqnum, &payload, &payloadlen)) {
if (errorData != NULL)
fillErrorData(errorData, DecodeError, buffer, length, 0);
return 0;
}
/*
* This is the setting of the packet data when we come to this point:
*
* length: complete length of received data
* buffer: points to data as received from network
* payloadlen: length of data excluding hdrSize and padding
*
* Because this is an SRTP packet we need to adjust some values here.
* The SRTP MKI and authentication data is always at the end of a
* packet. Thus compute the positions of this data.
*/
uint32_t srtpDataIndex = length - (pcc->getTagLength() + pcc->getMkiLength());
// Compute new length
length -= pcc->getTagLength() + pcc->getMkiLength();
*newLength = length;
// recompute payloadlen by subtracting SRTP data
payloadlen -= pcc->getTagLength() + pcc->getMkiLength();
// MKI is unused, so just skip it
// const uint8* mki = buffer + srtpDataIndex;
uint8_t* tag = buffer + srtpDataIndex + pcc->getMkiLength();
/* Guess the index */
uint64_t guessedIndex = pcc->guessIndex(seqnum);
/* Replay control */
if (!pcc->checkReplay(seqnum)) {
if (errorData != NULL)
fillErrorData(errorData, ReplayError, buffer, length, guessedIndex);
return -2;
}
if (pcc->getTagLength() > 0) {
uint32_t guessedRoc = guessedIndex >> 16;
uint8_t mac[20];
pcc->srtpAuthenticate(buffer, (uint32_t)length, guessedRoc, mac);
if (memcmp(tag, mac, pcc->getTagLength()) != 0) {
if (errorData != NULL)
fillErrorData(errorData, AuthError, buffer, length, guessedIndex);
return -1;
}
}
/* Decrypt the content */
pcc->srtpEncrypt(buffer, payload, payloadlen, guessedIndex, ssrc);
/* Update the Crypto-context */
pcc->update(seqnum);
return 1;
}
bool SrtpHandler::protectCtrl(CryptoContextCtrl* pcc, uint8_t* buffer, size_t length, size_t* newLength)
{
if (pcc == NULL) {
return false;
}
/* Encrypt the packet */
uint32_t ssrc = *(reinterpret_cast<uint32_t*>(buffer + 4)); // always SSRC of sender
ssrc = zrtpNtohl(ssrc);
uint32_t encIndex = pcc->getSrtcpIndex();
pcc->srtcpEncrypt(buffer + 8, length - 8, encIndex, ssrc);
encIndex |= 0x80000000; // set the E flag
// Fill SRTCP index as last word
uint32_t* ip = reinterpret_cast<uint32_t*>(buffer+length);
*ip = zrtpHtonl(encIndex);
// NO MKI support yet - here we assume MKI is zero. To build in MKI
// take MKI length into account when storing the authentication tag.
// Compute MAC and store in packet after the SRTCP index field
pcc->srtcpAuthenticate(buffer, length, encIndex, buffer + length + sizeof(uint32_t));
encIndex++;
encIndex &= ~0x80000000; // clear the E-flag and modulo 2^31
pcc->setSrtcpIndex(encIndex);
*newLength = length + pcc->getTagLength() + sizeof(uint32_t);
return true;
}
int32_t SrtpHandler::unprotectCtrl(CryptoContextCtrl* pcc, uint8_t* buffer, size_t length, size_t* newLength)
{
if (pcc == NULL) {
return 0;
}
// Compute the total length of the payload
int32_t payloadLen = length - (pcc->getTagLength() + pcc->getMkiLength() + 4);
*newLength = payloadLen;
// point to the SRTCP index field just after the real payload
const uint32_t* index = reinterpret_cast<uint32_t*>(buffer + payloadLen);
uint32_t encIndex = zrtpNtohl(*index);
uint32_t remoteIndex = encIndex & ~0x80000000; // get index without Encryption flag
if (!pcc->checkReplay(remoteIndex)) {
return -2;
}
uint8_t mac[20];
// Now get a pointer to the authentication tag field
const uint8_t* tag = buffer + (length - pcc->getTagLength());
// Authenticate includes the index, but not MKI and not (obviously) the tag itself
pcc->srtcpAuthenticate(buffer, payloadLen, encIndex, mac);
if (memcmp(tag, mac, pcc->getTagLength()) != 0) {
return -1;
}
uint32_t ssrc = *(reinterpret_cast<uint32_t*>(buffer + 4)); // always SSRC of sender
ssrc = zrtpNtohl(ssrc);
// Decrypt the content, exclude the very first SRTCP header (fixed, 8 bytes)
if (encIndex & 0x80000000)
pcc->srtcpEncrypt(buffer + 8, payloadLen - 8, remoteIndex, ssrc);
// Update the Crypto-context
pcc->update(remoteIndex);
return 1;
}