aes_icm_nss.c (13172B)
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 */ 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 (void)tlen; 111 112 debug_print(srtp_mod_aes_icm, "allocating cipher with key length %d", 113 key_len); 114 115 /* 116 * Verify the key_len is valid for one of: AES-128/192/256 117 */ 118 if (key_len != SRTP_AES_ICM_128_KEY_LEN_WSALT && 119 key_len != SRTP_AES_ICM_192_KEY_LEN_WSALT && 120 key_len != SRTP_AES_ICM_256_KEY_LEN_WSALT) { 121 return srtp_err_status_bad_param; 122 } 123 124 /* Initialize NSS equiv of NSS_NoDB_Init(NULL) */ 125 nss = NSS_InitContext("", "", "", "", NULL, 126 NSS_INIT_READONLY | NSS_INIT_NOCERTDB | 127 NSS_INIT_NOMODDB | NSS_INIT_FORCEOPEN | 128 NSS_INIT_OPTIMIZESPACE); 129 if (!nss) { 130 return (srtp_err_status_cipher_fail); 131 } 132 133 /* allocate memory a cipher of type aes_icm */ 134 *c = (srtp_cipher_t *)srtp_crypto_alloc(sizeof(srtp_cipher_t)); 135 if (*c == NULL) { 136 NSS_ShutdownContext(nss); 137 return srtp_err_status_alloc_fail; 138 } 139 140 icm = (srtp_aes_icm_ctx_t *)srtp_crypto_alloc(sizeof(srtp_aes_icm_ctx_t)); 141 if (icm == NULL) { 142 NSS_ShutdownContext(nss); 143 srtp_crypto_free(*c); 144 *c = NULL; 145 return srtp_err_status_alloc_fail; 146 } 147 148 icm->key = NULL; 149 icm->ctx = NULL; 150 icm->nss = nss; 151 152 /* set pointers */ 153 (*c)->state = icm; 154 155 /* setup cipher parameters */ 156 switch (key_len) { 157 case SRTP_AES_ICM_128_KEY_LEN_WSALT: 158 (*c)->algorithm = SRTP_AES_ICM_128; 159 (*c)->type = &srtp_aes_icm_128; 160 icm->key_size = SRTP_AES_128_KEY_LEN; 161 break; 162 case SRTP_AES_ICM_192_KEY_LEN_WSALT: 163 (*c)->algorithm = SRTP_AES_ICM_192; 164 (*c)->type = &srtp_aes_icm_192; 165 icm->key_size = SRTP_AES_192_KEY_LEN; 166 break; 167 case SRTP_AES_ICM_256_KEY_LEN_WSALT: 168 (*c)->algorithm = SRTP_AES_ICM_256; 169 (*c)->type = &srtp_aes_icm_256; 170 icm->key_size = SRTP_AES_256_KEY_LEN; 171 break; 172 } 173 174 /* set key size */ 175 (*c)->key_len = key_len; 176 177 return srtp_err_status_ok; 178 } 179 180 /* 181 * This function deallocates an instance of this engine 182 */ 183 static srtp_err_status_t srtp_aes_icm_nss_dealloc(srtp_cipher_t *c) 184 { 185 srtp_aes_icm_ctx_t *ctx; 186 187 ctx = (srtp_aes_icm_ctx_t *)c->state; 188 if (ctx) { 189 /* free any PK11 values that have been created */ 190 if (ctx->key) { 191 PK11_FreeSymKey(ctx->key); 192 ctx->key = NULL; 193 } 194 195 if (ctx->ctx) { 196 PK11_DestroyContext(ctx->ctx, PR_TRUE); 197 ctx->ctx = NULL; 198 } 199 200 if (ctx->nss) { 201 NSS_ShutdownContext(ctx->nss); 202 ctx->nss = NULL; 203 } 204 205 /* zeroize everything */ 206 octet_string_set_to_zero(ctx, sizeof(srtp_aes_icm_ctx_t)); 207 srtp_crypto_free(ctx); 208 } 209 210 /* free memory */ 211 srtp_crypto_free(c); 212 213 return (srtp_err_status_ok); 214 } 215 216 /* 217 * aes_icm_nss_context_init(...) initializes the aes_icm_context 218 * using the value in key[]. 219 * 220 * the key is the secret key 221 * 222 * the salt is unpredictable (but not necessarily secret) data which 223 * randomizes the starting point in the keystream 224 */ 225 static srtp_err_status_t srtp_aes_icm_nss_context_init(void *cv, 226 const uint8_t *key) 227 { 228 srtp_aes_icm_ctx_t *c = (srtp_aes_icm_ctx_t *)cv; 229 230 /* 231 * set counter and initial values to 'offset' value, being careful not to 232 * go past the end of the key buffer 233 */ 234 v128_set_to_zero(&c->counter); 235 v128_set_to_zero(&c->offset); 236 memcpy(&c->counter, key + c->key_size, SRTP_SALT_LEN); 237 memcpy(&c->offset, key + c->key_size, SRTP_SALT_LEN); 238 239 /* force last two octets of the offset to zero (for srtp compatibility) */ 240 c->offset.v8[SRTP_SALT_LEN] = c->offset.v8[SRTP_SALT_LEN + 1] = 0; 241 c->counter.v8[SRTP_SALT_LEN] = c->counter.v8[SRTP_SALT_LEN + 1] = 0; 242 243 debug_print(srtp_mod_aes_icm, "key: %s", 244 srtp_octet_string_hex_string(key, c->key_size)); 245 debug_print(srtp_mod_aes_icm, "offset: %s", v128_hex_string(&c->offset)); 246 247 if (c->key) { 248 PK11_FreeSymKey(c->key); 249 c->key = NULL; 250 } 251 252 PK11SlotInfo *slot = PK11_GetBestSlot(CKM_AES_CTR, NULL); 253 if (!slot) { 254 return srtp_err_status_bad_param; 255 } 256 257 /* explicitly cast away const of key */ 258 SECItem keyItem = { siBuffer, (unsigned char *)(uintptr_t)key, 259 c->key_size }; 260 c->key = PK11_ImportSymKey(slot, CKM_AES_CTR, PK11_OriginUnwrap, 261 CKA_ENCRYPT, &keyItem, NULL); 262 PK11_FreeSlot(slot); 263 264 if (!c->key) { 265 return srtp_err_status_cipher_fail; 266 } 267 268 return (srtp_err_status_ok); 269 } 270 271 /* 272 * aes_icm_set_iv(c, iv) sets the counter value to the exor of iv with 273 * the offset 274 */ 275 static srtp_err_status_t srtp_aes_icm_nss_set_iv(void *cv, 276 uint8_t *iv, 277 srtp_cipher_direction_t dir) 278 { 279 srtp_aes_icm_ctx_t *c = (srtp_aes_icm_ctx_t *)cv; 280 v128_t nonce; 281 (void)dir; 282 283 /* set nonce (for alignment) */ 284 v128_copy_octet_string(&nonce, iv); 285 286 debug_print(srtp_mod_aes_icm, "setting iv: %s", v128_hex_string(&nonce)); 287 288 v128_xor(&c->counter, &c->offset, &nonce); 289 290 debug_print(srtp_mod_aes_icm, "set_counter: %s", 291 v128_hex_string(&c->counter)); 292 293 /* set up the PK11 context now that we have all the info */ 294 CK_AES_CTR_PARAMS param; 295 param.ulCounterBits = 16; 296 memcpy(param.cb, &c->counter, 16); 297 298 if (!c->key) { 299 return srtp_err_status_bad_param; 300 } 301 302 if (c->ctx) { 303 PK11_DestroyContext(c->ctx, PR_TRUE); 304 } 305 306 SECItem paramItem = { siBuffer, (unsigned char *)¶m, 307 sizeof(CK_AES_CTR_PARAMS) }; 308 c->ctx = PK11_CreateContextBySymKey(CKM_AES_CTR, CKA_ENCRYPT, c->key, 309 ¶mItem); 310 if (!c->ctx) { 311 return srtp_err_status_cipher_fail; 312 } 313 314 return srtp_err_status_ok; 315 } 316 317 /* 318 * This function encrypts a buffer using AES CTR mode 319 * 320 * Parameters: 321 * c Crypto context 322 * buf data to encrypt 323 * enc_len length of encrypt buffer 324 */ 325 static srtp_err_status_t srtp_aes_icm_nss_encrypt(void *cv, 326 unsigned char *buf, 327 unsigned int *enc_len) 328 { 329 srtp_aes_icm_ctx_t *c = (srtp_aes_icm_ctx_t *)cv; 330 331 if (!c->ctx) { 332 return srtp_err_status_bad_param; 333 } 334 335 int rv = 336 PK11_CipherOp(c->ctx, buf, (int *)enc_len, *enc_len, buf, *enc_len); 337 338 srtp_err_status_t status = (srtp_err_status_ok); 339 if (rv != SECSuccess) { 340 status = (srtp_err_status_cipher_fail); 341 } 342 343 return status; 344 } 345 346 /* 347 * Name of this crypto engine 348 */ 349 static const char srtp_aes_icm_128_nss_description[] = 350 "AES-128 counter mode using NSS"; 351 static const char srtp_aes_icm_192_nss_description[] = 352 "AES-192 counter mode using NSS"; 353 static const char srtp_aes_icm_256_nss_description[] = 354 "AES-256 counter mode using NSS"; 355 356 /* 357 * This is the function table for this crypto engine. 358 * note: the encrypt function is identical to the decrypt function 359 */ 360 const srtp_cipher_type_t srtp_aes_icm_128 = { 361 srtp_aes_icm_nss_alloc, /* */ 362 srtp_aes_icm_nss_dealloc, /* */ 363 srtp_aes_icm_nss_context_init, /* */ 364 0, /* set_aad */ 365 srtp_aes_icm_nss_encrypt, /* */ 366 srtp_aes_icm_nss_encrypt, /* */ 367 srtp_aes_icm_nss_set_iv, /* */ 368 0, /* get_tag */ 369 srtp_aes_icm_128_nss_description, /* */ 370 &srtp_aes_icm_128_test_case_0, /* */ 371 SRTP_AES_ICM_128 /* */ 372 }; 373 374 /* 375 * This is the function table for this crypto engine. 376 * note: the encrypt function is identical to the decrypt function 377 */ 378 const srtp_cipher_type_t srtp_aes_icm_192 = { 379 srtp_aes_icm_nss_alloc, /* */ 380 srtp_aes_icm_nss_dealloc, /* */ 381 srtp_aes_icm_nss_context_init, /* */ 382 0, /* set_aad */ 383 srtp_aes_icm_nss_encrypt, /* */ 384 srtp_aes_icm_nss_encrypt, /* */ 385 srtp_aes_icm_nss_set_iv, /* */ 386 0, /* get_tag */ 387 srtp_aes_icm_192_nss_description, /* */ 388 &srtp_aes_icm_192_test_case_0, /* */ 389 SRTP_AES_ICM_192 /* */ 390 }; 391 392 /* 393 * This is the function table for this crypto engine. 394 * note: the encrypt function is identical to the decrypt function 395 */ 396 const srtp_cipher_type_t srtp_aes_icm_256 = { 397 srtp_aes_icm_nss_alloc, /* */ 398 srtp_aes_icm_nss_dealloc, /* */ 399 srtp_aes_icm_nss_context_init, /* */ 400 0, /* set_aad */ 401 srtp_aes_icm_nss_encrypt, /* */ 402 srtp_aes_icm_nss_encrypt, /* */ 403 srtp_aes_icm_nss_set_iv, /* */ 404 0, /* get_tag */ 405 srtp_aes_icm_256_nss_description, /* */ 406 &srtp_aes_icm_256_test_case_0, /* */ 407 SRTP_AES_ICM_256 /* */ 408 };