1 /*
2 * aes_icm_nss.c
3 *
4 * AES Integer Counter Mode
5 *
6 * Richard L. Barnes
7 * Cisco Systems, Inc.
8 */
9
10 /*
11 *
12 * Copyright (c) 2013-2017, Cisco Systems, Inc.
13 * All rights reserved.
14 *
15 * Redistribution and use in source and binary forms, with or without
16 * modification, are permitted provided that the following conditions
17 * are met:
18 *
19 * Redistributions of source code must retain the above copyright
20 * notice, this list of conditions and the following disclaimer.
21 *
22 * Redistributions in binary form must reproduce the above
23 * copyright notice, this list of conditions and the following
24 * disclaimer in the documentation and/or other materials provided
25 * with the distribution.
26 *
27 * Neither the name of the Cisco Systems, Inc. nor the names of its
28 * contributors may be used to endorse or promote products derived
29 * from this software without specific prior written permission.
30 *
31 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
34 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
35 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
36 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
37 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
38 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
39 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
40 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
41 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
42 * OF THE POSSIBILITY OF SUCH DAMAGE.
43 *
44 */
45
46 #ifdef HAVE_CONFIG_H
47 #include <config.h>
48 #endif
49
50 #include "aes_icm_ext.h"
51 #include "crypto_types.h"
52 #include "err.h" /* for srtp_debug */
53 #include "alloc.h"
54 #include "cipher_types.h"
55 #include "cipher_test_cases.h"
56
57 srtp_debug_module_t srtp_mod_aes_icm = {
58 0, /* debugging is off by default */
59 "aes icm nss" /* printable module name */
60 };
61
62 /*
63 * integer counter mode works as follows:
64 *
65 * 16 bits
66 * <----->
67 * +------+------+------+------+------+------+------+------+
68 * | nonce | packet index | ctr |---+
69 * +------+------+------+------+------+------+------+------+ |
70 * |
71 * +------+------+------+------+------+------+------+------+ v
72 * | salt |000000|->(+)
73 * +------+------+------+------+------+------+------+------+ |
74 * |
75 * +---------+
76 * | encrypt |
77 * +---------+
78 * |
79 * +------+------+------+------+------+------+------+------+ |
80 * | keystream block |<--+
81 * +------+------+------+------+------+------+------+------+
82 *
83 * All fields are big-endian
84 *
85 * ctr is the block counter, which increments from zero for
86 * each packet (16 bits wide)
87 *
88 * packet index is distinct for each packet (48 bits wide)
89 *
90 * nonce can be distinct across many uses of the same key, or
91 * can be a fixed value per key, or can be per-packet randomness
92 * (64 bits)
93 *
94 */
95
96 /*
97 * This function allocates a new instance of this crypto engine.
98 * The key_len parameter should be one of 30, 38, or 46 for
99 * AES-128, AES-192, and AES-256 respectively. Note, this key_len
100 * value is inflated, as it also accounts for the 112 bit salt
101 * value. The tlen argument is for the AEAD tag length, which
102 * isn't used in counter mode.
103 */
srtp_aes_icm_nss_alloc(srtp_cipher_t ** c,int key_len,int tlen)104 static srtp_err_status_t srtp_aes_icm_nss_alloc(srtp_cipher_t **c,
105 int key_len,
106 int tlen)
107 {
108 srtp_aes_icm_ctx_t *icm;
109 NSSInitContext *nss;
110
111 debug_print(srtp_mod_aes_icm, "allocating cipher with key length %d",
112 key_len);
113
114 /*
115 * Verify the key_len is valid for one of: AES-128/192/256
116 */
117 if (key_len != SRTP_AES_ICM_128_KEY_LEN_WSALT &&
118 key_len != SRTP_AES_ICM_192_KEY_LEN_WSALT &&
119 key_len != SRTP_AES_ICM_256_KEY_LEN_WSALT) {
120 return srtp_err_status_bad_param;
121 }
122
123 /* Initialize NSS equiv of NSS_NoDB_Init(NULL) */
124 nss = NSS_InitContext("", "", "", "", NULL,
125 NSS_INIT_READONLY | NSS_INIT_NOCERTDB |
126 NSS_INIT_NOMODDB | NSS_INIT_FORCEOPEN |
127 NSS_INIT_OPTIMIZESPACE);
128 if (!nss) {
129 return (srtp_err_status_cipher_fail);
130 }
131
132 /* allocate memory a cipher of type aes_icm */
133 *c = (srtp_cipher_t *)srtp_crypto_alloc(sizeof(srtp_cipher_t));
134 if (*c == NULL) {
135 NSS_ShutdownContext(nss);
136 return srtp_err_status_alloc_fail;
137 }
138
139 icm = (srtp_aes_icm_ctx_t *)srtp_crypto_alloc(sizeof(srtp_aes_icm_ctx_t));
140 if (icm == NULL) {
141 NSS_ShutdownContext(nss);
142 srtp_crypto_free(*c);
143 *c = NULL;
144 return srtp_err_status_alloc_fail;
145 }
146
147 icm->key = NULL;
148 icm->ctx = NULL;
149 icm->nss = nss;
150
151 /* set pointers */
152 (*c)->state = icm;
153
154 /* setup cipher parameters */
155 switch (key_len) {
156 case SRTP_AES_ICM_128_KEY_LEN_WSALT:
157 (*c)->algorithm = SRTP_AES_ICM_128;
158 (*c)->type = &srtp_aes_icm_128;
159 icm->key_size = SRTP_AES_128_KEY_LEN;
160 break;
161 case SRTP_AES_ICM_192_KEY_LEN_WSALT:
162 (*c)->algorithm = SRTP_AES_ICM_192;
163 (*c)->type = &srtp_aes_icm_192;
164 icm->key_size = SRTP_AES_192_KEY_LEN;
165 break;
166 case SRTP_AES_ICM_256_KEY_LEN_WSALT:
167 (*c)->algorithm = SRTP_AES_ICM_256;
168 (*c)->type = &srtp_aes_icm_256;
169 icm->key_size = SRTP_AES_256_KEY_LEN;
170 break;
171 }
172
173 /* set key size */
174 (*c)->key_len = key_len;
175
176 return srtp_err_status_ok;
177 }
178
179 /*
180 * This function deallocates an instance of this engine
181 */
srtp_aes_icm_nss_dealloc(srtp_cipher_t * c)182 static srtp_err_status_t srtp_aes_icm_nss_dealloc(srtp_cipher_t *c)
183 {
184 srtp_aes_icm_ctx_t *ctx;
185
186 ctx = (srtp_aes_icm_ctx_t *)c->state;
187 if (ctx) {
188 /* free any PK11 values that have been created */
189 if (ctx->key) {
190 PK11_FreeSymKey(ctx->key);
191 ctx->key = NULL;
192 }
193
194 if (ctx->ctx) {
195 PK11_DestroyContext(ctx->ctx, PR_TRUE);
196 ctx->ctx = NULL;
197 }
198
199 if (ctx->nss) {
200 NSS_ShutdownContext(ctx->nss);
201 ctx->nss = NULL;
202 }
203
204 /* zeroize everything */
205 octet_string_set_to_zero(ctx, sizeof(srtp_aes_icm_ctx_t));
206 srtp_crypto_free(ctx);
207 }
208
209 /* free memory */
210 srtp_crypto_free(c);
211
212 return (srtp_err_status_ok);
213 }
214
215 /*
216 * aes_icm_nss_context_init(...) initializes the aes_icm_context
217 * using the value in key[].
218 *
219 * the key is the secret key
220 *
221 * the salt is unpredictable (but not necessarily secret) data which
222 * randomizes the starting point in the keystream
223 */
srtp_aes_icm_nss_context_init(void * cv,const uint8_t * key)224 static srtp_err_status_t srtp_aes_icm_nss_context_init(void *cv,
225 const uint8_t *key)
226 {
227 srtp_aes_icm_ctx_t *c = (srtp_aes_icm_ctx_t *)cv;
228
229 /*
230 * set counter and initial values to 'offset' value, being careful not to
231 * go past the end of the key buffer
232 */
233 v128_set_to_zero(&c->counter);
234 v128_set_to_zero(&c->offset);
235 memcpy(&c->counter, key + c->key_size, SRTP_SALT_LEN);
236 memcpy(&c->offset, key + c->key_size, SRTP_SALT_LEN);
237
238 /* force last two octets of the offset to zero (for srtp compatibility) */
239 c->offset.v8[SRTP_SALT_LEN] = c->offset.v8[SRTP_SALT_LEN + 1] = 0;
240 c->counter.v8[SRTP_SALT_LEN] = c->counter.v8[SRTP_SALT_LEN + 1] = 0;
241
242 debug_print(srtp_mod_aes_icm, "key: %s",
243 srtp_octet_string_hex_string(key, c->key_size));
244 debug_print(srtp_mod_aes_icm, "offset: %s", v128_hex_string(&c->offset));
245
246 if (c->key) {
247 PK11_FreeSymKey(c->key);
248 c->key = NULL;
249 }
250
251 PK11SlotInfo *slot = PK11_GetBestSlot(CKM_AES_CTR, NULL);
252 if (!slot) {
253 return srtp_err_status_bad_param;
254 }
255
256 SECItem keyItem = { siBuffer, (unsigned char *)key, c->key_size };
257 c->key = PK11_ImportSymKey(slot, CKM_AES_CTR, PK11_OriginUnwrap,
258 CKA_ENCRYPT, &keyItem, NULL);
259 PK11_FreeSlot(slot);
260
261 if (!c->key) {
262 return srtp_err_status_cipher_fail;
263 }
264
265 return (srtp_err_status_ok);
266 }
267
268 /*
269 * aes_icm_set_iv(c, iv) sets the counter value to the exor of iv with
270 * the offset
271 */
srtp_aes_icm_nss_set_iv(void * cv,uint8_t * iv,srtp_cipher_direction_t dir)272 static srtp_err_status_t srtp_aes_icm_nss_set_iv(void *cv,
273 uint8_t *iv,
274 srtp_cipher_direction_t dir)
275 {
276 srtp_aes_icm_ctx_t *c = (srtp_aes_icm_ctx_t *)cv;
277 v128_t nonce;
278
279 /* set nonce (for alignment) */
280 v128_copy_octet_string(&nonce, iv);
281
282 debug_print(srtp_mod_aes_icm, "setting iv: %s", v128_hex_string(&nonce));
283
284 v128_xor(&c->counter, &c->offset, &nonce);
285
286 debug_print(srtp_mod_aes_icm, "set_counter: %s",
287 v128_hex_string(&c->counter));
288
289 /* set up the PK11 context now that we have all the info */
290 CK_AES_CTR_PARAMS param;
291 param.ulCounterBits = 16;
292 memcpy(param.cb, &c->counter, 16);
293
294 if (!c->key) {
295 return srtp_err_status_bad_param;
296 }
297
298 if (c->ctx) {
299 PK11_DestroyContext(c->ctx, PR_TRUE);
300 }
301
302 SECItem paramItem = { siBuffer, (unsigned char *)¶m,
303 sizeof(CK_AES_CTR_PARAMS) };
304 c->ctx = PK11_CreateContextBySymKey(CKM_AES_CTR, CKA_ENCRYPT, c->key,
305 ¶mItem);
306 if (!c->ctx) {
307 return srtp_err_status_cipher_fail;
308 }
309
310 return srtp_err_status_ok;
311 }
312
313 /*
314 * This function encrypts a buffer using AES CTR mode
315 *
316 * Parameters:
317 * c Crypto context
318 * buf data to encrypt
319 * enc_len length of encrypt buffer
320 */
srtp_aes_icm_nss_encrypt(void * cv,unsigned char * buf,unsigned int * enc_len)321 static srtp_err_status_t srtp_aes_icm_nss_encrypt(void *cv,
322 unsigned char *buf,
323 unsigned int *enc_len)
324 {
325 srtp_aes_icm_ctx_t *c = (srtp_aes_icm_ctx_t *)cv;
326
327 if (!c->ctx) {
328 return srtp_err_status_bad_param;
329 }
330
331 int rv =
332 PK11_CipherOp(c->ctx, buf, (int *)enc_len, *enc_len, buf, *enc_len);
333
334 srtp_err_status_t status = (srtp_err_status_ok);
335 if (rv != SECSuccess) {
336 status = (srtp_err_status_cipher_fail);
337 }
338
339 return status;
340 }
341
342 /*
343 * Name of this crypto engine
344 */
345 static const char srtp_aes_icm_128_nss_description[] =
346 "AES-128 counter mode using NSS";
347 static const char srtp_aes_icm_192_nss_description[] =
348 "AES-192 counter mode using NSS";
349 static const char srtp_aes_icm_256_nss_description[] =
350 "AES-256 counter mode using NSS";
351
352 /*
353 * This is the function table for this crypto engine.
354 * note: the encrypt function is identical to the decrypt function
355 */
356 const srtp_cipher_type_t srtp_aes_icm_128 = {
357 srtp_aes_icm_nss_alloc, /* */
358 srtp_aes_icm_nss_dealloc, /* */
359 srtp_aes_icm_nss_context_init, /* */
360 0, /* set_aad */
361 srtp_aes_icm_nss_encrypt, /* */
362 srtp_aes_icm_nss_encrypt, /* */
363 srtp_aes_icm_nss_set_iv, /* */
364 0, /* get_tag */
365 srtp_aes_icm_128_nss_description, /* */
366 &srtp_aes_icm_128_test_case_0, /* */
367 SRTP_AES_ICM_128 /* */
368 };
369
370 /*
371 * This is the function table for this crypto engine.
372 * note: the encrypt function is identical to the decrypt function
373 */
374 const srtp_cipher_type_t srtp_aes_icm_192 = {
375 srtp_aes_icm_nss_alloc, /* */
376 srtp_aes_icm_nss_dealloc, /* */
377 srtp_aes_icm_nss_context_init, /* */
378 0, /* set_aad */
379 srtp_aes_icm_nss_encrypt, /* */
380 srtp_aes_icm_nss_encrypt, /* */
381 srtp_aes_icm_nss_set_iv, /* */
382 0, /* get_tag */
383 srtp_aes_icm_192_nss_description, /* */
384 &srtp_aes_icm_192_test_case_0, /* */
385 SRTP_AES_ICM_192 /* */
386 };
387
388 /*
389 * This is the function table for this crypto engine.
390 * note: the encrypt function is identical to the decrypt function
391 */
392 const srtp_cipher_type_t srtp_aes_icm_256 = {
393 srtp_aes_icm_nss_alloc, /* */
394 srtp_aes_icm_nss_dealloc, /* */
395 srtp_aes_icm_nss_context_init, /* */
396 0, /* set_aad */
397 srtp_aes_icm_nss_encrypt, /* */
398 srtp_aes_icm_nss_encrypt, /* */
399 srtp_aes_icm_nss_set_iv, /* */
400 0, /* get_tag */
401 srtp_aes_icm_256_nss_description, /* */
402 &srtp_aes_icm_256_test_case_0, /* */
403 SRTP_AES_ICM_256 /* */
404 };
405