1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/nss/cmd/pk11gcmtest/pk11gcmtest.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,457 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +#include <stdio.h> 1.9 +#include <stdlib.h> 1.10 +#include <ctype.h> 1.11 + 1.12 +#include "pk11pub.h" 1.13 +#include "secerr.h" 1.14 +#include "nss.h" 1.15 + 1.16 +static SECStatus 1.17 +hex_to_byteval(const char *c2, unsigned char *byteval) 1.18 +{ 1.19 + int i; 1.20 + unsigned char offset; 1.21 + *byteval = 0; 1.22 + for (i=0; i<2; i++) { 1.23 + if (c2[i] >= '0' && c2[i] <= '9') { 1.24 + offset = c2[i] - '0'; 1.25 + *byteval |= offset << 4*(1-i); 1.26 + } else if (c2[i] >= 'a' && c2[i] <= 'f') { 1.27 + offset = c2[i] - 'a'; 1.28 + *byteval |= (offset + 10) << 4*(1-i); 1.29 + } else if (c2[i] >= 'A' && c2[i] <= 'F') { 1.30 + offset = c2[i] - 'A'; 1.31 + *byteval |= (offset + 10) << 4*(1-i); 1.32 + } else { 1.33 + return SECFailure; 1.34 + } 1.35 + } 1.36 + return SECSuccess; 1.37 +} 1.38 + 1.39 +static SECStatus 1.40 +aes_encrypt_buf( 1.41 + const unsigned char *key, unsigned int keysize, 1.42 + const unsigned char *iv, unsigned int ivsize, 1.43 + unsigned char *output, unsigned int *outputlen, unsigned int maxoutputlen, 1.44 + const unsigned char *input, unsigned int inputlen, 1.45 + const unsigned char *aad, unsigned int aadlen, unsigned int tagsize) 1.46 +{ 1.47 + SECStatus rv = SECFailure; 1.48 + SECItem key_item; 1.49 + PK11SlotInfo* slot = NULL; 1.50 + PK11SymKey *symKey = NULL; 1.51 + CK_GCM_PARAMS gcm_params; 1.52 + SECItem param; 1.53 + 1.54 + /* Import key into NSS. */ 1.55 + key_item.type = siBuffer; 1.56 + key_item.data = (unsigned char *) key; /* const cast */ 1.57 + key_item.len = keysize; 1.58 + slot = PK11_GetInternalSlot(); 1.59 + symKey = PK11_ImportSymKey(slot, CKM_AES_GCM, PK11_OriginUnwrap, 1.60 + CKA_ENCRYPT, &key_item, NULL); 1.61 + PK11_FreeSlot(slot); 1.62 + slot = NULL; 1.63 + if (!symKey) { 1.64 + fprintf(stderr, "PK11_ImportSymKey failed\n"); 1.65 + goto loser; 1.66 + } 1.67 + 1.68 + gcm_params.pIv = (unsigned char *) iv; /* const cast */ 1.69 + gcm_params.ulIvLen = ivsize; 1.70 + gcm_params.pAAD = (unsigned char *) aad; /* const cast */ 1.71 + gcm_params.ulAADLen = aadlen; 1.72 + gcm_params.ulTagBits = tagsize * 8; 1.73 + 1.74 + param.type = siBuffer; 1.75 + param.data = (unsigned char *) &gcm_params; 1.76 + param.len = sizeof(gcm_params); 1.77 + 1.78 + if (PK11_Encrypt(symKey, CKM_AES_GCM, ¶m, 1.79 + output, outputlen, maxoutputlen, 1.80 + input, inputlen) != SECSuccess) { 1.81 + fprintf(stderr, "PK11_Encrypt failed\n"); 1.82 + goto loser; 1.83 + } 1.84 + 1.85 + rv = SECSuccess; 1.86 + 1.87 +loser: 1.88 + if (symKey != NULL) { 1.89 + PK11_FreeSymKey(symKey); 1.90 + } 1.91 + return rv; 1.92 +} 1.93 + 1.94 +static SECStatus 1.95 +aes_decrypt_buf( 1.96 + const unsigned char *key, unsigned int keysize, 1.97 + const unsigned char *iv, unsigned int ivsize, 1.98 + unsigned char *output, unsigned int *outputlen, unsigned int maxoutputlen, 1.99 + const unsigned char *input, unsigned int inputlen, 1.100 + const unsigned char *aad, unsigned int aadlen, 1.101 + const unsigned char *tag, unsigned int tagsize) 1.102 +{ 1.103 + SECStatus rv = SECFailure; 1.104 + unsigned char concatenated[11*16]; /* 1 to 11 blocks */ 1.105 + SECItem key_item; 1.106 + PK11SlotInfo *slot = NULL; 1.107 + PK11SymKey *symKey = NULL; 1.108 + CK_GCM_PARAMS gcm_params; 1.109 + SECItem param; 1.110 + 1.111 + if (inputlen + tagsize > sizeof(concatenated)) { 1.112 + fprintf(stderr, "aes_decrypt_buf: local buffer too small\n"); 1.113 + goto loser; 1.114 + } 1.115 + memcpy(concatenated, input, inputlen); 1.116 + memcpy(concatenated + inputlen, tag, tagsize); 1.117 + 1.118 + /* Import key into NSS. */ 1.119 + key_item.type = siBuffer; 1.120 + key_item.data = (unsigned char *) key; /* const cast */ 1.121 + key_item.len = keysize; 1.122 + slot = PK11_GetInternalSlot(); 1.123 + symKey = PK11_ImportSymKey(slot, CKM_AES_GCM, PK11_OriginUnwrap, 1.124 + CKA_DECRYPT, &key_item, NULL); 1.125 + PK11_FreeSlot(slot); 1.126 + slot = NULL; 1.127 + if (!symKey) { 1.128 + fprintf(stderr, "PK11_ImportSymKey failed\n"); 1.129 + goto loser; 1.130 + } 1.131 + 1.132 + gcm_params.pIv = (unsigned char *) iv; 1.133 + gcm_params.ulIvLen = ivsize; 1.134 + gcm_params.pAAD = (unsigned char *) aad; 1.135 + gcm_params.ulAADLen = aadlen; 1.136 + gcm_params.ulTagBits = tagsize * 8; 1.137 + 1.138 + param.type = siBuffer; 1.139 + param.data = (unsigned char *) &gcm_params; 1.140 + param.len = sizeof(gcm_params); 1.141 + 1.142 + if (PK11_Decrypt(symKey, CKM_AES_GCM, ¶m, 1.143 + output, outputlen, maxoutputlen, 1.144 + concatenated, inputlen + tagsize) != SECSuccess) { 1.145 + goto loser; 1.146 + } 1.147 + 1.148 + rv = SECSuccess; 1.149 + 1.150 +loser: 1.151 + if (symKey != NULL) { 1.152 + PK11_FreeSymKey(symKey); 1.153 + } 1.154 + return rv; 1.155 +} 1.156 + 1.157 +/* 1.158 + * Perform the AES Known Answer Test (KAT) in Galois Counter Mode (GCM). 1.159 + * 1.160 + * respfn is the pathname of the RESPONSE file. 1.161 + */ 1.162 +static void 1.163 +aes_gcm_kat(const char *respfn) 1.164 +{ 1.165 + char buf[512]; /* holds one line from the input REQUEST file. 1.166 + * needs to be large enough to hold the longest 1.167 + * line "CIPHERTEXT = <320 hex digits>\n". 1.168 + */ 1.169 + FILE *aesresp; /* input stream from the RESPONSE file */ 1.170 + int i, j; 1.171 + unsigned int test_group = 0; 1.172 + unsigned int num_tests; 1.173 + PRBool is_encrypt; 1.174 + unsigned char key[32]; /* 128, 192, or 256 bits */ 1.175 + unsigned int keysize; 1.176 + unsigned char iv[10*16]; /* 1 to 10 blocks */ 1.177 + unsigned int ivsize; 1.178 + unsigned char plaintext[10*16]; /* 1 to 10 blocks */ 1.179 + unsigned int plaintextlen = 0; 1.180 + unsigned char aad[10*16]; /* 1 to 10 blocks */ 1.181 + unsigned int aadlen = 0; 1.182 + unsigned char ciphertext[10*16]; /* 1 to 10 blocks */ 1.183 + unsigned int ciphertextlen; 1.184 + unsigned char tag[16]; 1.185 + unsigned int tagsize; 1.186 + unsigned char output[10*16]; /* 1 to 10 blocks */ 1.187 + unsigned int outputlen; 1.188 + 1.189 + unsigned int expected_keylen = 0; 1.190 + unsigned int expected_ivlen = 0; 1.191 + unsigned int expected_ptlen = 0; 1.192 + unsigned int expected_aadlen = 0; 1.193 + unsigned int expected_taglen = 0; 1.194 + SECStatus rv; 1.195 + 1.196 + if (strstr(respfn, "Encrypt") != NULL) { 1.197 + is_encrypt = PR_TRUE; 1.198 + } else if (strstr(respfn, "Decrypt") != NULL) { 1.199 + is_encrypt = PR_FALSE; 1.200 + } else { 1.201 + fprintf(stderr, "Input file name must contain Encrypt or Decrypt\n"); 1.202 + exit(1); 1.203 + } 1.204 + aesresp = fopen(respfn, "r"); 1.205 + if (aesresp == NULL) { 1.206 + fprintf(stderr, "Cannot open input file %s\n", respfn); 1.207 + exit(1); 1.208 + } 1.209 + while (fgets(buf, sizeof buf, aesresp) != NULL) { 1.210 + /* a comment or blank line */ 1.211 + if (buf[0] == '#' || buf[0] == '\n') { 1.212 + continue; 1.213 + } 1.214 + /* [Keylen = ...], [IVlen = ...], etc. */ 1.215 + if (buf[0] == '[') { 1.216 + if (strncmp(&buf[1], "Keylen = ", 9) == 0) { 1.217 + expected_keylen = atoi(&buf[10]); 1.218 + } else if (strncmp(&buf[1], "IVlen = ", 8) == 0) { 1.219 + expected_ivlen = atoi(&buf[9]); 1.220 + } else if (strncmp(&buf[1], "PTlen = ", 8) == 0) { 1.221 + expected_ptlen = atoi(&buf[9]); 1.222 + } else if (strncmp(&buf[1], "AADlen = ", 9) == 0) { 1.223 + expected_aadlen = atoi(&buf[10]); 1.224 + } else if (strncmp(&buf[1], "Taglen = ", 9) == 0) { 1.225 + expected_taglen = atoi(&buf[10]); 1.226 + 1.227 + test_group++; 1.228 + if (test_group > 1) { 1.229 + /* Report num_tests for the previous test group. */ 1.230 + printf("%u tests\n", num_tests); 1.231 + } 1.232 + num_tests = 0; 1.233 + printf("Keylen = %u, IVlen = %u, PTlen = %u, AADlen = %u, " 1.234 + "Taglen = %u: ", expected_keylen, expected_ivlen, 1.235 + expected_ptlen, expected_aadlen, expected_taglen); 1.236 + /* Convert lengths in bits to lengths in bytes. */ 1.237 + PORT_Assert(expected_keylen % 8 == 0); 1.238 + expected_keylen /= 8; 1.239 + PORT_Assert(expected_ivlen % 8 == 0); 1.240 + expected_ivlen /= 8; 1.241 + PORT_Assert(expected_ptlen % 8 == 0); 1.242 + expected_ptlen /= 8; 1.243 + PORT_Assert(expected_aadlen % 8 == 0); 1.244 + expected_aadlen /= 8; 1.245 + PORT_Assert(expected_taglen % 8 == 0); 1.246 + expected_taglen /= 8; 1.247 + } else { 1.248 + fprintf(stderr, "Unexpected input line: %s\n", buf); 1.249 + exit(1); 1.250 + } 1.251 + continue; 1.252 + } 1.253 + /* "Count = x" begins a new data set */ 1.254 + if (strncmp(buf, "Count", 5) == 0) { 1.255 + /* zeroize the variables for the test with this data set */ 1.256 + memset(key, 0, sizeof key); 1.257 + keysize = 0; 1.258 + memset(iv, 0, sizeof iv); 1.259 + ivsize = 0; 1.260 + memset(plaintext, 0, sizeof plaintext); 1.261 + plaintextlen = 0; 1.262 + memset(aad, 0, sizeof aad); 1.263 + aadlen = 0; 1.264 + memset(ciphertext, 0, sizeof ciphertext); 1.265 + ciphertextlen = 0; 1.266 + memset(output, 0, sizeof output); 1.267 + outputlen = 0; 1.268 + num_tests++; 1.269 + continue; 1.270 + } 1.271 + /* Key = ... */ 1.272 + if (strncmp(buf, "Key", 3) == 0) { 1.273 + i = 3; 1.274 + while (isspace(buf[i]) || buf[i] == '=') { 1.275 + i++; 1.276 + } 1.277 + for (j=0; isxdigit(buf[i]); i+=2,j++) { 1.278 + hex_to_byteval(&buf[i], &key[j]); 1.279 + } 1.280 + keysize = j; 1.281 + if (keysize != expected_keylen) { 1.282 + fprintf(stderr, "Unexpected key length: %u vs. %u\n", 1.283 + keysize, expected_keylen); 1.284 + exit(1); 1.285 + } 1.286 + continue; 1.287 + } 1.288 + /* IV = ... */ 1.289 + if (strncmp(buf, "IV", 2) == 0) { 1.290 + i = 2; 1.291 + while (isspace(buf[i]) || buf[i] == '=') { 1.292 + i++; 1.293 + } 1.294 + for (j=0; isxdigit(buf[i]); i+=2,j++) { 1.295 + hex_to_byteval(&buf[i], &iv[j]); 1.296 + } 1.297 + ivsize = j; 1.298 + if (ivsize != expected_ivlen) { 1.299 + fprintf(stderr, "Unexpected IV length: %u vs. %u\n", 1.300 + ivsize, expected_ivlen); 1.301 + exit(1); 1.302 + } 1.303 + continue; 1.304 + } 1.305 + /* PT = ... */ 1.306 + if (strncmp(buf, "PT", 2) == 0) { 1.307 + i = 2; 1.308 + while (isspace(buf[i]) || buf[i] == '=') { 1.309 + i++; 1.310 + } 1.311 + for (j=0; isxdigit(buf[i]); i+=2,j++) { 1.312 + hex_to_byteval(&buf[i], &plaintext[j]); 1.313 + } 1.314 + plaintextlen = j; 1.315 + if (plaintextlen != expected_ptlen) { 1.316 + fprintf(stderr, "Unexpected PT length: %u vs. %u\n", 1.317 + plaintextlen, expected_ptlen); 1.318 + exit(1); 1.319 + } 1.320 + 1.321 + if (!is_encrypt) { 1.322 + rv = aes_decrypt_buf(key, keysize, iv, ivsize, 1.323 + output, &outputlen, sizeof output, 1.324 + ciphertext, ciphertextlen, aad, aadlen, tag, tagsize); 1.325 + if (rv != SECSuccess) { 1.326 + fprintf(stderr, "aes_decrypt_buf failed\n"); 1.327 + goto loser; 1.328 + } 1.329 + if (outputlen != plaintextlen) { 1.330 + fprintf(stderr, "aes_decrypt_buf: wrong output size\n"); 1.331 + goto loser; 1.332 + } 1.333 + if (memcmp(output, plaintext, plaintextlen) != 0) { 1.334 + fprintf(stderr, "aes_decrypt_buf: wrong plaintext\n"); 1.335 + goto loser; 1.336 + } 1.337 + } 1.338 + continue; 1.339 + } 1.340 + /* FAIL */ 1.341 + if (strncmp(buf, "FAIL", 4) == 0) { 1.342 + plaintextlen = 0; 1.343 + 1.344 + PORT_Assert(!is_encrypt); 1.345 + rv = aes_decrypt_buf(key, keysize, iv, ivsize, 1.346 + output, &outputlen, sizeof output, 1.347 + ciphertext, ciphertextlen, aad, aadlen, tag, tagsize); 1.348 + if (rv != SECFailure) { 1.349 + fprintf(stderr, "aes_decrypt_buf succeeded unexpectedly\n"); 1.350 + goto loser; 1.351 + } 1.352 + if (PORT_GetError() != SEC_ERROR_BAD_DATA) { 1.353 + fprintf(stderr, "aes_decrypt_buf failed with incorrect " 1.354 + "error code\n"); 1.355 + goto loser; 1.356 + } 1.357 + continue; 1.358 + } 1.359 + /* AAD = ... */ 1.360 + if (strncmp(buf, "AAD", 3) == 0) { 1.361 + i = 3; 1.362 + while (isspace(buf[i]) || buf[i] == '=') { 1.363 + i++; 1.364 + } 1.365 + for (j=0; isxdigit(buf[i]); i+=2,j++) { 1.366 + hex_to_byteval(&buf[i], &aad[j]); 1.367 + } 1.368 + aadlen = j; 1.369 + if (aadlen != expected_aadlen) { 1.370 + fprintf(stderr, "Unexpected AAD length: %u vs. %u\n", 1.371 + aadlen, expected_aadlen); 1.372 + exit(1); 1.373 + } 1.374 + continue; 1.375 + } 1.376 + /* CT = ... */ 1.377 + if (strncmp(buf, "CT", 2) == 0) { 1.378 + i = 2; 1.379 + while (isspace(buf[i]) || buf[i] == '=') { 1.380 + i++; 1.381 + } 1.382 + for (j=0; isxdigit(buf[i]); i+=2,j++) { 1.383 + hex_to_byteval(&buf[i], &ciphertext[j]); 1.384 + } 1.385 + ciphertextlen = j; 1.386 + if (ciphertextlen != expected_ptlen) { 1.387 + fprintf(stderr, "Unexpected CT length: %u vs. %u\n", 1.388 + ciphertextlen, expected_ptlen); 1.389 + exit(1); 1.390 + } 1.391 + continue; 1.392 + } 1.393 + /* Tag = ... */ 1.394 + if (strncmp(buf, "Tag", 3) == 0) { 1.395 + i = 3; 1.396 + while (isspace(buf[i]) || buf[i] == '=') { 1.397 + i++; 1.398 + } 1.399 + for (j=0; isxdigit(buf[i]); i+=2,j++) { 1.400 + hex_to_byteval(&buf[i], &tag[j]); 1.401 + } 1.402 + tagsize = j; 1.403 + if (tagsize != expected_taglen) { 1.404 + fprintf(stderr, "Unexpected tag length: %u vs. %u\n", 1.405 + tagsize, expected_taglen); 1.406 + exit(1); 1.407 + } 1.408 + 1.409 + if (is_encrypt) { 1.410 + rv = aes_encrypt_buf(key, keysize, iv, ivsize, 1.411 + output, &outputlen, sizeof output, 1.412 + plaintext, plaintextlen, aad, aadlen, tagsize); 1.413 + if (rv != SECSuccess) { 1.414 + fprintf(stderr, "aes_encrypt_buf failed\n"); 1.415 + goto loser; 1.416 + } 1.417 + if (outputlen != plaintextlen + tagsize) { 1.418 + fprintf(stderr, "aes_encrypt_buf: wrong output size\n"); 1.419 + goto loser; 1.420 + } 1.421 + if (memcmp(output, ciphertext, plaintextlen) != 0) { 1.422 + fprintf(stderr, "aes_encrypt_buf: wrong ciphertext\n"); 1.423 + goto loser; 1.424 + } 1.425 + if (memcmp(output + plaintextlen, tag, tagsize) != 0) { 1.426 + fprintf(stderr, "aes_encrypt_buf: wrong tag\n"); 1.427 + goto loser; 1.428 + } 1.429 + } 1.430 + continue; 1.431 + } 1.432 + } 1.433 + /* Report num_tests for the last test group. */ 1.434 + printf("%u tests\n", num_tests); 1.435 + printf("%u test groups\n", test_group); 1.436 + printf("PASS\n"); 1.437 +loser: 1.438 + fclose(aesresp); 1.439 +} 1.440 + 1.441 +int main(int argc, char **argv) 1.442 +{ 1.443 + if (argc < 2) exit(1); 1.444 + 1.445 + NSS_NoDB_Init(NULL); 1.446 + 1.447 + /*************/ 1.448 + /* AES */ 1.449 + /*************/ 1.450 + if (strcmp(argv[1], "aes") == 0) { 1.451 + /* argv[2]=kat argv[3]=gcm argv[4]=<test name>.rsp */ 1.452 + if (strcmp(argv[2], "kat") == 0) { 1.453 + /* Known Answer Test (KAT) */ 1.454 + aes_gcm_kat(argv[4]); 1.455 + } 1.456 + } 1.457 + 1.458 + NSS_Shutdown(); 1.459 + return 0; 1.460 +}