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
hex_to_byteval(const char * c2,unsigned char * byteval)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
aes_encrypt_buf(const unsigned char * key,unsigned int keysize,const unsigned char * iv,unsigned int ivsize,unsigned char * output,unsigned int * outputlen,unsigned int maxoutputlen,const unsigned char * input,unsigned int inputlen,const unsigned char * aad,unsigned int aadlen,unsigned int tagsize)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
aes_decrypt_buf(const unsigned char * key,unsigned int keysize,const unsigned char * iv,unsigned int ivsize,unsigned char * output,unsigned int * outputlen,unsigned int maxoutputlen,const unsigned char * input,unsigned int inputlen,const unsigned char * aad,unsigned int aadlen,const unsigned char * tag,unsigned int tagsize)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
aes_gcm_kat(const char * respfn)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(buf[i]) || buf[i] == '=') {
273 i++;
274 }
275 for (j = 0; isxdigit(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(buf[i]) || buf[i] == '=') {
290 i++;
291 }
292 for (j = 0; isxdigit(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(buf[i]) || buf[i] == '=') {
307 i++;
308 }
309 for (j = 0; isxdigit(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(buf[i]) || buf[i] == '=') {
361 i++;
362 }
363 for (j = 0; isxdigit(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(buf[i]) || buf[i] == '=') {
378 i++;
379 }
380 for (j = 0; isxdigit(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(buf[i]) || buf[i] == '=') {
395 i++;
396 }
397 for (j = 0; isxdigit(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
main(int argc,char ** argv)440 main(int argc, char **argv)
441 {
442 if (argc < 2)
443 exit(1);
444
445 NSS_NoDB_Init(NULL);
446
447 /*************/
448 /* AES */
449 /*************/
450 if (strcmp(argv[1], "aes") == 0) {
451 /* argv[2]=kat argv[3]=gcm argv[4]=<test name>.rsp */
452 if (strcmp(argv[2], "kat") == 0) {
453 /* Known Answer Test (KAT) */
454 aes_gcm_kat(argv[4]);
455 }
456 }
457
458 NSS_Shutdown();
459 return 0;
460 }
461