security/nss/cmd/pk11gcmtest/pk11gcmtest.c

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     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/. */
     5 #include <stdio.h>
     6 #include <stdlib.h>
     7 #include <ctype.h>
     9 #include "pk11pub.h"
    10 #include "secerr.h"
    11 #include "nss.h"
    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 }
    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_GCM_PARAMS gcm_params;
    49     SECItem param;
    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     }
    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;
    71     param.type = siBuffer;
    72     param.data = (unsigned char *) &gcm_params;
    73     param.len = sizeof(gcm_params);
    75     if (PK11_Encrypt(symKey, CKM_AES_GCM, &param,
    76 		     output, outputlen, maxoutputlen,
    77 		     input, inputlen) != SECSuccess) {
    78 	fprintf(stderr, "PK11_Encrypt failed\n");
    79 	goto loser;
    80     }
    82     rv = SECSuccess;
    84 loser:
    85     if (symKey != NULL) {
    86 	PK11_FreeSymKey(symKey);
    87     }
    88     return rv;
    89 }
    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_GCM_PARAMS gcm_params;
   106     SECItem param;
   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);
   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     }
   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;
   135     param.type = siBuffer;
   136     param.data = (unsigned char *) &gcm_params;
   137     param.len = sizeof(gcm_params);
   139     if (PK11_Decrypt(symKey, CKM_AES_GCM, &param,
   140 		     output, outputlen, maxoutputlen,
   141 		     concatenated, inputlen + tagsize) != SECSuccess) {
   142 	goto loser;
   143     }
   145     rv = SECSuccess;
   147 loser:
   148     if (symKey != NULL) {
   149 	PK11_FreeSymKey(symKey);
   150     }
   151     return rv;
   152 }
   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;
   170     PRBool is_encrypt;
   171     unsigned char key[32];              /* 128, 192, or 256 bits */
   172     unsigned int keysize;
   173     unsigned char iv[10*16];            /* 1 to 10 blocks */
   174     unsigned int ivsize;
   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;
   181     unsigned char tag[16];
   182     unsigned int tagsize;
   183     unsigned char output[10*16];         /* 1 to 10 blocks */
   184     unsigned int outputlen;
   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;
   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]);
   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: ", expected_keylen, expected_ivlen,
   232 		        expected_ptlen, expected_aadlen, expected_taglen);
   233 		/* Convert lengths in bits to lengths in bytes. */
   234 		PORT_Assert(expected_keylen % 8 == 0);
   235 		expected_keylen /= 8;
   236 		PORT_Assert(expected_ivlen % 8 == 0);
   237 		expected_ivlen /= 8;
   238 		PORT_Assert(expected_ptlen % 8 == 0);
   239 		expected_ptlen /= 8;
   240 		PORT_Assert(expected_aadlen % 8 == 0);
   241 		expected_aadlen /= 8;
   242 		PORT_Assert(expected_taglen % 8 == 0);
   243 		expected_taglen /= 8;
   244 	    } else {
   245 		fprintf(stderr, "Unexpected input line: %s\n", buf);
   246 		exit(1);
   247 	    }
   248 	    continue;
   249 	}
   250 	/* "Count = x" begins a new data set */
   251 	if (strncmp(buf, "Count", 5) == 0) {
   252 	    /* zeroize the variables for the test with this data set */
   253 	    memset(key, 0, sizeof key);
   254 	    keysize = 0;
   255 	    memset(iv, 0, sizeof iv);
   256 	    ivsize = 0;
   257 	    memset(plaintext, 0, sizeof plaintext);
   258 	    plaintextlen = 0;
   259 	    memset(aad, 0, sizeof aad);
   260 	    aadlen = 0;
   261 	    memset(ciphertext, 0, sizeof ciphertext);
   262 	    ciphertextlen = 0;
   263 	    memset(output, 0, sizeof output);
   264 	    outputlen = 0;
   265 	    num_tests++;
   266 	    continue;
   267 	}
   268 	/* Key = ... */
   269 	if (strncmp(buf, "Key", 3) == 0) {
   270 	    i = 3;
   271 	    while (isspace(buf[i]) || buf[i] == '=') {
   272 		i++;
   273 	    }
   274 	    for (j=0; isxdigit(buf[i]); i+=2,j++) {
   275 		hex_to_byteval(&buf[i], &key[j]);
   276 	    }
   277 	    keysize = j;
   278 	    if (keysize != expected_keylen) {
   279 		fprintf(stderr, "Unexpected key length: %u vs. %u\n",
   280 			keysize, expected_keylen);
   281 		exit(1);
   282 	    }
   283 	    continue;
   284 	}
   285 	/* IV = ... */
   286 	if (strncmp(buf, "IV", 2) == 0) {
   287 	    i = 2;
   288 	    while (isspace(buf[i]) || buf[i] == '=') {
   289 		i++;
   290 	    }
   291 	    for (j=0; isxdigit(buf[i]); i+=2,j++) {
   292 		hex_to_byteval(&buf[i], &iv[j]);
   293 	    }
   294 	    ivsize = j;
   295 	    if (ivsize != expected_ivlen) {
   296 		fprintf(stderr, "Unexpected IV length: %u vs. %u\n",
   297 			ivsize, expected_ivlen);
   298 		exit(1);
   299 	    }
   300 	    continue;
   301 	}
   302 	/* PT = ... */
   303 	if (strncmp(buf, "PT", 2) == 0) {
   304 	    i = 2;
   305 	    while (isspace(buf[i]) || buf[i] == '=') {
   306 		i++;
   307 	    }
   308 	    for (j=0; isxdigit(buf[i]); i+=2,j++) {
   309 		hex_to_byteval(&buf[i], &plaintext[j]);
   310 	    }
   311 	    plaintextlen = j;
   312 	    if (plaintextlen != expected_ptlen) {
   313 		fprintf(stderr, "Unexpected PT length: %u vs. %u\n",
   314 			plaintextlen, expected_ptlen);
   315 		exit(1);
   316 	    }
   318 	    if (!is_encrypt) {
   319 		rv = aes_decrypt_buf(key, keysize, iv, ivsize,
   320 		    output, &outputlen, sizeof output,
   321 		    ciphertext, ciphertextlen, aad, aadlen, tag, tagsize);
   322 		if (rv != SECSuccess) {
   323 		    fprintf(stderr, "aes_decrypt_buf failed\n");
   324 		    goto loser;
   325 		}
   326 		if (outputlen != plaintextlen) {
   327 		    fprintf(stderr, "aes_decrypt_buf: wrong output size\n");
   328 		    goto loser;
   329 		}
   330 		if (memcmp(output, plaintext, plaintextlen) != 0) {
   331 		    fprintf(stderr, "aes_decrypt_buf: wrong plaintext\n");
   332 		    goto loser;
   333 		}
   334 	    }
   335 	    continue;
   336 	}
   337 	/* FAIL */
   338 	if (strncmp(buf, "FAIL", 4) == 0) {
   339 	    plaintextlen = 0;
   341 	    PORT_Assert(!is_encrypt);
   342 	    rv = aes_decrypt_buf(key, keysize, iv, ivsize,
   343 		output, &outputlen, sizeof output,
   344 		ciphertext, ciphertextlen, aad, aadlen, tag, tagsize);
   345 	    if (rv != SECFailure) {
   346 		fprintf(stderr, "aes_decrypt_buf succeeded unexpectedly\n");
   347 		goto loser;
   348 	    }
   349 	    if (PORT_GetError() != SEC_ERROR_BAD_DATA) {
   350 		fprintf(stderr, "aes_decrypt_buf failed with incorrect "
   351 			"error code\n");
   352 		goto loser;
   353 	    }
   354 	    continue;
   355 	}
   356 	/* AAD = ... */
   357 	if (strncmp(buf, "AAD", 3) == 0) {
   358 	    i = 3;
   359 	    while (isspace(buf[i]) || buf[i] == '=') {
   360 		i++;
   361 	    }
   362 	    for (j=0; isxdigit(buf[i]); i+=2,j++) {
   363 		hex_to_byteval(&buf[i], &aad[j]);
   364 	    }
   365 	    aadlen = j;
   366 	    if (aadlen != expected_aadlen) {
   367 		fprintf(stderr, "Unexpected AAD length: %u vs. %u\n",
   368 			aadlen, expected_aadlen);
   369 		exit(1);
   370 	    }
   371 	    continue;
   372 	}
   373 	/* CT = ... */
   374 	if (strncmp(buf, "CT", 2) == 0) {
   375 	    i = 2;
   376 	    while (isspace(buf[i]) || buf[i] == '=') {
   377 		i++;
   378 	    }
   379 	    for (j=0; isxdigit(buf[i]); i+=2,j++) {
   380 		hex_to_byteval(&buf[i], &ciphertext[j]);
   381 	    }
   382 	    ciphertextlen = j;
   383 	    if (ciphertextlen != expected_ptlen) {
   384 		fprintf(stderr, "Unexpected CT length: %u vs. %u\n",
   385 			ciphertextlen, expected_ptlen);
   386 		exit(1);
   387 	    }
   388 	    continue;
   389 	}
   390 	/* Tag = ... */
   391 	if (strncmp(buf, "Tag", 3) == 0) {
   392 	    i = 3;
   393 	    while (isspace(buf[i]) || buf[i] == '=') {
   394 		i++;
   395 	    }
   396 	    for (j=0; isxdigit(buf[i]); i+=2,j++) {
   397 		hex_to_byteval(&buf[i], &tag[j]);
   398 	    }
   399 	    tagsize = j;
   400 	    if (tagsize != expected_taglen) {
   401 		fprintf(stderr, "Unexpected tag length: %u vs. %u\n",
   402 			tagsize, expected_taglen);
   403 		exit(1);
   404 	    }
   406 	    if (is_encrypt) {
   407 		rv = aes_encrypt_buf(key, keysize, iv, ivsize,
   408 		    output, &outputlen, sizeof output,
   409 		    plaintext, plaintextlen, aad, aadlen, tagsize);
   410 		if (rv != SECSuccess) {
   411 		    fprintf(stderr, "aes_encrypt_buf failed\n");
   412 		    goto loser;
   413 		}
   414 		if (outputlen != plaintextlen + tagsize) {
   415 		    fprintf(stderr, "aes_encrypt_buf: wrong output size\n");
   416 		    goto loser;
   417 		}
   418 		if (memcmp(output, ciphertext, plaintextlen) != 0) {
   419 		    fprintf(stderr, "aes_encrypt_buf: wrong ciphertext\n");
   420 		    goto loser;
   421 		}
   422 		if (memcmp(output + plaintextlen, tag, tagsize) != 0) {
   423 		    fprintf(stderr, "aes_encrypt_buf: wrong tag\n");
   424 		    goto loser;
   425 		}
   426 	    }
   427 	    continue;
   428 	}
   429     }
   430     /* Report num_tests for the last test group. */
   431     printf("%u tests\n", num_tests);
   432     printf("%u test groups\n", test_group);
   433     printf("PASS\n");
   434 loser:
   435     fclose(aesresp);
   436 }
   438 int main(int argc, char **argv)
   439 {
   440     if (argc < 2) exit(1);
   442     NSS_NoDB_Init(NULL);
   444     /*************/
   445     /*   AES     */
   446     /*************/
   447     if (strcmp(argv[1], "aes") == 0) {
   448 	/* argv[2]=kat argv[3]=gcm argv[4]=<test name>.rsp */
   449 	if (strcmp(argv[2], "kat") == 0) {
   450 	    /* Known Answer Test (KAT) */
   451 	    aes_gcm_kat(argv[4]);
   452 	}
   453     }
   455     NSS_Shutdown();
   456     return 0;
   457 }

mercurial