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