pk11gcmtest.c (15797B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 #include <stdio.h> 6 #include <stdlib.h> 7 #include <ctype.h> 8 9 #include "pk11pub.h" 10 #include "secerr.h" 11 #include "nss.h" 12 13 static SECStatus 14 hex_to_byteval(const char *c2, unsigned char *byteval) 15 { 16 int i; 17 unsigned char offset; 18 *byteval = 0; 19 for (i = 0; i < 2; i++) { 20 if (c2[i] >= '0' && c2[i] <= '9') { 21 offset = c2[i] - '0'; 22 *byteval |= offset << 4 * (1 - i); 23 } else if (c2[i] >= 'a' && c2[i] <= 'f') { 24 offset = c2[i] - 'a'; 25 *byteval |= (offset + 10) << 4 * (1 - i); 26 } else if (c2[i] >= 'A' && c2[i] <= 'F') { 27 offset = c2[i] - 'A'; 28 *byteval |= (offset + 10) << 4 * (1 - i); 29 } else { 30 return SECFailure; 31 } 32 } 33 return SECSuccess; 34 } 35 36 static SECStatus 37 aes_encrypt_buf( 38 const unsigned char *key, unsigned int keysize, 39 const unsigned char *iv, unsigned int ivsize, 40 unsigned char *output, unsigned int *outputlen, unsigned int maxoutputlen, 41 const unsigned char *input, unsigned int inputlen, 42 const unsigned char *aad, unsigned int aadlen, unsigned int tagsize) 43 { 44 SECStatus rv = SECFailure; 45 SECItem key_item; 46 PK11SlotInfo *slot = NULL; 47 PK11SymKey *symKey = NULL; 48 CK_NSS_GCM_PARAMS gcm_params; 49 SECItem param; 50 51 /* Import key into NSS. */ 52 key_item.type = siBuffer; 53 key_item.data = (unsigned char *)key; /* const cast */ 54 key_item.len = keysize; 55 slot = PK11_GetInternalSlot(); 56 symKey = PK11_ImportSymKey(slot, CKM_AES_GCM, PK11_OriginUnwrap, 57 CKA_ENCRYPT, &key_item, NULL); 58 PK11_FreeSlot(slot); 59 slot = NULL; 60 if (!symKey) { 61 fprintf(stderr, "PK11_ImportSymKey failed\n"); 62 goto loser; 63 } 64 65 gcm_params.pIv = (unsigned char *)iv; /* const cast */ 66 gcm_params.ulIvLen = ivsize; 67 gcm_params.pAAD = (unsigned char *)aad; /* const cast */ 68 gcm_params.ulAADLen = aadlen; 69 gcm_params.ulTagBits = tagsize * 8; 70 71 param.type = siBuffer; 72 param.data = (unsigned char *)&gcm_params; 73 param.len = sizeof(gcm_params); 74 75 if (PK11_Encrypt(symKey, CKM_AES_GCM, ¶m, 76 output, outputlen, maxoutputlen, 77 input, inputlen) != SECSuccess) { 78 fprintf(stderr, "PK11_Encrypt failed\n"); 79 goto loser; 80 } 81 82 rv = SECSuccess; 83 84 loser: 85 if (symKey != NULL) { 86 PK11_FreeSymKey(symKey); 87 } 88 return rv; 89 } 90 91 static SECStatus 92 aes_decrypt_buf( 93 const unsigned char *key, unsigned int keysize, 94 const unsigned char *iv, unsigned int ivsize, 95 unsigned char *output, unsigned int *outputlen, unsigned int maxoutputlen, 96 const unsigned char *input, unsigned int inputlen, 97 const unsigned char *aad, unsigned int aadlen, 98 const unsigned char *tag, unsigned int tagsize) 99 { 100 SECStatus rv = SECFailure; 101 unsigned char concatenated[11 * 16]; /* 1 to 11 blocks */ 102 SECItem key_item; 103 PK11SlotInfo *slot = NULL; 104 PK11SymKey *symKey = NULL; 105 CK_NSS_GCM_PARAMS gcm_params; 106 SECItem param; 107 108 if (inputlen + tagsize > sizeof(concatenated)) { 109 fprintf(stderr, "aes_decrypt_buf: local buffer too small\n"); 110 goto loser; 111 } 112 memcpy(concatenated, input, inputlen); 113 memcpy(concatenated + inputlen, tag, tagsize); 114 115 /* Import key into NSS. */ 116 key_item.type = siBuffer; 117 key_item.data = (unsigned char *)key; /* const cast */ 118 key_item.len = keysize; 119 slot = PK11_GetInternalSlot(); 120 symKey = PK11_ImportSymKey(slot, CKM_AES_GCM, PK11_OriginUnwrap, 121 CKA_DECRYPT, &key_item, NULL); 122 PK11_FreeSlot(slot); 123 slot = NULL; 124 if (!symKey) { 125 fprintf(stderr, "PK11_ImportSymKey failed\n"); 126 goto loser; 127 } 128 129 gcm_params.pIv = (unsigned char *)iv; 130 gcm_params.ulIvLen = ivsize; 131 gcm_params.pAAD = (unsigned char *)aad; 132 gcm_params.ulAADLen = aadlen; 133 gcm_params.ulTagBits = tagsize * 8; 134 135 param.type = siBuffer; 136 param.data = (unsigned char *)&gcm_params; 137 param.len = sizeof(gcm_params); 138 139 if (PK11_Decrypt(symKey, CKM_AES_GCM, ¶m, 140 output, outputlen, maxoutputlen, 141 concatenated, inputlen + tagsize) != SECSuccess) { 142 goto loser; 143 } 144 145 rv = SECSuccess; 146 147 loser: 148 if (symKey != NULL) { 149 PK11_FreeSymKey(symKey); 150 } 151 return rv; 152 } 153 154 /* 155 * Perform the AES Known Answer Test (KAT) in Galois Counter Mode (GCM). 156 * 157 * respfn is the pathname of the RESPONSE file. 158 */ 159 static void 160 aes_gcm_kat(const char *respfn) 161 { 162 char buf[512]; /* holds one line from the input REQUEST file. 163 * needs to be large enough to hold the longest 164 * line "CIPHERTEXT = <320 hex digits>\n". 165 */ 166 FILE *aesresp; /* input stream from the RESPONSE file */ 167 int i, j; 168 unsigned int test_group = 0; 169 unsigned int num_tests = 0; 170 PRBool is_encrypt; 171 unsigned char key[32]; /* 128, 192, or 256 bits */ 172 unsigned int keysize = 16; 173 unsigned char iv[10 * 16]; /* 1 to 10 blocks */ 174 unsigned int ivsize = 12; 175 unsigned char plaintext[10 * 16]; /* 1 to 10 blocks */ 176 unsigned int plaintextlen = 0; 177 unsigned char aad[10 * 16]; /* 1 to 10 blocks */ 178 unsigned int aadlen = 0; 179 unsigned char ciphertext[10 * 16]; /* 1 to 10 blocks */ 180 unsigned int ciphertextlen = 0; 181 unsigned char tag[16]; 182 unsigned int tagsize = 16; 183 unsigned char output[10 * 16]; /* 1 to 10 blocks */ 184 unsigned int outputlen = 0; 185 186 unsigned int expected_keylen = 0; 187 unsigned int expected_ivlen = 0; 188 unsigned int expected_ptlen = 0; 189 unsigned int expected_aadlen = 0; 190 unsigned int expected_taglen = 0; 191 SECStatus rv; 192 193 if (strstr(respfn, "Encrypt") != NULL) { 194 is_encrypt = PR_TRUE; 195 } else if (strstr(respfn, "Decrypt") != NULL) { 196 is_encrypt = PR_FALSE; 197 } else { 198 fprintf(stderr, "Input file name must contain Encrypt or Decrypt\n"); 199 exit(1); 200 } 201 aesresp = fopen(respfn, "r"); 202 if (aesresp == NULL) { 203 fprintf(stderr, "Cannot open input file %s\n", respfn); 204 exit(1); 205 } 206 while (fgets(buf, sizeof buf, aesresp) != NULL) { 207 /* a comment or blank line */ 208 if (buf[0] == '#' || buf[0] == '\n') { 209 continue; 210 } 211 /* [Keylen = ...], [IVlen = ...], etc. */ 212 if (buf[0] == '[') { 213 if (strncmp(&buf[1], "Keylen = ", 9) == 0) { 214 expected_keylen = atoi(&buf[10]); 215 } else if (strncmp(&buf[1], "IVlen = ", 8) == 0) { 216 expected_ivlen = atoi(&buf[9]); 217 } else if (strncmp(&buf[1], "PTlen = ", 8) == 0) { 218 expected_ptlen = atoi(&buf[9]); 219 } else if (strncmp(&buf[1], "AADlen = ", 9) == 0) { 220 expected_aadlen = atoi(&buf[10]); 221 } else if (strncmp(&buf[1], "Taglen = ", 9) == 0) { 222 expected_taglen = atoi(&buf[10]); 223 224 test_group++; 225 if (test_group > 1) { 226 /* Report num_tests for the previous test group. */ 227 printf("%u tests\n", num_tests); 228 } 229 num_tests = 0; 230 printf("Keylen = %u, IVlen = %u, PTlen = %u, AADlen = %u, " 231 "Taglen = %u: ", 232 expected_keylen, expected_ivlen, 233 expected_ptlen, expected_aadlen, expected_taglen); 234 /* Convert lengths in bits to lengths in bytes. */ 235 PORT_Assert(expected_keylen % 8 == 0); 236 expected_keylen /= 8; 237 PORT_Assert(expected_ivlen % 8 == 0); 238 expected_ivlen /= 8; 239 PORT_Assert(expected_ptlen % 8 == 0); 240 expected_ptlen /= 8; 241 PORT_Assert(expected_aadlen % 8 == 0); 242 expected_aadlen /= 8; 243 PORT_Assert(expected_taglen % 8 == 0); 244 expected_taglen /= 8; 245 } else { 246 fprintf(stderr, "Unexpected input line: %s\n", buf); 247 exit(1); 248 } 249 continue; 250 } 251 /* "Count = x" begins a new data set */ 252 if (strncmp(buf, "Count", 5) == 0) { 253 /* zeroize the variables for the test with this data set */ 254 memset(key, 0, sizeof key); 255 keysize = 0; 256 memset(iv, 0, sizeof iv); 257 ivsize = 0; 258 memset(plaintext, 0, sizeof plaintext); 259 plaintextlen = 0; 260 memset(aad, 0, sizeof aad); 261 aadlen = 0; 262 memset(ciphertext, 0, sizeof ciphertext); 263 ciphertextlen = 0; 264 memset(output, 0, sizeof output); 265 outputlen = 0; 266 num_tests++; 267 continue; 268 } 269 /* Key = ... */ 270 if (strncmp(buf, "Key", 3) == 0) { 271 i = 3; 272 while (isspace((unsigned char)buf[i]) || buf[i] == '=') { 273 i++; 274 } 275 for (j = 0; isxdigit((unsigned char)buf[i]); i += 2, j++) { 276 hex_to_byteval(&buf[i], &key[j]); 277 } 278 keysize = j; 279 if (keysize != expected_keylen) { 280 fprintf(stderr, "Unexpected key length: %u vs. %u\n", 281 keysize, expected_keylen); 282 exit(1); 283 } 284 continue; 285 } 286 /* IV = ... */ 287 if (strncmp(buf, "IV", 2) == 0) { 288 i = 2; 289 while (isspace((unsigned char)buf[i]) || buf[i] == '=') { 290 i++; 291 } 292 for (j = 0; isxdigit((unsigned char)buf[i]); i += 2, j++) { 293 hex_to_byteval(&buf[i], &iv[j]); 294 } 295 ivsize = j; 296 if (ivsize != expected_ivlen) { 297 fprintf(stderr, "Unexpected IV length: %u vs. %u\n", 298 ivsize, expected_ivlen); 299 exit(1); 300 } 301 continue; 302 } 303 /* PT = ... */ 304 if (strncmp(buf, "PT", 2) == 0) { 305 i = 2; 306 while (isspace((unsigned char)buf[i]) || buf[i] == '=') { 307 i++; 308 } 309 for (j = 0; isxdigit((unsigned char)buf[i]); i += 2, j++) { 310 hex_to_byteval(&buf[i], &plaintext[j]); 311 } 312 plaintextlen = j; 313 if (plaintextlen != expected_ptlen) { 314 fprintf(stderr, "Unexpected PT length: %u vs. %u\n", 315 plaintextlen, expected_ptlen); 316 exit(1); 317 } 318 319 if (!is_encrypt) { 320 rv = aes_decrypt_buf(key, keysize, iv, ivsize, 321 output, &outputlen, sizeof output, 322 ciphertext, ciphertextlen, aad, aadlen, tag, tagsize); 323 if (rv != SECSuccess) { 324 fprintf(stderr, "aes_decrypt_buf failed\n"); 325 goto loser; 326 } 327 if (outputlen != plaintextlen) { 328 fprintf(stderr, "aes_decrypt_buf: wrong output size\n"); 329 goto loser; 330 } 331 if (memcmp(output, plaintext, plaintextlen) != 0) { 332 fprintf(stderr, "aes_decrypt_buf: wrong plaintext\n"); 333 goto loser; 334 } 335 } 336 continue; 337 } 338 /* FAIL */ 339 if (strncmp(buf, "FAIL", 4) == 0) { 340 plaintextlen = 0; 341 342 PORT_Assert(!is_encrypt); 343 rv = aes_decrypt_buf(key, keysize, iv, ivsize, 344 output, &outputlen, sizeof output, 345 ciphertext, ciphertextlen, aad, aadlen, tag, tagsize); 346 if (rv != SECFailure) { 347 fprintf(stderr, "aes_decrypt_buf succeeded unexpectedly\n"); 348 goto loser; 349 } 350 if (PORT_GetError() != SEC_ERROR_BAD_DATA) { 351 fprintf(stderr, "aes_decrypt_buf failed with incorrect " 352 "error code\n"); 353 goto loser; 354 } 355 continue; 356 } 357 /* AAD = ... */ 358 if (strncmp(buf, "AAD", 3) == 0) { 359 i = 3; 360 while (isspace((unsigned char)buf[i]) || buf[i] == '=') { 361 i++; 362 } 363 for (j = 0; isxdigit((unsigned char)buf[i]); i += 2, j++) { 364 hex_to_byteval(&buf[i], &aad[j]); 365 } 366 aadlen = j; 367 if (aadlen != expected_aadlen) { 368 fprintf(stderr, "Unexpected AAD length: %u vs. %u\n", 369 aadlen, expected_aadlen); 370 exit(1); 371 } 372 continue; 373 } 374 /* CT = ... */ 375 if (strncmp(buf, "CT", 2) == 0) { 376 i = 2; 377 while (isspace((unsigned char)buf[i]) || buf[i] == '=') { 378 i++; 379 } 380 for (j = 0; isxdigit((unsigned char)buf[i]); i += 2, j++) { 381 hex_to_byteval(&buf[i], &ciphertext[j]); 382 } 383 ciphertextlen = j; 384 if (ciphertextlen != expected_ptlen) { 385 fprintf(stderr, "Unexpected CT length: %u vs. %u\n", 386 ciphertextlen, expected_ptlen); 387 exit(1); 388 } 389 continue; 390 } 391 /* Tag = ... */ 392 if (strncmp(buf, "Tag", 3) == 0) { 393 i = 3; 394 while (isspace((unsigned char)buf[i]) || buf[i] == '=') { 395 i++; 396 } 397 for (j = 0; isxdigit((unsigned char)buf[i]); i += 2, j++) { 398 hex_to_byteval(&buf[i], &tag[j]); 399 } 400 tagsize = j; 401 if (tagsize != expected_taglen) { 402 fprintf(stderr, "Unexpected tag length: %u vs. %u\n", 403 tagsize, expected_taglen); 404 exit(1); 405 } 406 407 if (is_encrypt) { 408 rv = aes_encrypt_buf(key, keysize, iv, ivsize, 409 output, &outputlen, sizeof output, 410 plaintext, plaintextlen, aad, aadlen, tagsize); 411 if (rv != SECSuccess) { 412 fprintf(stderr, "aes_encrypt_buf failed\n"); 413 goto loser; 414 } 415 if (outputlen != plaintextlen + tagsize) { 416 fprintf(stderr, "aes_encrypt_buf: wrong output size\n"); 417 goto loser; 418 } 419 if (memcmp(output, ciphertext, plaintextlen) != 0) { 420 fprintf(stderr, "aes_encrypt_buf: wrong ciphertext\n"); 421 goto loser; 422 } 423 if (memcmp(output + plaintextlen, tag, tagsize) != 0) { 424 fprintf(stderr, "aes_encrypt_buf: wrong tag\n"); 425 goto loser; 426 } 427 } 428 continue; 429 } 430 } 431 /* Report num_tests for the last test group. */ 432 printf("%u tests\n", num_tests); 433 printf("%u test groups\n", test_group); 434 printf("PASS\n"); 435 loser: 436 fclose(aesresp); 437 } 438 439 int 440 main(int argc, char **argv) 441 { 442 if (argc < 2) { 443 return 1; 444 } 445 446 if (NSS_NoDB_Init(NULL) != SECSuccess) { 447 return 1; 448 } 449 450 /*************/ 451 /* AES */ 452 /*************/ 453 if (strcmp(argv[1], "aes") == 0) { 454 /* argv[2]=kat argv[3]=gcm argv[4]=<test name>.rsp */ 455 if (strcmp(argv[2], "kat") == 0) { 456 /* Known Answer Test (KAT) */ 457 aes_gcm_kat(argv[4]); 458 } 459 } 460 461 if (NSS_Shutdown() != SECSuccess) { 462 return 1; 463 } 464 return 0; 465 }