Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
michael@0 | 1 | /* This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 4 | |
michael@0 | 5 | #include <stdio.h> |
michael@0 | 6 | #include <stdlib.h> |
michael@0 | 7 | #include <ctype.h> |
michael@0 | 8 | |
michael@0 | 9 | #include "secitem.h" |
michael@0 | 10 | #include "blapi.h" |
michael@0 | 11 | #include "nssutil.h" |
michael@0 | 12 | #include "secerr.h" |
michael@0 | 13 | #include "secder.h" |
michael@0 | 14 | #include "secdig.h" |
michael@0 | 15 | #include "secoid.h" |
michael@0 | 16 | #include "ec.h" |
michael@0 | 17 | #include "hasht.h" |
michael@0 | 18 | #include "lowkeyi.h" |
michael@0 | 19 | #include "softoken.h" |
michael@0 | 20 | |
michael@0 | 21 | #if 0 |
michael@0 | 22 | #include "../../lib/freebl/mpi/mpi.h" |
michael@0 | 23 | #endif |
michael@0 | 24 | |
michael@0 | 25 | #ifndef NSS_DISABLE_ECC |
michael@0 | 26 | extern SECStatus |
michael@0 | 27 | EC_DecodeParams(const SECItem *encodedParams, ECParams **ecparams); |
michael@0 | 28 | extern SECStatus |
michael@0 | 29 | EC_CopyParams(PLArenaPool *arena, ECParams *dstParams, |
michael@0 | 30 | const ECParams *srcParams); |
michael@0 | 31 | #endif |
michael@0 | 32 | |
michael@0 | 33 | #define ENCRYPT 1 |
michael@0 | 34 | #define DECRYPT 0 |
michael@0 | 35 | #define BYTE unsigned char |
michael@0 | 36 | #define DEFAULT_RSA_PUBLIC_EXPONENT 0x10001 |
michael@0 | 37 | #define RSA_MAX_TEST_MODULUS_BITS 4096 |
michael@0 | 38 | #define RSA_MAX_TEST_MODULUS_BYTES RSA_MAX_TEST_MODULUS_BITS/8 |
michael@0 | 39 | #define RSA_MAX_TEST_EXPONENT_BYTES 8 |
michael@0 | 40 | #define PQG_TEST_SEED_BYTES 20 |
michael@0 | 41 | |
michael@0 | 42 | SECStatus |
michael@0 | 43 | hex_to_byteval(const char *c2, unsigned char *byteval) |
michael@0 | 44 | { |
michael@0 | 45 | int i; |
michael@0 | 46 | unsigned char offset; |
michael@0 | 47 | *byteval = 0; |
michael@0 | 48 | for (i=0; i<2; i++) { |
michael@0 | 49 | if (c2[i] >= '0' && c2[i] <= '9') { |
michael@0 | 50 | offset = c2[i] - '0'; |
michael@0 | 51 | *byteval |= offset << 4*(1-i); |
michael@0 | 52 | } else if (c2[i] >= 'a' && c2[i] <= 'f') { |
michael@0 | 53 | offset = c2[i] - 'a'; |
michael@0 | 54 | *byteval |= (offset + 10) << 4*(1-i); |
michael@0 | 55 | } else if (c2[i] >= 'A' && c2[i] <= 'F') { |
michael@0 | 56 | offset = c2[i] - 'A'; |
michael@0 | 57 | *byteval |= (offset + 10) << 4*(1-i); |
michael@0 | 58 | } else { |
michael@0 | 59 | return SECFailure; |
michael@0 | 60 | } |
michael@0 | 61 | } |
michael@0 | 62 | return SECSuccess; |
michael@0 | 63 | } |
michael@0 | 64 | |
michael@0 | 65 | SECStatus |
michael@0 | 66 | byteval_to_hex(unsigned char byteval, char *c2, char a) |
michael@0 | 67 | { |
michael@0 | 68 | int i; |
michael@0 | 69 | unsigned char offset; |
michael@0 | 70 | for (i=0; i<2; i++) { |
michael@0 | 71 | offset = (byteval >> 4*(1-i)) & 0x0f; |
michael@0 | 72 | if (offset < 10) { |
michael@0 | 73 | c2[i] = '0' + offset; |
michael@0 | 74 | } else { |
michael@0 | 75 | c2[i] = a + offset - 10; |
michael@0 | 76 | } |
michael@0 | 77 | } |
michael@0 | 78 | return SECSuccess; |
michael@0 | 79 | } |
michael@0 | 80 | |
michael@0 | 81 | void |
michael@0 | 82 | to_hex_str(char *str, const unsigned char *buf, unsigned int len) |
michael@0 | 83 | { |
michael@0 | 84 | unsigned int i; |
michael@0 | 85 | for (i=0; i<len; i++) { |
michael@0 | 86 | byteval_to_hex(buf[i], &str[2*i], 'a'); |
michael@0 | 87 | } |
michael@0 | 88 | str[2*len] = '\0'; |
michael@0 | 89 | } |
michael@0 | 90 | |
michael@0 | 91 | void |
michael@0 | 92 | to_hex_str_cap(char *str, const unsigned char *buf, unsigned int len) |
michael@0 | 93 | { |
michael@0 | 94 | unsigned int i; |
michael@0 | 95 | for (i=0; i<len; i++) { |
michael@0 | 96 | byteval_to_hex(buf[i], &str[2*i], 'A'); |
michael@0 | 97 | } |
michael@0 | 98 | str[2*len] = '\0'; |
michael@0 | 99 | } |
michael@0 | 100 | |
michael@0 | 101 | /* |
michael@0 | 102 | * Convert a string of hex digits (str) to an array (buf) of len bytes. |
michael@0 | 103 | * Return PR_TRUE if the hex string can fit in the byte array. Return |
michael@0 | 104 | * PR_FALSE if the hex string is empty or is too long. |
michael@0 | 105 | */ |
michael@0 | 106 | PRBool |
michael@0 | 107 | from_hex_str(unsigned char *buf, unsigned int len, const char *str) |
michael@0 | 108 | { |
michael@0 | 109 | unsigned int nxdigit; /* number of hex digits in str */ |
michael@0 | 110 | unsigned int i; /* index into buf */ |
michael@0 | 111 | unsigned int j; /* index into str */ |
michael@0 | 112 | |
michael@0 | 113 | /* count the hex digits */ |
michael@0 | 114 | nxdigit = 0; |
michael@0 | 115 | for (nxdigit = 0; isxdigit(str[nxdigit]); nxdigit++) { |
michael@0 | 116 | /* empty body */ |
michael@0 | 117 | } |
michael@0 | 118 | if (nxdigit == 0) { |
michael@0 | 119 | return PR_FALSE; |
michael@0 | 120 | } |
michael@0 | 121 | if (nxdigit > 2*len) { |
michael@0 | 122 | /* |
michael@0 | 123 | * The input hex string is too long, but we allow it if the |
michael@0 | 124 | * extra digits are leading 0's. |
michael@0 | 125 | */ |
michael@0 | 126 | for (j = 0; j < nxdigit-2*len; j++) { |
michael@0 | 127 | if (str[j] != '0') { |
michael@0 | 128 | return PR_FALSE; |
michael@0 | 129 | } |
michael@0 | 130 | } |
michael@0 | 131 | /* skip leading 0's */ |
michael@0 | 132 | str += nxdigit-2*len; |
michael@0 | 133 | nxdigit = 2*len; |
michael@0 | 134 | } |
michael@0 | 135 | for (i=0, j=0; i< len; i++) { |
michael@0 | 136 | if (2*i < 2*len-nxdigit) { |
michael@0 | 137 | /* Handle a short input as if we padded it with leading 0's. */ |
michael@0 | 138 | if (2*i+1 < 2*len-nxdigit) { |
michael@0 | 139 | buf[i] = 0; |
michael@0 | 140 | } else { |
michael@0 | 141 | char tmp[2]; |
michael@0 | 142 | tmp[0] = '0'; |
michael@0 | 143 | tmp[1] = str[j]; |
michael@0 | 144 | hex_to_byteval(tmp, &buf[i]); |
michael@0 | 145 | j++; |
michael@0 | 146 | } |
michael@0 | 147 | } else { |
michael@0 | 148 | hex_to_byteval(&str[j], &buf[i]); |
michael@0 | 149 | j += 2; |
michael@0 | 150 | } |
michael@0 | 151 | } |
michael@0 | 152 | return PR_TRUE; |
michael@0 | 153 | } |
michael@0 | 154 | |
michael@0 | 155 | SECStatus |
michael@0 | 156 | tdea_encrypt_buf( |
michael@0 | 157 | int mode, |
michael@0 | 158 | const unsigned char *key, |
michael@0 | 159 | const unsigned char *iv, |
michael@0 | 160 | unsigned char *output, unsigned int *outputlen, unsigned int maxoutputlen, |
michael@0 | 161 | const unsigned char *input, unsigned int inputlen) |
michael@0 | 162 | { |
michael@0 | 163 | SECStatus rv = SECFailure; |
michael@0 | 164 | DESContext *cx; |
michael@0 | 165 | unsigned char doublecheck[8*20]; /* 1 to 20 blocks */ |
michael@0 | 166 | unsigned int doublechecklen = 0; |
michael@0 | 167 | |
michael@0 | 168 | cx = DES_CreateContext(key, iv, mode, PR_TRUE); |
michael@0 | 169 | if (cx == NULL) { |
michael@0 | 170 | goto loser; |
michael@0 | 171 | } |
michael@0 | 172 | rv = DES_Encrypt(cx, output, outputlen, maxoutputlen, input, inputlen); |
michael@0 | 173 | if (rv != SECSuccess) { |
michael@0 | 174 | goto loser; |
michael@0 | 175 | } |
michael@0 | 176 | if (*outputlen != inputlen) { |
michael@0 | 177 | goto loser; |
michael@0 | 178 | } |
michael@0 | 179 | DES_DestroyContext(cx, PR_TRUE); |
michael@0 | 180 | cx = NULL; |
michael@0 | 181 | |
michael@0 | 182 | /* |
michael@0 | 183 | * Doublecheck our result by decrypting the ciphertext and |
michael@0 | 184 | * compare the output with the input plaintext. |
michael@0 | 185 | */ |
michael@0 | 186 | cx = DES_CreateContext(key, iv, mode, PR_FALSE); |
michael@0 | 187 | if (cx == NULL) { |
michael@0 | 188 | goto loser; |
michael@0 | 189 | } |
michael@0 | 190 | rv = DES_Decrypt(cx, doublecheck, &doublechecklen, sizeof doublecheck, |
michael@0 | 191 | output, *outputlen); |
michael@0 | 192 | if (rv != SECSuccess) { |
michael@0 | 193 | goto loser; |
michael@0 | 194 | } |
michael@0 | 195 | if (doublechecklen != *outputlen) { |
michael@0 | 196 | goto loser; |
michael@0 | 197 | } |
michael@0 | 198 | DES_DestroyContext(cx, PR_TRUE); |
michael@0 | 199 | cx = NULL; |
michael@0 | 200 | if (memcmp(doublecheck, input, inputlen) != 0) { |
michael@0 | 201 | goto loser; |
michael@0 | 202 | } |
michael@0 | 203 | rv = SECSuccess; |
michael@0 | 204 | |
michael@0 | 205 | loser: |
michael@0 | 206 | if (cx != NULL) { |
michael@0 | 207 | DES_DestroyContext(cx, PR_TRUE); |
michael@0 | 208 | } |
michael@0 | 209 | return rv; |
michael@0 | 210 | } |
michael@0 | 211 | |
michael@0 | 212 | SECStatus |
michael@0 | 213 | tdea_decrypt_buf( |
michael@0 | 214 | int mode, |
michael@0 | 215 | const unsigned char *key, |
michael@0 | 216 | const unsigned char *iv, |
michael@0 | 217 | unsigned char *output, unsigned int *outputlen, unsigned int maxoutputlen, |
michael@0 | 218 | const unsigned char *input, unsigned int inputlen) |
michael@0 | 219 | { |
michael@0 | 220 | SECStatus rv = SECFailure; |
michael@0 | 221 | DESContext *cx; |
michael@0 | 222 | unsigned char doublecheck[8*20]; /* 1 to 20 blocks */ |
michael@0 | 223 | unsigned int doublechecklen = 0; |
michael@0 | 224 | |
michael@0 | 225 | cx = DES_CreateContext(key, iv, mode, PR_FALSE); |
michael@0 | 226 | if (cx == NULL) { |
michael@0 | 227 | goto loser; |
michael@0 | 228 | } |
michael@0 | 229 | rv = DES_Decrypt(cx, output, outputlen, maxoutputlen, |
michael@0 | 230 | input, inputlen); |
michael@0 | 231 | if (rv != SECSuccess) { |
michael@0 | 232 | goto loser; |
michael@0 | 233 | } |
michael@0 | 234 | if (*outputlen != inputlen) { |
michael@0 | 235 | goto loser; |
michael@0 | 236 | } |
michael@0 | 237 | DES_DestroyContext(cx, PR_TRUE); |
michael@0 | 238 | cx = NULL; |
michael@0 | 239 | |
michael@0 | 240 | /* |
michael@0 | 241 | * Doublecheck our result by encrypting the plaintext and |
michael@0 | 242 | * compare the output with the input ciphertext. |
michael@0 | 243 | */ |
michael@0 | 244 | cx = DES_CreateContext(key, iv, mode, PR_TRUE); |
michael@0 | 245 | if (cx == NULL) { |
michael@0 | 246 | goto loser; |
michael@0 | 247 | } |
michael@0 | 248 | rv = DES_Encrypt(cx, doublecheck, &doublechecklen, sizeof doublecheck, |
michael@0 | 249 | output, *outputlen); |
michael@0 | 250 | if (rv != SECSuccess) { |
michael@0 | 251 | goto loser; |
michael@0 | 252 | } |
michael@0 | 253 | if (doublechecklen != *outputlen) { |
michael@0 | 254 | goto loser; |
michael@0 | 255 | } |
michael@0 | 256 | DES_DestroyContext(cx, PR_TRUE); |
michael@0 | 257 | cx = NULL; |
michael@0 | 258 | if (memcmp(doublecheck, input, inputlen) != 0) { |
michael@0 | 259 | goto loser; |
michael@0 | 260 | } |
michael@0 | 261 | rv = SECSuccess; |
michael@0 | 262 | |
michael@0 | 263 | loser: |
michael@0 | 264 | if (cx != NULL) { |
michael@0 | 265 | DES_DestroyContext(cx, PR_TRUE); |
michael@0 | 266 | } |
michael@0 | 267 | return rv; |
michael@0 | 268 | } |
michael@0 | 269 | |
michael@0 | 270 | /* |
michael@0 | 271 | * Perform the TDEA Known Answer Test (KAT) or Multi-block Message |
michael@0 | 272 | * Test (MMT) in ECB or CBC mode. The KAT (there are five types) |
michael@0 | 273 | * and MMT have the same structure: given the key and IV (CBC mode |
michael@0 | 274 | * only), encrypt the given plaintext or decrypt the given ciphertext. |
michael@0 | 275 | * So we can handle them the same way. |
michael@0 | 276 | * |
michael@0 | 277 | * reqfn is the pathname of the REQUEST file. |
michael@0 | 278 | * |
michael@0 | 279 | * The output RESPONSE file is written to stdout. |
michael@0 | 280 | */ |
michael@0 | 281 | void |
michael@0 | 282 | tdea_kat_mmt(char *reqfn) |
michael@0 | 283 | { |
michael@0 | 284 | char buf[180]; /* holds one line from the input REQUEST file. |
michael@0 | 285 | * needs to be large enough to hold the longest |
michael@0 | 286 | * line "CIPHERTEXT = <180 hex digits>\n". |
michael@0 | 287 | */ |
michael@0 | 288 | FILE *req; /* input stream from the REQUEST file */ |
michael@0 | 289 | FILE *resp; /* output stream to the RESPONSE file */ |
michael@0 | 290 | int i, j; |
michael@0 | 291 | int mode; /* NSS_DES_EDE3 (ECB) or NSS_DES_EDE3_CBC */ |
michael@0 | 292 | int crypt = DECRYPT; /* 1 means encrypt, 0 means decrypt */ |
michael@0 | 293 | unsigned char key[24]; /* TDEA 3 key bundle */ |
michael@0 | 294 | unsigned int numKeys = 0; |
michael@0 | 295 | unsigned char iv[8]; /* for all modes except ECB */ |
michael@0 | 296 | unsigned char plaintext[8*20]; /* 1 to 20 blocks */ |
michael@0 | 297 | unsigned int plaintextlen; |
michael@0 | 298 | unsigned char ciphertext[8*20]; /* 1 to 20 blocks */ |
michael@0 | 299 | unsigned int ciphertextlen; |
michael@0 | 300 | SECStatus rv; |
michael@0 | 301 | |
michael@0 | 302 | req = fopen(reqfn, "r"); |
michael@0 | 303 | resp = stdout; |
michael@0 | 304 | while (fgets(buf, sizeof buf, req) != NULL) { |
michael@0 | 305 | /* a comment or blank line */ |
michael@0 | 306 | if (buf[0] == '#' || buf[0] == '\n') { |
michael@0 | 307 | fputs(buf, resp); |
michael@0 | 308 | continue; |
michael@0 | 309 | } |
michael@0 | 310 | /* [ENCRYPT] or [DECRYPT] */ |
michael@0 | 311 | if (buf[0] == '[') { |
michael@0 | 312 | if (strncmp(&buf[1], "ENCRYPT", 7) == 0) { |
michael@0 | 313 | crypt = ENCRYPT; |
michael@0 | 314 | } else { |
michael@0 | 315 | crypt = DECRYPT; |
michael@0 | 316 | } |
michael@0 | 317 | fputs(buf, resp); |
michael@0 | 318 | continue; |
michael@0 | 319 | } |
michael@0 | 320 | /* NumKeys */ |
michael@0 | 321 | if (strncmp(&buf[0], "NumKeys", 7) == 0) { |
michael@0 | 322 | i = 7; |
michael@0 | 323 | while (isspace(buf[i]) || buf[i] == '=') { |
michael@0 | 324 | i++; |
michael@0 | 325 | } |
michael@0 | 326 | numKeys = buf[i]; |
michael@0 | 327 | fputs(buf, resp); |
michael@0 | 328 | continue; |
michael@0 | 329 | } |
michael@0 | 330 | /* "COUNT = x" begins a new data set */ |
michael@0 | 331 | if (strncmp(buf, "COUNT", 5) == 0) { |
michael@0 | 332 | /* mode defaults to ECB, if dataset has IV mode will be set CBC */ |
michael@0 | 333 | mode = NSS_DES_EDE3; |
michael@0 | 334 | /* zeroize the variables for the test with this data set */ |
michael@0 | 335 | memset(key, 0, sizeof key); |
michael@0 | 336 | memset(iv, 0, sizeof iv); |
michael@0 | 337 | memset(plaintext, 0, sizeof plaintext); |
michael@0 | 338 | plaintextlen = 0; |
michael@0 | 339 | memset(ciphertext, 0, sizeof ciphertext); |
michael@0 | 340 | ciphertextlen = 0; |
michael@0 | 341 | fputs(buf, resp); |
michael@0 | 342 | continue; |
michael@0 | 343 | } |
michael@0 | 344 | if (numKeys == 0) { |
michael@0 | 345 | if (strncmp(buf, "KEYs", 4) == 0) { |
michael@0 | 346 | i = 4; |
michael@0 | 347 | while (isspace(buf[i]) || buf[i] == '=') { |
michael@0 | 348 | i++; |
michael@0 | 349 | } |
michael@0 | 350 | for (j=0; isxdigit(buf[i]); i+=2,j++) { |
michael@0 | 351 | hex_to_byteval(&buf[i], &key[j]); |
michael@0 | 352 | key[j+8] = key[j]; |
michael@0 | 353 | key[j+16] = key[j]; |
michael@0 | 354 | } |
michael@0 | 355 | fputs(buf, resp); |
michael@0 | 356 | continue; |
michael@0 | 357 | } |
michael@0 | 358 | } else { |
michael@0 | 359 | /* KEY1 = ... */ |
michael@0 | 360 | if (strncmp(buf, "KEY1", 4) == 0) { |
michael@0 | 361 | i = 4; |
michael@0 | 362 | while (isspace(buf[i]) || buf[i] == '=') { |
michael@0 | 363 | i++; |
michael@0 | 364 | } |
michael@0 | 365 | for (j=0; isxdigit(buf[i]); i+=2,j++) { |
michael@0 | 366 | hex_to_byteval(&buf[i], &key[j]); |
michael@0 | 367 | } |
michael@0 | 368 | fputs(buf, resp); |
michael@0 | 369 | continue; |
michael@0 | 370 | } |
michael@0 | 371 | /* KEY2 = ... */ |
michael@0 | 372 | if (strncmp(buf, "KEY2", 4) == 0) { |
michael@0 | 373 | i = 4; |
michael@0 | 374 | while (isspace(buf[i]) || buf[i] == '=') { |
michael@0 | 375 | i++; |
michael@0 | 376 | } |
michael@0 | 377 | for (j=8; isxdigit(buf[i]); i+=2,j++) { |
michael@0 | 378 | hex_to_byteval(&buf[i], &key[j]); |
michael@0 | 379 | } |
michael@0 | 380 | fputs(buf, resp); |
michael@0 | 381 | continue; |
michael@0 | 382 | } |
michael@0 | 383 | /* KEY3 = ... */ |
michael@0 | 384 | if (strncmp(buf, "KEY3", 4) == 0) { |
michael@0 | 385 | i = 4; |
michael@0 | 386 | while (isspace(buf[i]) || buf[i] == '=') { |
michael@0 | 387 | i++; |
michael@0 | 388 | } |
michael@0 | 389 | for (j=16; isxdigit(buf[i]); i+=2,j++) { |
michael@0 | 390 | hex_to_byteval(&buf[i], &key[j]); |
michael@0 | 391 | } |
michael@0 | 392 | fputs(buf, resp); |
michael@0 | 393 | continue; |
michael@0 | 394 | } |
michael@0 | 395 | } |
michael@0 | 396 | |
michael@0 | 397 | /* IV = ... */ |
michael@0 | 398 | if (strncmp(buf, "IV", 2) == 0) { |
michael@0 | 399 | mode = NSS_DES_EDE3_CBC; |
michael@0 | 400 | i = 2; |
michael@0 | 401 | while (isspace(buf[i]) || buf[i] == '=') { |
michael@0 | 402 | i++; |
michael@0 | 403 | } |
michael@0 | 404 | for (j=0; j<sizeof iv; i+=2,j++) { |
michael@0 | 405 | hex_to_byteval(&buf[i], &iv[j]); |
michael@0 | 406 | } |
michael@0 | 407 | fputs(buf, resp); |
michael@0 | 408 | continue; |
michael@0 | 409 | } |
michael@0 | 410 | |
michael@0 | 411 | /* PLAINTEXT = ... */ |
michael@0 | 412 | if (strncmp(buf, "PLAINTEXT", 9) == 0) { |
michael@0 | 413 | /* sanity check */ |
michael@0 | 414 | if (crypt != ENCRYPT) { |
michael@0 | 415 | goto loser; |
michael@0 | 416 | } |
michael@0 | 417 | i = 9; |
michael@0 | 418 | while (isspace(buf[i]) || buf[i] == '=') { |
michael@0 | 419 | i++; |
michael@0 | 420 | } |
michael@0 | 421 | for (j=0; isxdigit(buf[i]); i+=2,j++) { |
michael@0 | 422 | hex_to_byteval(&buf[i], &plaintext[j]); |
michael@0 | 423 | } |
michael@0 | 424 | plaintextlen = j; |
michael@0 | 425 | rv = tdea_encrypt_buf(mode, key, |
michael@0 | 426 | (mode == NSS_DES_EDE3) ? NULL : iv, |
michael@0 | 427 | ciphertext, &ciphertextlen, sizeof ciphertext, |
michael@0 | 428 | plaintext, plaintextlen); |
michael@0 | 429 | if (rv != SECSuccess) { |
michael@0 | 430 | goto loser; |
michael@0 | 431 | } |
michael@0 | 432 | |
michael@0 | 433 | fputs(buf, resp); |
michael@0 | 434 | fputs("CIPHERTEXT = ", resp); |
michael@0 | 435 | to_hex_str(buf, ciphertext, ciphertextlen); |
michael@0 | 436 | fputs(buf, resp); |
michael@0 | 437 | fputc('\n', resp); |
michael@0 | 438 | continue; |
michael@0 | 439 | } |
michael@0 | 440 | /* CIPHERTEXT = ... */ |
michael@0 | 441 | if (strncmp(buf, "CIPHERTEXT", 10) == 0) { |
michael@0 | 442 | /* sanity check */ |
michael@0 | 443 | if (crypt != DECRYPT) { |
michael@0 | 444 | goto loser; |
michael@0 | 445 | } |
michael@0 | 446 | |
michael@0 | 447 | i = 10; |
michael@0 | 448 | while (isspace(buf[i]) || buf[i] == '=') { |
michael@0 | 449 | i++; |
michael@0 | 450 | } |
michael@0 | 451 | for (j=0; isxdigit(buf[i]); i+=2,j++) { |
michael@0 | 452 | hex_to_byteval(&buf[i], &ciphertext[j]); |
michael@0 | 453 | } |
michael@0 | 454 | ciphertextlen = j; |
michael@0 | 455 | |
michael@0 | 456 | rv = tdea_decrypt_buf(mode, key, |
michael@0 | 457 | (mode == NSS_DES_EDE3) ? NULL : iv, |
michael@0 | 458 | plaintext, &plaintextlen, sizeof plaintext, |
michael@0 | 459 | ciphertext, ciphertextlen); |
michael@0 | 460 | if (rv != SECSuccess) { |
michael@0 | 461 | goto loser; |
michael@0 | 462 | } |
michael@0 | 463 | |
michael@0 | 464 | fputs(buf, resp); |
michael@0 | 465 | fputs("PLAINTEXT = ", resp); |
michael@0 | 466 | to_hex_str(buf, plaintext, plaintextlen); |
michael@0 | 467 | fputs(buf, resp); |
michael@0 | 468 | fputc('\n', resp); |
michael@0 | 469 | continue; |
michael@0 | 470 | } |
michael@0 | 471 | } |
michael@0 | 472 | |
michael@0 | 473 | loser: |
michael@0 | 474 | fclose(req); |
michael@0 | 475 | } |
michael@0 | 476 | |
michael@0 | 477 | /* |
michael@0 | 478 | * Set the parity bit for the given byte |
michael@0 | 479 | */ |
michael@0 | 480 | BYTE odd_parity( BYTE in) |
michael@0 | 481 | { |
michael@0 | 482 | BYTE out = in; |
michael@0 | 483 | in ^= in >> 4; |
michael@0 | 484 | in ^= in >> 2; |
michael@0 | 485 | in ^= in >> 1; |
michael@0 | 486 | return (BYTE)(out ^ !(in & 1)); |
michael@0 | 487 | } |
michael@0 | 488 | |
michael@0 | 489 | /* |
michael@0 | 490 | * Generate Keys [i+1] from Key[i], PT/CT[j-2], PT/CT[j-1], and PT/CT[j] |
michael@0 | 491 | * for TDEA Monte Carlo Test (MCT) in ECB and CBC modes. |
michael@0 | 492 | */ |
michael@0 | 493 | void |
michael@0 | 494 | tdea_mct_next_keys(unsigned char *key, |
michael@0 | 495 | const unsigned char *text_2, const unsigned char *text_1, |
michael@0 | 496 | const unsigned char *text, unsigned int numKeys) |
michael@0 | 497 | { |
michael@0 | 498 | int k; |
michael@0 | 499 | |
michael@0 | 500 | /* key1[i+1] = key1[i] xor PT/CT[j] */ |
michael@0 | 501 | for (k=0; k<8; k++) { |
michael@0 | 502 | key[k] ^= text[k]; |
michael@0 | 503 | } |
michael@0 | 504 | /* key2 */ |
michael@0 | 505 | if (numKeys == 2 || numKeys == 3) { |
michael@0 | 506 | /* key2 independent */ |
michael@0 | 507 | for (k=8; k<16; k++) { |
michael@0 | 508 | /* key2[i+1] = KEY2[i] xor PT/CT[j-1] */ |
michael@0 | 509 | key[k] ^= text_1[k-8]; |
michael@0 | 510 | } |
michael@0 | 511 | } else { |
michael@0 | 512 | /* key2 == key 1 */ |
michael@0 | 513 | for (k=8; k<16; k++) { |
michael@0 | 514 | /* key2[i+1] = KEY2[i] xor PT/CT[j] */ |
michael@0 | 515 | key[k] = key[k-8]; |
michael@0 | 516 | } |
michael@0 | 517 | } |
michael@0 | 518 | /* key3 */ |
michael@0 | 519 | if (numKeys == 1 || numKeys == 2) { |
michael@0 | 520 | /* key3 == key 1 */ |
michael@0 | 521 | for (k=16; k<24; k++) { |
michael@0 | 522 | /* key3[i+1] = KEY3[i] xor PT/CT[j] */ |
michael@0 | 523 | key[k] = key[k-16]; |
michael@0 | 524 | } |
michael@0 | 525 | } else { |
michael@0 | 526 | /* key3 independent */ |
michael@0 | 527 | for (k=16; k<24; k++) { |
michael@0 | 528 | /* key3[i+1] = KEY3[i] xor PT/CT[j-2] */ |
michael@0 | 529 | key[k] ^= text_2[k-16]; |
michael@0 | 530 | } |
michael@0 | 531 | } |
michael@0 | 532 | /* set the parity bits */ |
michael@0 | 533 | for (k=0; k<24; k++) { |
michael@0 | 534 | key[k] = odd_parity(key[k]); |
michael@0 | 535 | } |
michael@0 | 536 | } |
michael@0 | 537 | |
michael@0 | 538 | /* |
michael@0 | 539 | * Perform the Monte Carlo Test |
michael@0 | 540 | * |
michael@0 | 541 | * mode = NSS_DES_EDE3 or NSS_DES_EDE3_CBC |
michael@0 | 542 | * crypt = ENCRYPT || DECRYPT |
michael@0 | 543 | * inputtext = plaintext or Cyphertext depending on the value of crypt |
michael@0 | 544 | * inputlength is expected to be size 8 bytes |
michael@0 | 545 | * iv = needs to be set for NSS_DES_EDE3_CBC mode |
michael@0 | 546 | * resp = is the output response file. |
michael@0 | 547 | */ |
michael@0 | 548 | void |
michael@0 | 549 | tdea_mct_test(int mode, unsigned char* key, unsigned int numKeys, |
michael@0 | 550 | unsigned int crypt, unsigned char* inputtext, |
michael@0 | 551 | unsigned int inputlength, unsigned char* iv, FILE *resp) { |
michael@0 | 552 | |
michael@0 | 553 | int i, j; |
michael@0 | 554 | unsigned char outputtext_1[8]; /* PT/CT[j-1] */ |
michael@0 | 555 | unsigned char outputtext_2[8]; /* PT/CT[j-2] */ |
michael@0 | 556 | char buf[80]; /* holds one line from the input REQUEST file. */ |
michael@0 | 557 | unsigned int outputlen; |
michael@0 | 558 | unsigned char outputtext[8]; |
michael@0 | 559 | |
michael@0 | 560 | |
michael@0 | 561 | SECStatus rv; |
michael@0 | 562 | |
michael@0 | 563 | if (mode == NSS_DES_EDE3 && iv != NULL) { |
michael@0 | 564 | printf("IV must be NULL for NSS_DES_EDE3 mode"); |
michael@0 | 565 | goto loser; |
michael@0 | 566 | } else if (mode == NSS_DES_EDE3_CBC && iv == NULL) { |
michael@0 | 567 | printf("IV must not be NULL for NSS_DES_EDE3_CBC mode"); |
michael@0 | 568 | goto loser; |
michael@0 | 569 | } |
michael@0 | 570 | |
michael@0 | 571 | /* loop 400 times */ |
michael@0 | 572 | for (i=0; i<400; i++) { |
michael@0 | 573 | /* if i == 0 CV[0] = IV not necessary */ |
michael@0 | 574 | /* record the count and key values and plainText */ |
michael@0 | 575 | sprintf(buf, "COUNT = %d\n", i); |
michael@0 | 576 | fputs(buf, resp); |
michael@0 | 577 | /* Output KEY1[i] */ |
michael@0 | 578 | fputs("KEY1 = ", resp); |
michael@0 | 579 | to_hex_str(buf, key, 8); |
michael@0 | 580 | fputs(buf, resp); |
michael@0 | 581 | fputc('\n', resp); |
michael@0 | 582 | /* Output KEY2[i] */ |
michael@0 | 583 | fputs("KEY2 = ", resp); |
michael@0 | 584 | to_hex_str(buf, &key[8], 8); |
michael@0 | 585 | fputs(buf, resp); |
michael@0 | 586 | fputc('\n', resp); |
michael@0 | 587 | /* Output KEY3[i] */ |
michael@0 | 588 | fputs("KEY3 = ", resp); |
michael@0 | 589 | to_hex_str(buf, &key[16], 8); |
michael@0 | 590 | fputs(buf, resp); |
michael@0 | 591 | fputc('\n', resp); |
michael@0 | 592 | if (mode == NSS_DES_EDE3_CBC) { |
michael@0 | 593 | /* Output CV[i] */ |
michael@0 | 594 | fputs("IV = ", resp); |
michael@0 | 595 | to_hex_str(buf, iv, 8); |
michael@0 | 596 | fputs(buf, resp); |
michael@0 | 597 | fputc('\n', resp); |
michael@0 | 598 | } |
michael@0 | 599 | if (crypt == ENCRYPT) { |
michael@0 | 600 | /* Output PT[0] */ |
michael@0 | 601 | fputs("PLAINTEXT = ", resp); |
michael@0 | 602 | } else { |
michael@0 | 603 | /* Output CT[0] */ |
michael@0 | 604 | fputs("CIPHERTEXT = ", resp); |
michael@0 | 605 | } |
michael@0 | 606 | |
michael@0 | 607 | to_hex_str(buf, inputtext, inputlength); |
michael@0 | 608 | fputs(buf, resp); |
michael@0 | 609 | fputc('\n', resp); |
michael@0 | 610 | |
michael@0 | 611 | /* loop 10,000 times */ |
michael@0 | 612 | for (j=0; j<10000; j++) { |
michael@0 | 613 | |
michael@0 | 614 | outputlen = 0; |
michael@0 | 615 | if (crypt == ENCRYPT) { |
michael@0 | 616 | /* inputtext == ciphertext outputtext == plaintext*/ |
michael@0 | 617 | rv = tdea_encrypt_buf(mode, key, |
michael@0 | 618 | (mode == NSS_DES_EDE3) ? NULL : iv, |
michael@0 | 619 | outputtext, &outputlen, 8, |
michael@0 | 620 | inputtext, 8); |
michael@0 | 621 | } else { |
michael@0 | 622 | /* inputtext == plaintext outputtext == ciphertext */ |
michael@0 | 623 | rv = tdea_decrypt_buf(mode, key, |
michael@0 | 624 | (mode == NSS_DES_EDE3) ? NULL : iv, |
michael@0 | 625 | outputtext, &outputlen, 8, |
michael@0 | 626 | inputtext, 8); |
michael@0 | 627 | } |
michael@0 | 628 | |
michael@0 | 629 | if (rv != SECSuccess) { |
michael@0 | 630 | goto loser; |
michael@0 | 631 | } |
michael@0 | 632 | if (outputlen != inputlength) { |
michael@0 | 633 | goto loser; |
michael@0 | 634 | } |
michael@0 | 635 | |
michael@0 | 636 | if (mode == NSS_DES_EDE3_CBC) { |
michael@0 | 637 | if (crypt == ENCRYPT) { |
michael@0 | 638 | if (j == 0) { |
michael@0 | 639 | /*P[j+1] = CV[0] */ |
michael@0 | 640 | memcpy(inputtext, iv, 8); |
michael@0 | 641 | } else { |
michael@0 | 642 | /* p[j+1] = C[j-1] */ |
michael@0 | 643 | memcpy(inputtext, outputtext_1, 8); |
michael@0 | 644 | } |
michael@0 | 645 | /* CV[j+1] = C[j] */ |
michael@0 | 646 | memcpy(iv, outputtext, 8); |
michael@0 | 647 | if (j != 9999) { |
michael@0 | 648 | /* save C[j-1] */ |
michael@0 | 649 | memcpy(outputtext_1, outputtext, 8); |
michael@0 | 650 | } |
michael@0 | 651 | } else { /* DECRYPT */ |
michael@0 | 652 | /* CV[j+1] = C[j] */ |
michael@0 | 653 | memcpy(iv, inputtext, 8); |
michael@0 | 654 | /* C[j+1] = P[j] */ |
michael@0 | 655 | memcpy(inputtext, outputtext, 8); |
michael@0 | 656 | } |
michael@0 | 657 | } else { |
michael@0 | 658 | /* ECB mode PT/CT[j+1] = CT/PT[j] */ |
michael@0 | 659 | memcpy(inputtext, outputtext, 8); |
michael@0 | 660 | } |
michael@0 | 661 | |
michael@0 | 662 | /* Save PT/CT[j-2] and PT/CT[j-1] */ |
michael@0 | 663 | if (j==9997) memcpy(outputtext_2, outputtext, 8); |
michael@0 | 664 | if (j==9998) memcpy(outputtext_1, outputtext, 8); |
michael@0 | 665 | /* done at the end of the for(j) loop */ |
michael@0 | 666 | } |
michael@0 | 667 | |
michael@0 | 668 | |
michael@0 | 669 | if (crypt == ENCRYPT) { |
michael@0 | 670 | /* Output CT[j] */ |
michael@0 | 671 | fputs("CIPHERTEXT = ", resp); |
michael@0 | 672 | } else { |
michael@0 | 673 | /* Output PT[j] */ |
michael@0 | 674 | fputs("PLAINTEXT = ", resp); |
michael@0 | 675 | } |
michael@0 | 676 | to_hex_str(buf, outputtext, 8); |
michael@0 | 677 | fputs(buf, resp); |
michael@0 | 678 | fputc('\n', resp); |
michael@0 | 679 | |
michael@0 | 680 | /* Key[i+1] = Key[i] xor ... outputtext_2 == PT/CT[j-2] |
michael@0 | 681 | * outputtext_1 == PT/CT[j-1] outputtext == PT/CT[j] |
michael@0 | 682 | */ |
michael@0 | 683 | tdea_mct_next_keys(key, outputtext_2, |
michael@0 | 684 | outputtext_1, outputtext, numKeys); |
michael@0 | 685 | |
michael@0 | 686 | if (mode == NSS_DES_EDE3_CBC) { |
michael@0 | 687 | /* taken care of in the j=9999 iteration */ |
michael@0 | 688 | if (crypt == ENCRYPT) { |
michael@0 | 689 | /* P[i] = C[j-1] */ |
michael@0 | 690 | /* CV[i] = C[j] */ |
michael@0 | 691 | } else { |
michael@0 | 692 | /* taken care of in the j=9999 iteration */ |
michael@0 | 693 | /* CV[i] = C[j] */ |
michael@0 | 694 | /* C[i] = P[j] */ |
michael@0 | 695 | } |
michael@0 | 696 | } else { |
michael@0 | 697 | /* ECB PT/CT[i] = PT/CT[j] */ |
michael@0 | 698 | memcpy(inputtext, outputtext, 8); |
michael@0 | 699 | } |
michael@0 | 700 | /* done at the end of the for(i) loop */ |
michael@0 | 701 | fputc('\n', resp); |
michael@0 | 702 | } |
michael@0 | 703 | |
michael@0 | 704 | loser: |
michael@0 | 705 | return; |
michael@0 | 706 | } |
michael@0 | 707 | |
michael@0 | 708 | /* |
michael@0 | 709 | * Perform the TDEA Monte Carlo Test (MCT) in ECB/CBC modes. |
michael@0 | 710 | * by gathering the input from the request file, and then |
michael@0 | 711 | * calling tdea_mct_test. |
michael@0 | 712 | * |
michael@0 | 713 | * reqfn is the pathname of the input REQUEST file. |
michael@0 | 714 | * |
michael@0 | 715 | * The output RESPONSE file is written to stdout. |
michael@0 | 716 | */ |
michael@0 | 717 | void |
michael@0 | 718 | tdea_mct(int mode, char *reqfn) |
michael@0 | 719 | { |
michael@0 | 720 | int i, j; |
michael@0 | 721 | char buf[80]; /* holds one line from the input REQUEST file. */ |
michael@0 | 722 | FILE *req; /* input stream from the REQUEST file */ |
michael@0 | 723 | FILE *resp; /* output stream to the RESPONSE file */ |
michael@0 | 724 | unsigned int crypt = 0; /* 1 means encrypt, 0 means decrypt */ |
michael@0 | 725 | unsigned char key[24]; /* TDEA 3 key bundle */ |
michael@0 | 726 | unsigned int numKeys = 0; |
michael@0 | 727 | unsigned char plaintext[8]; /* PT[j] */ |
michael@0 | 728 | unsigned char ciphertext[8]; /* CT[j] */ |
michael@0 | 729 | unsigned char iv[8]; |
michael@0 | 730 | |
michael@0 | 731 | /* zeroize the variables for the test with this data set */ |
michael@0 | 732 | memset(key, 0, sizeof key); |
michael@0 | 733 | memset(plaintext, 0, sizeof plaintext); |
michael@0 | 734 | memset(ciphertext, 0, sizeof ciphertext); |
michael@0 | 735 | memset(iv, 0, sizeof iv); |
michael@0 | 736 | |
michael@0 | 737 | req = fopen(reqfn, "r"); |
michael@0 | 738 | resp = stdout; |
michael@0 | 739 | while (fgets(buf, sizeof buf, req) != NULL) { |
michael@0 | 740 | /* a comment or blank line */ |
michael@0 | 741 | if (buf[0] == '#' || buf[0] == '\n') { |
michael@0 | 742 | fputs(buf, resp); |
michael@0 | 743 | continue; |
michael@0 | 744 | } |
michael@0 | 745 | /* [ENCRYPT] or [DECRYPT] */ |
michael@0 | 746 | if (buf[0] == '[') { |
michael@0 | 747 | if (strncmp(&buf[1], "ENCRYPT", 7) == 0) { |
michael@0 | 748 | crypt = ENCRYPT; |
michael@0 | 749 | } else { |
michael@0 | 750 | crypt = DECRYPT; |
michael@0 | 751 | } |
michael@0 | 752 | fputs(buf, resp); |
michael@0 | 753 | continue; |
michael@0 | 754 | } |
michael@0 | 755 | /* NumKeys */ |
michael@0 | 756 | if (strncmp(&buf[0], "NumKeys", 7) == 0) { |
michael@0 | 757 | i = 7; |
michael@0 | 758 | while (isspace(buf[i]) || buf[i] == '=') { |
michael@0 | 759 | i++; |
michael@0 | 760 | } |
michael@0 | 761 | numKeys = atoi(&buf[i]); |
michael@0 | 762 | continue; |
michael@0 | 763 | } |
michael@0 | 764 | /* KEY1 = ... */ |
michael@0 | 765 | if (strncmp(buf, "KEY1", 4) == 0) { |
michael@0 | 766 | i = 4; |
michael@0 | 767 | while (isspace(buf[i]) || buf[i] == '=') { |
michael@0 | 768 | i++; |
michael@0 | 769 | } |
michael@0 | 770 | for (j=0; isxdigit(buf[i]); i+=2,j++) { |
michael@0 | 771 | hex_to_byteval(&buf[i], &key[j]); |
michael@0 | 772 | } |
michael@0 | 773 | continue; |
michael@0 | 774 | } |
michael@0 | 775 | /* KEY2 = ... */ |
michael@0 | 776 | if (strncmp(buf, "KEY2", 4) == 0) { |
michael@0 | 777 | i = 4; |
michael@0 | 778 | while (isspace(buf[i]) || buf[i] == '=') { |
michael@0 | 779 | i++; |
michael@0 | 780 | } |
michael@0 | 781 | for (j=8; isxdigit(buf[i]); i+=2,j++) { |
michael@0 | 782 | hex_to_byteval(&buf[i], &key[j]); |
michael@0 | 783 | } |
michael@0 | 784 | continue; |
michael@0 | 785 | } |
michael@0 | 786 | /* KEY3 = ... */ |
michael@0 | 787 | if (strncmp(buf, "KEY3", 4) == 0) { |
michael@0 | 788 | i = 4; |
michael@0 | 789 | while (isspace(buf[i]) || buf[i] == '=') { |
michael@0 | 790 | i++; |
michael@0 | 791 | } |
michael@0 | 792 | for (j=16; isxdigit(buf[i]); i+=2,j++) { |
michael@0 | 793 | hex_to_byteval(&buf[i], &key[j]); |
michael@0 | 794 | } |
michael@0 | 795 | continue; |
michael@0 | 796 | } |
michael@0 | 797 | |
michael@0 | 798 | /* IV = ... */ |
michael@0 | 799 | if (strncmp(buf, "IV", 2) == 0) { |
michael@0 | 800 | i = 2; |
michael@0 | 801 | while (isspace(buf[i]) || buf[i] == '=') { |
michael@0 | 802 | i++; |
michael@0 | 803 | } |
michael@0 | 804 | for (j=0; j<sizeof iv; i+=2,j++) { |
michael@0 | 805 | hex_to_byteval(&buf[i], &iv[j]); |
michael@0 | 806 | } |
michael@0 | 807 | continue; |
michael@0 | 808 | } |
michael@0 | 809 | |
michael@0 | 810 | /* PLAINTEXT = ... */ |
michael@0 | 811 | if (strncmp(buf, "PLAINTEXT", 9) == 0) { |
michael@0 | 812 | |
michael@0 | 813 | /* sanity check */ |
michael@0 | 814 | if (crypt != ENCRYPT) { |
michael@0 | 815 | goto loser; |
michael@0 | 816 | } |
michael@0 | 817 | /* PT[0] = PT */ |
michael@0 | 818 | i = 9; |
michael@0 | 819 | while (isspace(buf[i]) || buf[i] == '=') { |
michael@0 | 820 | i++; |
michael@0 | 821 | } |
michael@0 | 822 | for (j=0; j<sizeof plaintext; i+=2,j++) { |
michael@0 | 823 | hex_to_byteval(&buf[i], &plaintext[j]); |
michael@0 | 824 | } |
michael@0 | 825 | |
michael@0 | 826 | /* do the Monte Carlo test */ |
michael@0 | 827 | if (mode==NSS_DES_EDE3) { |
michael@0 | 828 | tdea_mct_test(NSS_DES_EDE3, key, numKeys, crypt, plaintext, sizeof plaintext, NULL, resp); |
michael@0 | 829 | } else { |
michael@0 | 830 | tdea_mct_test(NSS_DES_EDE3_CBC, key, numKeys, crypt, plaintext, sizeof plaintext, iv, resp); |
michael@0 | 831 | } |
michael@0 | 832 | continue; |
michael@0 | 833 | } |
michael@0 | 834 | /* CIPHERTEXT = ... */ |
michael@0 | 835 | if (strncmp(buf, "CIPHERTEXT", 10) == 0) { |
michael@0 | 836 | /* sanity check */ |
michael@0 | 837 | if (crypt != DECRYPT) { |
michael@0 | 838 | goto loser; |
michael@0 | 839 | } |
michael@0 | 840 | /* CT[0] = CT */ |
michael@0 | 841 | i = 10; |
michael@0 | 842 | while (isspace(buf[i]) || buf[i] == '=') { |
michael@0 | 843 | i++; |
michael@0 | 844 | } |
michael@0 | 845 | for (j=0; isxdigit(buf[i]); i+=2,j++) { |
michael@0 | 846 | hex_to_byteval(&buf[i], &ciphertext[j]); |
michael@0 | 847 | } |
michael@0 | 848 | |
michael@0 | 849 | /* do the Monte Carlo test */ |
michael@0 | 850 | if (mode==NSS_DES_EDE3) { |
michael@0 | 851 | tdea_mct_test(NSS_DES_EDE3, key, numKeys, crypt, ciphertext, sizeof ciphertext, NULL, resp); |
michael@0 | 852 | } else { |
michael@0 | 853 | tdea_mct_test(NSS_DES_EDE3_CBC, key, numKeys, crypt, ciphertext, sizeof ciphertext, iv, resp); |
michael@0 | 854 | } |
michael@0 | 855 | continue; |
michael@0 | 856 | } |
michael@0 | 857 | } |
michael@0 | 858 | |
michael@0 | 859 | loser: |
michael@0 | 860 | fclose(req); |
michael@0 | 861 | } |
michael@0 | 862 | |
michael@0 | 863 | |
michael@0 | 864 | SECStatus |
michael@0 | 865 | aes_encrypt_buf( |
michael@0 | 866 | int mode, |
michael@0 | 867 | const unsigned char *key, unsigned int keysize, |
michael@0 | 868 | const unsigned char *iv, |
michael@0 | 869 | unsigned char *output, unsigned int *outputlen, unsigned int maxoutputlen, |
michael@0 | 870 | const unsigned char *input, unsigned int inputlen) |
michael@0 | 871 | { |
michael@0 | 872 | SECStatus rv = SECFailure; |
michael@0 | 873 | AESContext *cx; |
michael@0 | 874 | unsigned char doublecheck[10*16]; /* 1 to 10 blocks */ |
michael@0 | 875 | unsigned int doublechecklen = 0; |
michael@0 | 876 | |
michael@0 | 877 | cx = AES_CreateContext(key, iv, mode, PR_TRUE, keysize, 16); |
michael@0 | 878 | if (cx == NULL) { |
michael@0 | 879 | goto loser; |
michael@0 | 880 | } |
michael@0 | 881 | rv = AES_Encrypt(cx, output, outputlen, maxoutputlen, input, inputlen); |
michael@0 | 882 | if (rv != SECSuccess) { |
michael@0 | 883 | goto loser; |
michael@0 | 884 | } |
michael@0 | 885 | if (*outputlen != inputlen) { |
michael@0 | 886 | goto loser; |
michael@0 | 887 | } |
michael@0 | 888 | AES_DestroyContext(cx, PR_TRUE); |
michael@0 | 889 | cx = NULL; |
michael@0 | 890 | |
michael@0 | 891 | /* |
michael@0 | 892 | * Doublecheck our result by decrypting the ciphertext and |
michael@0 | 893 | * compare the output with the input plaintext. |
michael@0 | 894 | */ |
michael@0 | 895 | cx = AES_CreateContext(key, iv, mode, PR_FALSE, keysize, 16); |
michael@0 | 896 | if (cx == NULL) { |
michael@0 | 897 | goto loser; |
michael@0 | 898 | } |
michael@0 | 899 | rv = AES_Decrypt(cx, doublecheck, &doublechecklen, sizeof doublecheck, |
michael@0 | 900 | output, *outputlen); |
michael@0 | 901 | if (rv != SECSuccess) { |
michael@0 | 902 | goto loser; |
michael@0 | 903 | } |
michael@0 | 904 | if (doublechecklen != *outputlen) { |
michael@0 | 905 | goto loser; |
michael@0 | 906 | } |
michael@0 | 907 | AES_DestroyContext(cx, PR_TRUE); |
michael@0 | 908 | cx = NULL; |
michael@0 | 909 | if (memcmp(doublecheck, input, inputlen) != 0) { |
michael@0 | 910 | goto loser; |
michael@0 | 911 | } |
michael@0 | 912 | rv = SECSuccess; |
michael@0 | 913 | |
michael@0 | 914 | loser: |
michael@0 | 915 | if (cx != NULL) { |
michael@0 | 916 | AES_DestroyContext(cx, PR_TRUE); |
michael@0 | 917 | } |
michael@0 | 918 | return rv; |
michael@0 | 919 | } |
michael@0 | 920 | |
michael@0 | 921 | SECStatus |
michael@0 | 922 | aes_decrypt_buf( |
michael@0 | 923 | int mode, |
michael@0 | 924 | const unsigned char *key, unsigned int keysize, |
michael@0 | 925 | const unsigned char *iv, |
michael@0 | 926 | unsigned char *output, unsigned int *outputlen, unsigned int maxoutputlen, |
michael@0 | 927 | const unsigned char *input, unsigned int inputlen) |
michael@0 | 928 | { |
michael@0 | 929 | SECStatus rv = SECFailure; |
michael@0 | 930 | AESContext *cx; |
michael@0 | 931 | unsigned char doublecheck[10*16]; /* 1 to 10 blocks */ |
michael@0 | 932 | unsigned int doublechecklen = 0; |
michael@0 | 933 | |
michael@0 | 934 | cx = AES_CreateContext(key, iv, mode, PR_FALSE, keysize, 16); |
michael@0 | 935 | if (cx == NULL) { |
michael@0 | 936 | goto loser; |
michael@0 | 937 | } |
michael@0 | 938 | rv = AES_Decrypt(cx, output, outputlen, maxoutputlen, |
michael@0 | 939 | input, inputlen); |
michael@0 | 940 | if (rv != SECSuccess) { |
michael@0 | 941 | goto loser; |
michael@0 | 942 | } |
michael@0 | 943 | if (*outputlen != inputlen) { |
michael@0 | 944 | goto loser; |
michael@0 | 945 | } |
michael@0 | 946 | AES_DestroyContext(cx, PR_TRUE); |
michael@0 | 947 | cx = NULL; |
michael@0 | 948 | |
michael@0 | 949 | /* |
michael@0 | 950 | * Doublecheck our result by encrypting the plaintext and |
michael@0 | 951 | * compare the output with the input ciphertext. |
michael@0 | 952 | */ |
michael@0 | 953 | cx = AES_CreateContext(key, iv, mode, PR_TRUE, keysize, 16); |
michael@0 | 954 | if (cx == NULL) { |
michael@0 | 955 | goto loser; |
michael@0 | 956 | } |
michael@0 | 957 | rv = AES_Encrypt(cx, doublecheck, &doublechecklen, sizeof doublecheck, |
michael@0 | 958 | output, *outputlen); |
michael@0 | 959 | if (rv != SECSuccess) { |
michael@0 | 960 | goto loser; |
michael@0 | 961 | } |
michael@0 | 962 | if (doublechecklen != *outputlen) { |
michael@0 | 963 | goto loser; |
michael@0 | 964 | } |
michael@0 | 965 | AES_DestroyContext(cx, PR_TRUE); |
michael@0 | 966 | cx = NULL; |
michael@0 | 967 | if (memcmp(doublecheck, input, inputlen) != 0) { |
michael@0 | 968 | goto loser; |
michael@0 | 969 | } |
michael@0 | 970 | rv = SECSuccess; |
michael@0 | 971 | |
michael@0 | 972 | loser: |
michael@0 | 973 | if (cx != NULL) { |
michael@0 | 974 | AES_DestroyContext(cx, PR_TRUE); |
michael@0 | 975 | } |
michael@0 | 976 | return rv; |
michael@0 | 977 | } |
michael@0 | 978 | |
michael@0 | 979 | /* |
michael@0 | 980 | * Perform the AES Known Answer Test (KAT) or Multi-block Message |
michael@0 | 981 | * Test (MMT) in ECB or CBC mode. The KAT (there are four types) |
michael@0 | 982 | * and MMT have the same structure: given the key and IV (CBC mode |
michael@0 | 983 | * only), encrypt the given plaintext or decrypt the given ciphertext. |
michael@0 | 984 | * So we can handle them the same way. |
michael@0 | 985 | * |
michael@0 | 986 | * reqfn is the pathname of the REQUEST file. |
michael@0 | 987 | * |
michael@0 | 988 | * The output RESPONSE file is written to stdout. |
michael@0 | 989 | */ |
michael@0 | 990 | void |
michael@0 | 991 | aes_kat_mmt(char *reqfn) |
michael@0 | 992 | { |
michael@0 | 993 | char buf[512]; /* holds one line from the input REQUEST file. |
michael@0 | 994 | * needs to be large enough to hold the longest |
michael@0 | 995 | * line "CIPHERTEXT = <320 hex digits>\n". |
michael@0 | 996 | */ |
michael@0 | 997 | FILE *aesreq; /* input stream from the REQUEST file */ |
michael@0 | 998 | FILE *aesresp; /* output stream to the RESPONSE file */ |
michael@0 | 999 | int i, j; |
michael@0 | 1000 | int mode; /* NSS_AES (ECB) or NSS_AES_CBC */ |
michael@0 | 1001 | int encrypt = 0; /* 1 means encrypt, 0 means decrypt */ |
michael@0 | 1002 | unsigned char key[32]; /* 128, 192, or 256 bits */ |
michael@0 | 1003 | unsigned int keysize; |
michael@0 | 1004 | unsigned char iv[16]; /* for all modes except ECB */ |
michael@0 | 1005 | unsigned char plaintext[10*16]; /* 1 to 10 blocks */ |
michael@0 | 1006 | unsigned int plaintextlen; |
michael@0 | 1007 | unsigned char ciphertext[10*16]; /* 1 to 10 blocks */ |
michael@0 | 1008 | unsigned int ciphertextlen; |
michael@0 | 1009 | SECStatus rv; |
michael@0 | 1010 | |
michael@0 | 1011 | aesreq = fopen(reqfn, "r"); |
michael@0 | 1012 | aesresp = stdout; |
michael@0 | 1013 | while (fgets(buf, sizeof buf, aesreq) != NULL) { |
michael@0 | 1014 | /* a comment or blank line */ |
michael@0 | 1015 | if (buf[0] == '#' || buf[0] == '\n') { |
michael@0 | 1016 | fputs(buf, aesresp); |
michael@0 | 1017 | continue; |
michael@0 | 1018 | } |
michael@0 | 1019 | /* [ENCRYPT] or [DECRYPT] */ |
michael@0 | 1020 | if (buf[0] == '[') { |
michael@0 | 1021 | if (strncmp(&buf[1], "ENCRYPT", 7) == 0) { |
michael@0 | 1022 | encrypt = 1; |
michael@0 | 1023 | } else { |
michael@0 | 1024 | encrypt = 0; |
michael@0 | 1025 | } |
michael@0 | 1026 | fputs(buf, aesresp); |
michael@0 | 1027 | continue; |
michael@0 | 1028 | } |
michael@0 | 1029 | /* "COUNT = x" begins a new data set */ |
michael@0 | 1030 | if (strncmp(buf, "COUNT", 5) == 0) { |
michael@0 | 1031 | mode = NSS_AES; |
michael@0 | 1032 | /* zeroize the variables for the test with this data set */ |
michael@0 | 1033 | memset(key, 0, sizeof key); |
michael@0 | 1034 | keysize = 0; |
michael@0 | 1035 | memset(iv, 0, sizeof iv); |
michael@0 | 1036 | memset(plaintext, 0, sizeof plaintext); |
michael@0 | 1037 | plaintextlen = 0; |
michael@0 | 1038 | memset(ciphertext, 0, sizeof ciphertext); |
michael@0 | 1039 | ciphertextlen = 0; |
michael@0 | 1040 | fputs(buf, aesresp); |
michael@0 | 1041 | continue; |
michael@0 | 1042 | } |
michael@0 | 1043 | /* KEY = ... */ |
michael@0 | 1044 | if (strncmp(buf, "KEY", 3) == 0) { |
michael@0 | 1045 | i = 3; |
michael@0 | 1046 | while (isspace(buf[i]) || buf[i] == '=') { |
michael@0 | 1047 | i++; |
michael@0 | 1048 | } |
michael@0 | 1049 | for (j=0; isxdigit(buf[i]); i+=2,j++) { |
michael@0 | 1050 | hex_to_byteval(&buf[i], &key[j]); |
michael@0 | 1051 | } |
michael@0 | 1052 | keysize = j; |
michael@0 | 1053 | fputs(buf, aesresp); |
michael@0 | 1054 | continue; |
michael@0 | 1055 | } |
michael@0 | 1056 | /* IV = ... */ |
michael@0 | 1057 | if (strncmp(buf, "IV", 2) == 0) { |
michael@0 | 1058 | mode = NSS_AES_CBC; |
michael@0 | 1059 | i = 2; |
michael@0 | 1060 | while (isspace(buf[i]) || buf[i] == '=') { |
michael@0 | 1061 | i++; |
michael@0 | 1062 | } |
michael@0 | 1063 | for (j=0; j<sizeof iv; i+=2,j++) { |
michael@0 | 1064 | hex_to_byteval(&buf[i], &iv[j]); |
michael@0 | 1065 | } |
michael@0 | 1066 | fputs(buf, aesresp); |
michael@0 | 1067 | continue; |
michael@0 | 1068 | } |
michael@0 | 1069 | /* PLAINTEXT = ... */ |
michael@0 | 1070 | if (strncmp(buf, "PLAINTEXT", 9) == 0) { |
michael@0 | 1071 | /* sanity check */ |
michael@0 | 1072 | if (!encrypt) { |
michael@0 | 1073 | goto loser; |
michael@0 | 1074 | } |
michael@0 | 1075 | |
michael@0 | 1076 | i = 9; |
michael@0 | 1077 | while (isspace(buf[i]) || buf[i] == '=') { |
michael@0 | 1078 | i++; |
michael@0 | 1079 | } |
michael@0 | 1080 | for (j=0; isxdigit(buf[i]); i+=2,j++) { |
michael@0 | 1081 | hex_to_byteval(&buf[i], &plaintext[j]); |
michael@0 | 1082 | } |
michael@0 | 1083 | plaintextlen = j; |
michael@0 | 1084 | |
michael@0 | 1085 | rv = aes_encrypt_buf(mode, key, keysize, |
michael@0 | 1086 | (mode == NSS_AES) ? NULL : iv, |
michael@0 | 1087 | ciphertext, &ciphertextlen, sizeof ciphertext, |
michael@0 | 1088 | plaintext, plaintextlen); |
michael@0 | 1089 | if (rv != SECSuccess) { |
michael@0 | 1090 | goto loser; |
michael@0 | 1091 | } |
michael@0 | 1092 | |
michael@0 | 1093 | fputs(buf, aesresp); |
michael@0 | 1094 | fputs("CIPHERTEXT = ", aesresp); |
michael@0 | 1095 | to_hex_str(buf, ciphertext, ciphertextlen); |
michael@0 | 1096 | fputs(buf, aesresp); |
michael@0 | 1097 | fputc('\n', aesresp); |
michael@0 | 1098 | continue; |
michael@0 | 1099 | } |
michael@0 | 1100 | /* CIPHERTEXT = ... */ |
michael@0 | 1101 | if (strncmp(buf, "CIPHERTEXT", 10) == 0) { |
michael@0 | 1102 | /* sanity check */ |
michael@0 | 1103 | if (encrypt) { |
michael@0 | 1104 | goto loser; |
michael@0 | 1105 | } |
michael@0 | 1106 | |
michael@0 | 1107 | i = 10; |
michael@0 | 1108 | while (isspace(buf[i]) || buf[i] == '=') { |
michael@0 | 1109 | i++; |
michael@0 | 1110 | } |
michael@0 | 1111 | for (j=0; isxdigit(buf[i]); i+=2,j++) { |
michael@0 | 1112 | hex_to_byteval(&buf[i], &ciphertext[j]); |
michael@0 | 1113 | } |
michael@0 | 1114 | ciphertextlen = j; |
michael@0 | 1115 | |
michael@0 | 1116 | rv = aes_decrypt_buf(mode, key, keysize, |
michael@0 | 1117 | (mode == NSS_AES) ? NULL : iv, |
michael@0 | 1118 | plaintext, &plaintextlen, sizeof plaintext, |
michael@0 | 1119 | ciphertext, ciphertextlen); |
michael@0 | 1120 | if (rv != SECSuccess) { |
michael@0 | 1121 | goto loser; |
michael@0 | 1122 | } |
michael@0 | 1123 | |
michael@0 | 1124 | fputs(buf, aesresp); |
michael@0 | 1125 | fputs("PLAINTEXT = ", aesresp); |
michael@0 | 1126 | to_hex_str(buf, plaintext, plaintextlen); |
michael@0 | 1127 | fputs(buf, aesresp); |
michael@0 | 1128 | fputc('\n', aesresp); |
michael@0 | 1129 | continue; |
michael@0 | 1130 | } |
michael@0 | 1131 | } |
michael@0 | 1132 | loser: |
michael@0 | 1133 | fclose(aesreq); |
michael@0 | 1134 | } |
michael@0 | 1135 | |
michael@0 | 1136 | /* |
michael@0 | 1137 | * Generate Key[i+1] from Key[i], CT[j-1], and CT[j] for AES Monte Carlo |
michael@0 | 1138 | * Test (MCT) in ECB and CBC modes. |
michael@0 | 1139 | */ |
michael@0 | 1140 | void |
michael@0 | 1141 | aes_mct_next_key(unsigned char *key, unsigned int keysize, |
michael@0 | 1142 | const unsigned char *ciphertext_1, const unsigned char *ciphertext) |
michael@0 | 1143 | { |
michael@0 | 1144 | int k; |
michael@0 | 1145 | |
michael@0 | 1146 | switch (keysize) { |
michael@0 | 1147 | case 16: /* 128-bit key */ |
michael@0 | 1148 | /* Key[i+1] = Key[i] xor CT[j] */ |
michael@0 | 1149 | for (k=0; k<16; k++) { |
michael@0 | 1150 | key[k] ^= ciphertext[k]; |
michael@0 | 1151 | } |
michael@0 | 1152 | break; |
michael@0 | 1153 | case 24: /* 192-bit key */ |
michael@0 | 1154 | /* |
michael@0 | 1155 | * Key[i+1] = Key[i] xor (last 64-bits of |
michael@0 | 1156 | * CT[j-1] || CT[j]) |
michael@0 | 1157 | */ |
michael@0 | 1158 | for (k=0; k<8; k++) { |
michael@0 | 1159 | key[k] ^= ciphertext_1[k+8]; |
michael@0 | 1160 | } |
michael@0 | 1161 | for (k=8; k<24; k++) { |
michael@0 | 1162 | key[k] ^= ciphertext[k-8]; |
michael@0 | 1163 | } |
michael@0 | 1164 | break; |
michael@0 | 1165 | case 32: /* 256-bit key */ |
michael@0 | 1166 | /* Key[i+1] = Key[i] xor (CT[j-1] || CT[j]) */ |
michael@0 | 1167 | for (k=0; k<16; k++) { |
michael@0 | 1168 | key[k] ^= ciphertext_1[k]; |
michael@0 | 1169 | } |
michael@0 | 1170 | for (k=16; k<32; k++) { |
michael@0 | 1171 | key[k] ^= ciphertext[k-16]; |
michael@0 | 1172 | } |
michael@0 | 1173 | break; |
michael@0 | 1174 | } |
michael@0 | 1175 | } |
michael@0 | 1176 | |
michael@0 | 1177 | /* |
michael@0 | 1178 | * Perform the AES Monte Carlo Test (MCT) in ECB mode. MCT exercises |
michael@0 | 1179 | * our AES code in streaming mode because the plaintext or ciphertext |
michael@0 | 1180 | * is generated block by block as we go, so we can't collect all the |
michael@0 | 1181 | * plaintext or ciphertext in one buffer and encrypt or decrypt it in |
michael@0 | 1182 | * one shot. |
michael@0 | 1183 | * |
michael@0 | 1184 | * reqfn is the pathname of the input REQUEST file. |
michael@0 | 1185 | * |
michael@0 | 1186 | * The output RESPONSE file is written to stdout. |
michael@0 | 1187 | */ |
michael@0 | 1188 | void |
michael@0 | 1189 | aes_ecb_mct(char *reqfn) |
michael@0 | 1190 | { |
michael@0 | 1191 | char buf[80]; /* holds one line from the input REQUEST file. |
michael@0 | 1192 | * needs to be large enough to hold the longest |
michael@0 | 1193 | * line "KEY = <64 hex digits>\n". |
michael@0 | 1194 | */ |
michael@0 | 1195 | FILE *aesreq; /* input stream from the REQUEST file */ |
michael@0 | 1196 | FILE *aesresp; /* output stream to the RESPONSE file */ |
michael@0 | 1197 | int i, j; |
michael@0 | 1198 | int encrypt = 0; /* 1 means encrypt, 0 means decrypt */ |
michael@0 | 1199 | unsigned char key[32]; /* 128, 192, or 256 bits */ |
michael@0 | 1200 | unsigned int keysize; |
michael@0 | 1201 | unsigned char plaintext[16]; /* PT[j] */ |
michael@0 | 1202 | unsigned char plaintext_1[16]; /* PT[j-1] */ |
michael@0 | 1203 | unsigned char ciphertext[16]; /* CT[j] */ |
michael@0 | 1204 | unsigned char ciphertext_1[16]; /* CT[j-1] */ |
michael@0 | 1205 | unsigned char doublecheck[16]; |
michael@0 | 1206 | unsigned int outputlen; |
michael@0 | 1207 | AESContext *cx = NULL; /* the operation being tested */ |
michael@0 | 1208 | AESContext *cx2 = NULL; /* the inverse operation done in parallel |
michael@0 | 1209 | * to doublecheck our result. |
michael@0 | 1210 | */ |
michael@0 | 1211 | SECStatus rv; |
michael@0 | 1212 | |
michael@0 | 1213 | aesreq = fopen(reqfn, "r"); |
michael@0 | 1214 | aesresp = stdout; |
michael@0 | 1215 | while (fgets(buf, sizeof buf, aesreq) != NULL) { |
michael@0 | 1216 | /* a comment or blank line */ |
michael@0 | 1217 | if (buf[0] == '#' || buf[0] == '\n') { |
michael@0 | 1218 | fputs(buf, aesresp); |
michael@0 | 1219 | continue; |
michael@0 | 1220 | } |
michael@0 | 1221 | /* [ENCRYPT] or [DECRYPT] */ |
michael@0 | 1222 | if (buf[0] == '[') { |
michael@0 | 1223 | if (strncmp(&buf[1], "ENCRYPT", 7) == 0) { |
michael@0 | 1224 | encrypt = 1; |
michael@0 | 1225 | } else { |
michael@0 | 1226 | encrypt = 0; |
michael@0 | 1227 | } |
michael@0 | 1228 | fputs(buf, aesresp); |
michael@0 | 1229 | continue; |
michael@0 | 1230 | } |
michael@0 | 1231 | /* "COUNT = x" begins a new data set */ |
michael@0 | 1232 | if (strncmp(buf, "COUNT", 5) == 0) { |
michael@0 | 1233 | /* zeroize the variables for the test with this data set */ |
michael@0 | 1234 | memset(key, 0, sizeof key); |
michael@0 | 1235 | keysize = 0; |
michael@0 | 1236 | memset(plaintext, 0, sizeof plaintext); |
michael@0 | 1237 | memset(ciphertext, 0, sizeof ciphertext); |
michael@0 | 1238 | continue; |
michael@0 | 1239 | } |
michael@0 | 1240 | /* KEY = ... */ |
michael@0 | 1241 | if (strncmp(buf, "KEY", 3) == 0) { |
michael@0 | 1242 | /* Key[0] = Key */ |
michael@0 | 1243 | i = 3; |
michael@0 | 1244 | while (isspace(buf[i]) || buf[i] == '=') { |
michael@0 | 1245 | i++; |
michael@0 | 1246 | } |
michael@0 | 1247 | for (j=0; isxdigit(buf[i]); i+=2,j++) { |
michael@0 | 1248 | hex_to_byteval(&buf[i], &key[j]); |
michael@0 | 1249 | } |
michael@0 | 1250 | keysize = j; |
michael@0 | 1251 | continue; |
michael@0 | 1252 | } |
michael@0 | 1253 | /* PLAINTEXT = ... */ |
michael@0 | 1254 | if (strncmp(buf, "PLAINTEXT", 9) == 0) { |
michael@0 | 1255 | /* sanity check */ |
michael@0 | 1256 | if (!encrypt) { |
michael@0 | 1257 | goto loser; |
michael@0 | 1258 | } |
michael@0 | 1259 | /* PT[0] = PT */ |
michael@0 | 1260 | i = 9; |
michael@0 | 1261 | while (isspace(buf[i]) || buf[i] == '=') { |
michael@0 | 1262 | i++; |
michael@0 | 1263 | } |
michael@0 | 1264 | for (j=0; j<sizeof plaintext; i+=2,j++) { |
michael@0 | 1265 | hex_to_byteval(&buf[i], &plaintext[j]); |
michael@0 | 1266 | } |
michael@0 | 1267 | |
michael@0 | 1268 | for (i=0; i<100; i++) { |
michael@0 | 1269 | sprintf(buf, "COUNT = %d\n", i); |
michael@0 | 1270 | fputs(buf, aesresp); |
michael@0 | 1271 | /* Output Key[i] */ |
michael@0 | 1272 | fputs("KEY = ", aesresp); |
michael@0 | 1273 | to_hex_str(buf, key, keysize); |
michael@0 | 1274 | fputs(buf, aesresp); |
michael@0 | 1275 | fputc('\n', aesresp); |
michael@0 | 1276 | /* Output PT[0] */ |
michael@0 | 1277 | fputs("PLAINTEXT = ", aesresp); |
michael@0 | 1278 | to_hex_str(buf, plaintext, sizeof plaintext); |
michael@0 | 1279 | fputs(buf, aesresp); |
michael@0 | 1280 | fputc('\n', aesresp); |
michael@0 | 1281 | |
michael@0 | 1282 | cx = AES_CreateContext(key, NULL, NSS_AES, |
michael@0 | 1283 | PR_TRUE, keysize, 16); |
michael@0 | 1284 | if (cx == NULL) { |
michael@0 | 1285 | goto loser; |
michael@0 | 1286 | } |
michael@0 | 1287 | /* |
michael@0 | 1288 | * doublecheck our result by decrypting the result |
michael@0 | 1289 | * and comparing the output with the plaintext. |
michael@0 | 1290 | */ |
michael@0 | 1291 | cx2 = AES_CreateContext(key, NULL, NSS_AES, |
michael@0 | 1292 | PR_FALSE, keysize, 16); |
michael@0 | 1293 | if (cx2 == NULL) { |
michael@0 | 1294 | goto loser; |
michael@0 | 1295 | } |
michael@0 | 1296 | for (j=0; j<1000; j++) { |
michael@0 | 1297 | /* Save CT[j-1] */ |
michael@0 | 1298 | memcpy(ciphertext_1, ciphertext, sizeof ciphertext); |
michael@0 | 1299 | |
michael@0 | 1300 | /* CT[j] = AES(Key[i], PT[j]) */ |
michael@0 | 1301 | outputlen = 0; |
michael@0 | 1302 | rv = AES_Encrypt(cx, |
michael@0 | 1303 | ciphertext, &outputlen, sizeof ciphertext, |
michael@0 | 1304 | plaintext, sizeof plaintext); |
michael@0 | 1305 | if (rv != SECSuccess) { |
michael@0 | 1306 | goto loser; |
michael@0 | 1307 | } |
michael@0 | 1308 | if (outputlen != sizeof plaintext) { |
michael@0 | 1309 | goto loser; |
michael@0 | 1310 | } |
michael@0 | 1311 | |
michael@0 | 1312 | /* doublecheck our result */ |
michael@0 | 1313 | outputlen = 0; |
michael@0 | 1314 | rv = AES_Decrypt(cx2, |
michael@0 | 1315 | doublecheck, &outputlen, sizeof doublecheck, |
michael@0 | 1316 | ciphertext, sizeof ciphertext); |
michael@0 | 1317 | if (rv != SECSuccess) { |
michael@0 | 1318 | goto loser; |
michael@0 | 1319 | } |
michael@0 | 1320 | if (outputlen != sizeof ciphertext) { |
michael@0 | 1321 | goto loser; |
michael@0 | 1322 | } |
michael@0 | 1323 | if (memcmp(doublecheck, plaintext, sizeof plaintext)) { |
michael@0 | 1324 | goto loser; |
michael@0 | 1325 | } |
michael@0 | 1326 | |
michael@0 | 1327 | /* PT[j+1] = CT[j] */ |
michael@0 | 1328 | memcpy(plaintext, ciphertext, sizeof plaintext); |
michael@0 | 1329 | } |
michael@0 | 1330 | AES_DestroyContext(cx, PR_TRUE); |
michael@0 | 1331 | cx = NULL; |
michael@0 | 1332 | AES_DestroyContext(cx2, PR_TRUE); |
michael@0 | 1333 | cx2 = NULL; |
michael@0 | 1334 | |
michael@0 | 1335 | /* Output CT[j] */ |
michael@0 | 1336 | fputs("CIPHERTEXT = ", aesresp); |
michael@0 | 1337 | to_hex_str(buf, ciphertext, sizeof ciphertext); |
michael@0 | 1338 | fputs(buf, aesresp); |
michael@0 | 1339 | fputc('\n', aesresp); |
michael@0 | 1340 | |
michael@0 | 1341 | /* Key[i+1] = Key[i] xor ... */ |
michael@0 | 1342 | aes_mct_next_key(key, keysize, ciphertext_1, ciphertext); |
michael@0 | 1343 | /* PT[0] = CT[j] */ |
michael@0 | 1344 | /* done at the end of the for(j) loop */ |
michael@0 | 1345 | |
michael@0 | 1346 | fputc('\n', aesresp); |
michael@0 | 1347 | } |
michael@0 | 1348 | |
michael@0 | 1349 | continue; |
michael@0 | 1350 | } |
michael@0 | 1351 | /* CIPHERTEXT = ... */ |
michael@0 | 1352 | if (strncmp(buf, "CIPHERTEXT", 10) == 0) { |
michael@0 | 1353 | /* sanity check */ |
michael@0 | 1354 | if (encrypt) { |
michael@0 | 1355 | goto loser; |
michael@0 | 1356 | } |
michael@0 | 1357 | /* CT[0] = CT */ |
michael@0 | 1358 | i = 10; |
michael@0 | 1359 | while (isspace(buf[i]) || buf[i] == '=') { |
michael@0 | 1360 | i++; |
michael@0 | 1361 | } |
michael@0 | 1362 | for (j=0; isxdigit(buf[i]); i+=2,j++) { |
michael@0 | 1363 | hex_to_byteval(&buf[i], &ciphertext[j]); |
michael@0 | 1364 | } |
michael@0 | 1365 | |
michael@0 | 1366 | for (i=0; i<100; i++) { |
michael@0 | 1367 | sprintf(buf, "COUNT = %d\n", i); |
michael@0 | 1368 | fputs(buf, aesresp); |
michael@0 | 1369 | /* Output Key[i] */ |
michael@0 | 1370 | fputs("KEY = ", aesresp); |
michael@0 | 1371 | to_hex_str(buf, key, keysize); |
michael@0 | 1372 | fputs(buf, aesresp); |
michael@0 | 1373 | fputc('\n', aesresp); |
michael@0 | 1374 | /* Output CT[0] */ |
michael@0 | 1375 | fputs("CIPHERTEXT = ", aesresp); |
michael@0 | 1376 | to_hex_str(buf, ciphertext, sizeof ciphertext); |
michael@0 | 1377 | fputs(buf, aesresp); |
michael@0 | 1378 | fputc('\n', aesresp); |
michael@0 | 1379 | |
michael@0 | 1380 | cx = AES_CreateContext(key, NULL, NSS_AES, |
michael@0 | 1381 | PR_FALSE, keysize, 16); |
michael@0 | 1382 | if (cx == NULL) { |
michael@0 | 1383 | goto loser; |
michael@0 | 1384 | } |
michael@0 | 1385 | /* |
michael@0 | 1386 | * doublecheck our result by encrypting the result |
michael@0 | 1387 | * and comparing the output with the ciphertext. |
michael@0 | 1388 | */ |
michael@0 | 1389 | cx2 = AES_CreateContext(key, NULL, NSS_AES, |
michael@0 | 1390 | PR_TRUE, keysize, 16); |
michael@0 | 1391 | if (cx2 == NULL) { |
michael@0 | 1392 | goto loser; |
michael@0 | 1393 | } |
michael@0 | 1394 | for (j=0; j<1000; j++) { |
michael@0 | 1395 | /* Save PT[j-1] */ |
michael@0 | 1396 | memcpy(plaintext_1, plaintext, sizeof plaintext); |
michael@0 | 1397 | |
michael@0 | 1398 | /* PT[j] = AES(Key[i], CT[j]) */ |
michael@0 | 1399 | outputlen = 0; |
michael@0 | 1400 | rv = AES_Decrypt(cx, |
michael@0 | 1401 | plaintext, &outputlen, sizeof plaintext, |
michael@0 | 1402 | ciphertext, sizeof ciphertext); |
michael@0 | 1403 | if (rv != SECSuccess) { |
michael@0 | 1404 | goto loser; |
michael@0 | 1405 | } |
michael@0 | 1406 | if (outputlen != sizeof ciphertext) { |
michael@0 | 1407 | goto loser; |
michael@0 | 1408 | } |
michael@0 | 1409 | |
michael@0 | 1410 | /* doublecheck our result */ |
michael@0 | 1411 | outputlen = 0; |
michael@0 | 1412 | rv = AES_Encrypt(cx2, |
michael@0 | 1413 | doublecheck, &outputlen, sizeof doublecheck, |
michael@0 | 1414 | plaintext, sizeof plaintext); |
michael@0 | 1415 | if (rv != SECSuccess) { |
michael@0 | 1416 | goto loser; |
michael@0 | 1417 | } |
michael@0 | 1418 | if (outputlen != sizeof plaintext) { |
michael@0 | 1419 | goto loser; |
michael@0 | 1420 | } |
michael@0 | 1421 | if (memcmp(doublecheck, ciphertext, sizeof ciphertext)) { |
michael@0 | 1422 | goto loser; |
michael@0 | 1423 | } |
michael@0 | 1424 | |
michael@0 | 1425 | /* CT[j+1] = PT[j] */ |
michael@0 | 1426 | memcpy(ciphertext, plaintext, sizeof ciphertext); |
michael@0 | 1427 | } |
michael@0 | 1428 | AES_DestroyContext(cx, PR_TRUE); |
michael@0 | 1429 | cx = NULL; |
michael@0 | 1430 | AES_DestroyContext(cx2, PR_TRUE); |
michael@0 | 1431 | cx2 = NULL; |
michael@0 | 1432 | |
michael@0 | 1433 | /* Output PT[j] */ |
michael@0 | 1434 | fputs("PLAINTEXT = ", aesresp); |
michael@0 | 1435 | to_hex_str(buf, plaintext, sizeof plaintext); |
michael@0 | 1436 | fputs(buf, aesresp); |
michael@0 | 1437 | fputc('\n', aesresp); |
michael@0 | 1438 | |
michael@0 | 1439 | /* Key[i+1] = Key[i] xor ... */ |
michael@0 | 1440 | aes_mct_next_key(key, keysize, plaintext_1, plaintext); |
michael@0 | 1441 | /* CT[0] = PT[j] */ |
michael@0 | 1442 | /* done at the end of the for(j) loop */ |
michael@0 | 1443 | |
michael@0 | 1444 | fputc('\n', aesresp); |
michael@0 | 1445 | } |
michael@0 | 1446 | |
michael@0 | 1447 | continue; |
michael@0 | 1448 | } |
michael@0 | 1449 | } |
michael@0 | 1450 | loser: |
michael@0 | 1451 | if (cx != NULL) { |
michael@0 | 1452 | AES_DestroyContext(cx, PR_TRUE); |
michael@0 | 1453 | } |
michael@0 | 1454 | if (cx2 != NULL) { |
michael@0 | 1455 | AES_DestroyContext(cx2, PR_TRUE); |
michael@0 | 1456 | } |
michael@0 | 1457 | fclose(aesreq); |
michael@0 | 1458 | } |
michael@0 | 1459 | |
michael@0 | 1460 | /* |
michael@0 | 1461 | * Perform the AES Monte Carlo Test (MCT) in CBC mode. MCT exercises |
michael@0 | 1462 | * our AES code in streaming mode because the plaintext or ciphertext |
michael@0 | 1463 | * is generated block by block as we go, so we can't collect all the |
michael@0 | 1464 | * plaintext or ciphertext in one buffer and encrypt or decrypt it in |
michael@0 | 1465 | * one shot. |
michael@0 | 1466 | * |
michael@0 | 1467 | * reqfn is the pathname of the input REQUEST file. |
michael@0 | 1468 | * |
michael@0 | 1469 | * The output RESPONSE file is written to stdout. |
michael@0 | 1470 | */ |
michael@0 | 1471 | void |
michael@0 | 1472 | aes_cbc_mct(char *reqfn) |
michael@0 | 1473 | { |
michael@0 | 1474 | char buf[80]; /* holds one line from the input REQUEST file. |
michael@0 | 1475 | * needs to be large enough to hold the longest |
michael@0 | 1476 | * line "KEY = <64 hex digits>\n". |
michael@0 | 1477 | */ |
michael@0 | 1478 | FILE *aesreq; /* input stream from the REQUEST file */ |
michael@0 | 1479 | FILE *aesresp; /* output stream to the RESPONSE file */ |
michael@0 | 1480 | int i, j; |
michael@0 | 1481 | int encrypt = 0; /* 1 means encrypt, 0 means decrypt */ |
michael@0 | 1482 | unsigned char key[32]; /* 128, 192, or 256 bits */ |
michael@0 | 1483 | unsigned int keysize; |
michael@0 | 1484 | unsigned char iv[16]; |
michael@0 | 1485 | unsigned char plaintext[16]; /* PT[j] */ |
michael@0 | 1486 | unsigned char plaintext_1[16]; /* PT[j-1] */ |
michael@0 | 1487 | unsigned char ciphertext[16]; /* CT[j] */ |
michael@0 | 1488 | unsigned char ciphertext_1[16]; /* CT[j-1] */ |
michael@0 | 1489 | unsigned char doublecheck[16]; |
michael@0 | 1490 | unsigned int outputlen; |
michael@0 | 1491 | AESContext *cx = NULL; /* the operation being tested */ |
michael@0 | 1492 | AESContext *cx2 = NULL; /* the inverse operation done in parallel |
michael@0 | 1493 | * to doublecheck our result. |
michael@0 | 1494 | */ |
michael@0 | 1495 | SECStatus rv; |
michael@0 | 1496 | |
michael@0 | 1497 | aesreq = fopen(reqfn, "r"); |
michael@0 | 1498 | aesresp = stdout; |
michael@0 | 1499 | while (fgets(buf, sizeof buf, aesreq) != NULL) { |
michael@0 | 1500 | /* a comment or blank line */ |
michael@0 | 1501 | if (buf[0] == '#' || buf[0] == '\n') { |
michael@0 | 1502 | fputs(buf, aesresp); |
michael@0 | 1503 | continue; |
michael@0 | 1504 | } |
michael@0 | 1505 | /* [ENCRYPT] or [DECRYPT] */ |
michael@0 | 1506 | if (buf[0] == '[') { |
michael@0 | 1507 | if (strncmp(&buf[1], "ENCRYPT", 7) == 0) { |
michael@0 | 1508 | encrypt = 1; |
michael@0 | 1509 | } else { |
michael@0 | 1510 | encrypt = 0; |
michael@0 | 1511 | } |
michael@0 | 1512 | fputs(buf, aesresp); |
michael@0 | 1513 | continue; |
michael@0 | 1514 | } |
michael@0 | 1515 | /* "COUNT = x" begins a new data set */ |
michael@0 | 1516 | if (strncmp(buf, "COUNT", 5) == 0) { |
michael@0 | 1517 | /* zeroize the variables for the test with this data set */ |
michael@0 | 1518 | memset(key, 0, sizeof key); |
michael@0 | 1519 | keysize = 0; |
michael@0 | 1520 | memset(iv, 0, sizeof iv); |
michael@0 | 1521 | memset(plaintext, 0, sizeof plaintext); |
michael@0 | 1522 | memset(ciphertext, 0, sizeof ciphertext); |
michael@0 | 1523 | continue; |
michael@0 | 1524 | } |
michael@0 | 1525 | /* KEY = ... */ |
michael@0 | 1526 | if (strncmp(buf, "KEY", 3) == 0) { |
michael@0 | 1527 | /* Key[0] = Key */ |
michael@0 | 1528 | i = 3; |
michael@0 | 1529 | while (isspace(buf[i]) || buf[i] == '=') { |
michael@0 | 1530 | i++; |
michael@0 | 1531 | } |
michael@0 | 1532 | for (j=0; isxdigit(buf[i]); i+=2,j++) { |
michael@0 | 1533 | hex_to_byteval(&buf[i], &key[j]); |
michael@0 | 1534 | } |
michael@0 | 1535 | keysize = j; |
michael@0 | 1536 | continue; |
michael@0 | 1537 | } |
michael@0 | 1538 | /* IV = ... */ |
michael@0 | 1539 | if (strncmp(buf, "IV", 2) == 0) { |
michael@0 | 1540 | /* IV[0] = IV */ |
michael@0 | 1541 | i = 2; |
michael@0 | 1542 | while (isspace(buf[i]) || buf[i] == '=') { |
michael@0 | 1543 | i++; |
michael@0 | 1544 | } |
michael@0 | 1545 | for (j=0; j<sizeof iv; i+=2,j++) { |
michael@0 | 1546 | hex_to_byteval(&buf[i], &iv[j]); |
michael@0 | 1547 | } |
michael@0 | 1548 | continue; |
michael@0 | 1549 | } |
michael@0 | 1550 | /* PLAINTEXT = ... */ |
michael@0 | 1551 | if (strncmp(buf, "PLAINTEXT", 9) == 0) { |
michael@0 | 1552 | /* sanity check */ |
michael@0 | 1553 | if (!encrypt) { |
michael@0 | 1554 | goto loser; |
michael@0 | 1555 | } |
michael@0 | 1556 | /* PT[0] = PT */ |
michael@0 | 1557 | i = 9; |
michael@0 | 1558 | while (isspace(buf[i]) || buf[i] == '=') { |
michael@0 | 1559 | i++; |
michael@0 | 1560 | } |
michael@0 | 1561 | for (j=0; j<sizeof plaintext; i+=2,j++) { |
michael@0 | 1562 | hex_to_byteval(&buf[i], &plaintext[j]); |
michael@0 | 1563 | } |
michael@0 | 1564 | |
michael@0 | 1565 | for (i=0; i<100; i++) { |
michael@0 | 1566 | sprintf(buf, "COUNT = %d\n", i); |
michael@0 | 1567 | fputs(buf, aesresp); |
michael@0 | 1568 | /* Output Key[i] */ |
michael@0 | 1569 | fputs("KEY = ", aesresp); |
michael@0 | 1570 | to_hex_str(buf, key, keysize); |
michael@0 | 1571 | fputs(buf, aesresp); |
michael@0 | 1572 | fputc('\n', aesresp); |
michael@0 | 1573 | /* Output IV[i] */ |
michael@0 | 1574 | fputs("IV = ", aesresp); |
michael@0 | 1575 | to_hex_str(buf, iv, sizeof iv); |
michael@0 | 1576 | fputs(buf, aesresp); |
michael@0 | 1577 | fputc('\n', aesresp); |
michael@0 | 1578 | /* Output PT[0] */ |
michael@0 | 1579 | fputs("PLAINTEXT = ", aesresp); |
michael@0 | 1580 | to_hex_str(buf, plaintext, sizeof plaintext); |
michael@0 | 1581 | fputs(buf, aesresp); |
michael@0 | 1582 | fputc('\n', aesresp); |
michael@0 | 1583 | |
michael@0 | 1584 | cx = AES_CreateContext(key, iv, NSS_AES_CBC, |
michael@0 | 1585 | PR_TRUE, keysize, 16); |
michael@0 | 1586 | if (cx == NULL) { |
michael@0 | 1587 | goto loser; |
michael@0 | 1588 | } |
michael@0 | 1589 | /* |
michael@0 | 1590 | * doublecheck our result by decrypting the result |
michael@0 | 1591 | * and comparing the output with the plaintext. |
michael@0 | 1592 | */ |
michael@0 | 1593 | cx2 = AES_CreateContext(key, iv, NSS_AES_CBC, |
michael@0 | 1594 | PR_FALSE, keysize, 16); |
michael@0 | 1595 | if (cx2 == NULL) { |
michael@0 | 1596 | goto loser; |
michael@0 | 1597 | } |
michael@0 | 1598 | /* CT[-1] = IV[i] */ |
michael@0 | 1599 | memcpy(ciphertext, iv, sizeof ciphertext); |
michael@0 | 1600 | for (j=0; j<1000; j++) { |
michael@0 | 1601 | /* Save CT[j-1] */ |
michael@0 | 1602 | memcpy(ciphertext_1, ciphertext, sizeof ciphertext); |
michael@0 | 1603 | /* |
michael@0 | 1604 | * If ( j=0 ) |
michael@0 | 1605 | * CT[j] = AES(Key[i], IV[i], PT[j]) |
michael@0 | 1606 | * PT[j+1] = IV[i] (= CT[j-1]) |
michael@0 | 1607 | * Else |
michael@0 | 1608 | * CT[j] = AES(Key[i], PT[j]) |
michael@0 | 1609 | * PT[j+1] = CT[j-1] |
michael@0 | 1610 | */ |
michael@0 | 1611 | outputlen = 0; |
michael@0 | 1612 | rv = AES_Encrypt(cx, |
michael@0 | 1613 | ciphertext, &outputlen, sizeof ciphertext, |
michael@0 | 1614 | plaintext, sizeof plaintext); |
michael@0 | 1615 | if (rv != SECSuccess) { |
michael@0 | 1616 | goto loser; |
michael@0 | 1617 | } |
michael@0 | 1618 | if (outputlen != sizeof plaintext) { |
michael@0 | 1619 | goto loser; |
michael@0 | 1620 | } |
michael@0 | 1621 | |
michael@0 | 1622 | /* doublecheck our result */ |
michael@0 | 1623 | outputlen = 0; |
michael@0 | 1624 | rv = AES_Decrypt(cx2, |
michael@0 | 1625 | doublecheck, &outputlen, sizeof doublecheck, |
michael@0 | 1626 | ciphertext, sizeof ciphertext); |
michael@0 | 1627 | if (rv != SECSuccess) { |
michael@0 | 1628 | goto loser; |
michael@0 | 1629 | } |
michael@0 | 1630 | if (outputlen != sizeof ciphertext) { |
michael@0 | 1631 | goto loser; |
michael@0 | 1632 | } |
michael@0 | 1633 | if (memcmp(doublecheck, plaintext, sizeof plaintext)) { |
michael@0 | 1634 | goto loser; |
michael@0 | 1635 | } |
michael@0 | 1636 | |
michael@0 | 1637 | memcpy(plaintext, ciphertext_1, sizeof plaintext); |
michael@0 | 1638 | } |
michael@0 | 1639 | AES_DestroyContext(cx, PR_TRUE); |
michael@0 | 1640 | cx = NULL; |
michael@0 | 1641 | AES_DestroyContext(cx2, PR_TRUE); |
michael@0 | 1642 | cx2 = NULL; |
michael@0 | 1643 | |
michael@0 | 1644 | /* Output CT[j] */ |
michael@0 | 1645 | fputs("CIPHERTEXT = ", aesresp); |
michael@0 | 1646 | to_hex_str(buf, ciphertext, sizeof ciphertext); |
michael@0 | 1647 | fputs(buf, aesresp); |
michael@0 | 1648 | fputc('\n', aesresp); |
michael@0 | 1649 | |
michael@0 | 1650 | /* Key[i+1] = Key[i] xor ... */ |
michael@0 | 1651 | aes_mct_next_key(key, keysize, ciphertext_1, ciphertext); |
michael@0 | 1652 | /* IV[i+1] = CT[j] */ |
michael@0 | 1653 | memcpy(iv, ciphertext, sizeof iv); |
michael@0 | 1654 | /* PT[0] = CT[j-1] */ |
michael@0 | 1655 | /* done at the end of the for(j) loop */ |
michael@0 | 1656 | |
michael@0 | 1657 | fputc('\n', aesresp); |
michael@0 | 1658 | } |
michael@0 | 1659 | |
michael@0 | 1660 | continue; |
michael@0 | 1661 | } |
michael@0 | 1662 | /* CIPHERTEXT = ... */ |
michael@0 | 1663 | if (strncmp(buf, "CIPHERTEXT", 10) == 0) { |
michael@0 | 1664 | /* sanity check */ |
michael@0 | 1665 | if (encrypt) { |
michael@0 | 1666 | goto loser; |
michael@0 | 1667 | } |
michael@0 | 1668 | /* CT[0] = CT */ |
michael@0 | 1669 | i = 10; |
michael@0 | 1670 | while (isspace(buf[i]) || buf[i] == '=') { |
michael@0 | 1671 | i++; |
michael@0 | 1672 | } |
michael@0 | 1673 | for (j=0; isxdigit(buf[i]); i+=2,j++) { |
michael@0 | 1674 | hex_to_byteval(&buf[i], &ciphertext[j]); |
michael@0 | 1675 | } |
michael@0 | 1676 | |
michael@0 | 1677 | for (i=0; i<100; i++) { |
michael@0 | 1678 | sprintf(buf, "COUNT = %d\n", i); |
michael@0 | 1679 | fputs(buf, aesresp); |
michael@0 | 1680 | /* Output Key[i] */ |
michael@0 | 1681 | fputs("KEY = ", aesresp); |
michael@0 | 1682 | to_hex_str(buf, key, keysize); |
michael@0 | 1683 | fputs(buf, aesresp); |
michael@0 | 1684 | fputc('\n', aesresp); |
michael@0 | 1685 | /* Output IV[i] */ |
michael@0 | 1686 | fputs("IV = ", aesresp); |
michael@0 | 1687 | to_hex_str(buf, iv, sizeof iv); |
michael@0 | 1688 | fputs(buf, aesresp); |
michael@0 | 1689 | fputc('\n', aesresp); |
michael@0 | 1690 | /* Output CT[0] */ |
michael@0 | 1691 | fputs("CIPHERTEXT = ", aesresp); |
michael@0 | 1692 | to_hex_str(buf, ciphertext, sizeof ciphertext); |
michael@0 | 1693 | fputs(buf, aesresp); |
michael@0 | 1694 | fputc('\n', aesresp); |
michael@0 | 1695 | |
michael@0 | 1696 | cx = AES_CreateContext(key, iv, NSS_AES_CBC, |
michael@0 | 1697 | PR_FALSE, keysize, 16); |
michael@0 | 1698 | if (cx == NULL) { |
michael@0 | 1699 | goto loser; |
michael@0 | 1700 | } |
michael@0 | 1701 | /* |
michael@0 | 1702 | * doublecheck our result by encrypting the result |
michael@0 | 1703 | * and comparing the output with the ciphertext. |
michael@0 | 1704 | */ |
michael@0 | 1705 | cx2 = AES_CreateContext(key, iv, NSS_AES_CBC, |
michael@0 | 1706 | PR_TRUE, keysize, 16); |
michael@0 | 1707 | if (cx2 == NULL) { |
michael@0 | 1708 | goto loser; |
michael@0 | 1709 | } |
michael@0 | 1710 | /* PT[-1] = IV[i] */ |
michael@0 | 1711 | memcpy(plaintext, iv, sizeof plaintext); |
michael@0 | 1712 | for (j=0; j<1000; j++) { |
michael@0 | 1713 | /* Save PT[j-1] */ |
michael@0 | 1714 | memcpy(plaintext_1, plaintext, sizeof plaintext); |
michael@0 | 1715 | /* |
michael@0 | 1716 | * If ( j=0 ) |
michael@0 | 1717 | * PT[j] = AES(Key[i], IV[i], CT[j]) |
michael@0 | 1718 | * CT[j+1] = IV[i] (= PT[j-1]) |
michael@0 | 1719 | * Else |
michael@0 | 1720 | * PT[j] = AES(Key[i], CT[j]) |
michael@0 | 1721 | * CT[j+1] = PT[j-1] |
michael@0 | 1722 | */ |
michael@0 | 1723 | outputlen = 0; |
michael@0 | 1724 | rv = AES_Decrypt(cx, |
michael@0 | 1725 | plaintext, &outputlen, sizeof plaintext, |
michael@0 | 1726 | ciphertext, sizeof ciphertext); |
michael@0 | 1727 | if (rv != SECSuccess) { |
michael@0 | 1728 | goto loser; |
michael@0 | 1729 | } |
michael@0 | 1730 | if (outputlen != sizeof ciphertext) { |
michael@0 | 1731 | goto loser; |
michael@0 | 1732 | } |
michael@0 | 1733 | |
michael@0 | 1734 | /* doublecheck our result */ |
michael@0 | 1735 | outputlen = 0; |
michael@0 | 1736 | rv = AES_Encrypt(cx2, |
michael@0 | 1737 | doublecheck, &outputlen, sizeof doublecheck, |
michael@0 | 1738 | plaintext, sizeof plaintext); |
michael@0 | 1739 | if (rv != SECSuccess) { |
michael@0 | 1740 | goto loser; |
michael@0 | 1741 | } |
michael@0 | 1742 | if (outputlen != sizeof plaintext) { |
michael@0 | 1743 | goto loser; |
michael@0 | 1744 | } |
michael@0 | 1745 | if (memcmp(doublecheck, ciphertext, sizeof ciphertext)) { |
michael@0 | 1746 | goto loser; |
michael@0 | 1747 | } |
michael@0 | 1748 | |
michael@0 | 1749 | memcpy(ciphertext, plaintext_1, sizeof ciphertext); |
michael@0 | 1750 | } |
michael@0 | 1751 | AES_DestroyContext(cx, PR_TRUE); |
michael@0 | 1752 | cx = NULL; |
michael@0 | 1753 | AES_DestroyContext(cx2, PR_TRUE); |
michael@0 | 1754 | cx2 = NULL; |
michael@0 | 1755 | |
michael@0 | 1756 | /* Output PT[j] */ |
michael@0 | 1757 | fputs("PLAINTEXT = ", aesresp); |
michael@0 | 1758 | to_hex_str(buf, plaintext, sizeof plaintext); |
michael@0 | 1759 | fputs(buf, aesresp); |
michael@0 | 1760 | fputc('\n', aesresp); |
michael@0 | 1761 | |
michael@0 | 1762 | /* Key[i+1] = Key[i] xor ... */ |
michael@0 | 1763 | aes_mct_next_key(key, keysize, plaintext_1, plaintext); |
michael@0 | 1764 | /* IV[i+1] = PT[j] */ |
michael@0 | 1765 | memcpy(iv, plaintext, sizeof iv); |
michael@0 | 1766 | /* CT[0] = PT[j-1] */ |
michael@0 | 1767 | /* done at the end of the for(j) loop */ |
michael@0 | 1768 | |
michael@0 | 1769 | fputc('\n', aesresp); |
michael@0 | 1770 | } |
michael@0 | 1771 | |
michael@0 | 1772 | continue; |
michael@0 | 1773 | } |
michael@0 | 1774 | } |
michael@0 | 1775 | loser: |
michael@0 | 1776 | if (cx != NULL) { |
michael@0 | 1777 | AES_DestroyContext(cx, PR_TRUE); |
michael@0 | 1778 | } |
michael@0 | 1779 | if (cx2 != NULL) { |
michael@0 | 1780 | AES_DestroyContext(cx2, PR_TRUE); |
michael@0 | 1781 | } |
michael@0 | 1782 | fclose(aesreq); |
michael@0 | 1783 | } |
michael@0 | 1784 | |
michael@0 | 1785 | void write_compact_string(FILE *out, unsigned char *hash, unsigned int len) |
michael@0 | 1786 | { |
michael@0 | 1787 | unsigned int i; |
michael@0 | 1788 | int j, count = 0, last = -1, z = 0; |
michael@0 | 1789 | long start = ftell(out); |
michael@0 | 1790 | for (i=0; i<len; i++) { |
michael@0 | 1791 | for (j=7; j>=0; j--) { |
michael@0 | 1792 | if (last < 0) { |
michael@0 | 1793 | last = (hash[i] & (1 << j)) ? 1 : 0; |
michael@0 | 1794 | fprintf(out, "%d ", last); |
michael@0 | 1795 | count = 1; |
michael@0 | 1796 | } else if (hash[i] & (1 << j)) { |
michael@0 | 1797 | if (last) { |
michael@0 | 1798 | count++; |
michael@0 | 1799 | } else { |
michael@0 | 1800 | last = 0; |
michael@0 | 1801 | fprintf(out, "%d ", count); |
michael@0 | 1802 | count = 1; |
michael@0 | 1803 | z++; |
michael@0 | 1804 | } |
michael@0 | 1805 | } else { |
michael@0 | 1806 | if (!last) { |
michael@0 | 1807 | count++; |
michael@0 | 1808 | } else { |
michael@0 | 1809 | last = 1; |
michael@0 | 1810 | fprintf(out, "%d ", count); |
michael@0 | 1811 | count = 1; |
michael@0 | 1812 | z++; |
michael@0 | 1813 | } |
michael@0 | 1814 | } |
michael@0 | 1815 | } |
michael@0 | 1816 | } |
michael@0 | 1817 | fprintf(out, "^\n"); |
michael@0 | 1818 | fseek(out, start, SEEK_SET); |
michael@0 | 1819 | fprintf(out, "%d ", z); |
michael@0 | 1820 | fseek(out, 0, SEEK_END); |
michael@0 | 1821 | } |
michael@0 | 1822 | |
michael@0 | 1823 | int get_next_line(FILE *req, char *key, char *val, FILE *rsp) |
michael@0 | 1824 | { |
michael@0 | 1825 | int ignore = 0; |
michael@0 | 1826 | char *writeto = key; |
michael@0 | 1827 | int w = 0; |
michael@0 | 1828 | int c; |
michael@0 | 1829 | while ((c = fgetc(req)) != EOF) { |
michael@0 | 1830 | if (ignore) { |
michael@0 | 1831 | fprintf(rsp, "%c", c); |
michael@0 | 1832 | if (c == '\n') return ignore; |
michael@0 | 1833 | } else if (c == '\n') { |
michael@0 | 1834 | break; |
michael@0 | 1835 | } else if (c == '#') { |
michael@0 | 1836 | ignore = 1; |
michael@0 | 1837 | fprintf(rsp, "%c", c); |
michael@0 | 1838 | } else if (c == '=') { |
michael@0 | 1839 | writeto[w] = '\0'; |
michael@0 | 1840 | w = 0; |
michael@0 | 1841 | writeto = val; |
michael@0 | 1842 | } else if (c == ' ' || c == '[' || c == ']') { |
michael@0 | 1843 | continue; |
michael@0 | 1844 | } else { |
michael@0 | 1845 | writeto[w++] = c; |
michael@0 | 1846 | } |
michael@0 | 1847 | } |
michael@0 | 1848 | writeto[w] = '\0'; |
michael@0 | 1849 | return (c == EOF) ? -1 : ignore; |
michael@0 | 1850 | } |
michael@0 | 1851 | |
michael@0 | 1852 | #ifndef NSS_DISABLE_ECC |
michael@0 | 1853 | typedef struct curveNameTagPairStr { |
michael@0 | 1854 | char *curveName; |
michael@0 | 1855 | SECOidTag curveOidTag; |
michael@0 | 1856 | } CurveNameTagPair; |
michael@0 | 1857 | |
michael@0 | 1858 | #define DEFAULT_CURVE_OID_TAG SEC_OID_SECG_EC_SECP192R1 |
michael@0 | 1859 | /* #define DEFAULT_CURVE_OID_TAG SEC_OID_SECG_EC_SECP160R1 */ |
michael@0 | 1860 | |
michael@0 | 1861 | static CurveNameTagPair nameTagPair[] = |
michael@0 | 1862 | { |
michael@0 | 1863 | { "sect163k1", SEC_OID_SECG_EC_SECT163K1}, |
michael@0 | 1864 | { "nistk163", SEC_OID_SECG_EC_SECT163K1}, |
michael@0 | 1865 | { "sect163r1", SEC_OID_SECG_EC_SECT163R1}, |
michael@0 | 1866 | { "sect163r2", SEC_OID_SECG_EC_SECT163R2}, |
michael@0 | 1867 | { "nistb163", SEC_OID_SECG_EC_SECT163R2}, |
michael@0 | 1868 | { "sect193r1", SEC_OID_SECG_EC_SECT193R1}, |
michael@0 | 1869 | { "sect193r2", SEC_OID_SECG_EC_SECT193R2}, |
michael@0 | 1870 | { "sect233k1", SEC_OID_SECG_EC_SECT233K1}, |
michael@0 | 1871 | { "nistk233", SEC_OID_SECG_EC_SECT233K1}, |
michael@0 | 1872 | { "sect233r1", SEC_OID_SECG_EC_SECT233R1}, |
michael@0 | 1873 | { "nistb233", SEC_OID_SECG_EC_SECT233R1}, |
michael@0 | 1874 | { "sect239k1", SEC_OID_SECG_EC_SECT239K1}, |
michael@0 | 1875 | { "sect283k1", SEC_OID_SECG_EC_SECT283K1}, |
michael@0 | 1876 | { "nistk283", SEC_OID_SECG_EC_SECT283K1}, |
michael@0 | 1877 | { "sect283r1", SEC_OID_SECG_EC_SECT283R1}, |
michael@0 | 1878 | { "nistb283", SEC_OID_SECG_EC_SECT283R1}, |
michael@0 | 1879 | { "sect409k1", SEC_OID_SECG_EC_SECT409K1}, |
michael@0 | 1880 | { "nistk409", SEC_OID_SECG_EC_SECT409K1}, |
michael@0 | 1881 | { "sect409r1", SEC_OID_SECG_EC_SECT409R1}, |
michael@0 | 1882 | { "nistb409", SEC_OID_SECG_EC_SECT409R1}, |
michael@0 | 1883 | { "sect571k1", SEC_OID_SECG_EC_SECT571K1}, |
michael@0 | 1884 | { "nistk571", SEC_OID_SECG_EC_SECT571K1}, |
michael@0 | 1885 | { "sect571r1", SEC_OID_SECG_EC_SECT571R1}, |
michael@0 | 1886 | { "nistb571", SEC_OID_SECG_EC_SECT571R1}, |
michael@0 | 1887 | { "secp160k1", SEC_OID_SECG_EC_SECP160K1}, |
michael@0 | 1888 | { "secp160r1", SEC_OID_SECG_EC_SECP160R1}, |
michael@0 | 1889 | { "secp160r2", SEC_OID_SECG_EC_SECP160R2}, |
michael@0 | 1890 | { "secp192k1", SEC_OID_SECG_EC_SECP192K1}, |
michael@0 | 1891 | { "secp192r1", SEC_OID_SECG_EC_SECP192R1}, |
michael@0 | 1892 | { "nistp192", SEC_OID_SECG_EC_SECP192R1}, |
michael@0 | 1893 | { "secp224k1", SEC_OID_SECG_EC_SECP224K1}, |
michael@0 | 1894 | { "secp224r1", SEC_OID_SECG_EC_SECP224R1}, |
michael@0 | 1895 | { "nistp224", SEC_OID_SECG_EC_SECP224R1}, |
michael@0 | 1896 | { "secp256k1", SEC_OID_SECG_EC_SECP256K1}, |
michael@0 | 1897 | { "secp256r1", SEC_OID_SECG_EC_SECP256R1}, |
michael@0 | 1898 | { "nistp256", SEC_OID_SECG_EC_SECP256R1}, |
michael@0 | 1899 | { "secp384r1", SEC_OID_SECG_EC_SECP384R1}, |
michael@0 | 1900 | { "nistp384", SEC_OID_SECG_EC_SECP384R1}, |
michael@0 | 1901 | { "secp521r1", SEC_OID_SECG_EC_SECP521R1}, |
michael@0 | 1902 | { "nistp521", SEC_OID_SECG_EC_SECP521R1}, |
michael@0 | 1903 | |
michael@0 | 1904 | { "prime192v1", SEC_OID_ANSIX962_EC_PRIME192V1 }, |
michael@0 | 1905 | { "prime192v2", SEC_OID_ANSIX962_EC_PRIME192V2 }, |
michael@0 | 1906 | { "prime192v3", SEC_OID_ANSIX962_EC_PRIME192V3 }, |
michael@0 | 1907 | { "prime239v1", SEC_OID_ANSIX962_EC_PRIME239V1 }, |
michael@0 | 1908 | { "prime239v2", SEC_OID_ANSIX962_EC_PRIME239V2 }, |
michael@0 | 1909 | { "prime239v3", SEC_OID_ANSIX962_EC_PRIME239V3 }, |
michael@0 | 1910 | |
michael@0 | 1911 | { "c2pnb163v1", SEC_OID_ANSIX962_EC_C2PNB163V1 }, |
michael@0 | 1912 | { "c2pnb163v2", SEC_OID_ANSIX962_EC_C2PNB163V2 }, |
michael@0 | 1913 | { "c2pnb163v3", SEC_OID_ANSIX962_EC_C2PNB163V3 }, |
michael@0 | 1914 | { "c2pnb176v1", SEC_OID_ANSIX962_EC_C2PNB176V1 }, |
michael@0 | 1915 | { "c2tnb191v1", SEC_OID_ANSIX962_EC_C2TNB191V1 }, |
michael@0 | 1916 | { "c2tnb191v2", SEC_OID_ANSIX962_EC_C2TNB191V2 }, |
michael@0 | 1917 | { "c2tnb191v3", SEC_OID_ANSIX962_EC_C2TNB191V3 }, |
michael@0 | 1918 | { "c2onb191v4", SEC_OID_ANSIX962_EC_C2ONB191V4 }, |
michael@0 | 1919 | { "c2onb191v5", SEC_OID_ANSIX962_EC_C2ONB191V5 }, |
michael@0 | 1920 | { "c2pnb208w1", SEC_OID_ANSIX962_EC_C2PNB208W1 }, |
michael@0 | 1921 | { "c2tnb239v1", SEC_OID_ANSIX962_EC_C2TNB239V1 }, |
michael@0 | 1922 | { "c2tnb239v2", SEC_OID_ANSIX962_EC_C2TNB239V2 }, |
michael@0 | 1923 | { "c2tnb239v3", SEC_OID_ANSIX962_EC_C2TNB239V3 }, |
michael@0 | 1924 | { "c2onb239v4", SEC_OID_ANSIX962_EC_C2ONB239V4 }, |
michael@0 | 1925 | { "c2onb239v5", SEC_OID_ANSIX962_EC_C2ONB239V5 }, |
michael@0 | 1926 | { "c2pnb272w1", SEC_OID_ANSIX962_EC_C2PNB272W1 }, |
michael@0 | 1927 | { "c2pnb304w1", SEC_OID_ANSIX962_EC_C2PNB304W1 }, |
michael@0 | 1928 | { "c2tnb359v1", SEC_OID_ANSIX962_EC_C2TNB359V1 }, |
michael@0 | 1929 | { "c2pnb368w1", SEC_OID_ANSIX962_EC_C2PNB368W1 }, |
michael@0 | 1930 | { "c2tnb431r1", SEC_OID_ANSIX962_EC_C2TNB431R1 }, |
michael@0 | 1931 | |
michael@0 | 1932 | { "secp112r1", SEC_OID_SECG_EC_SECP112R1}, |
michael@0 | 1933 | { "secp112r2", SEC_OID_SECG_EC_SECP112R2}, |
michael@0 | 1934 | { "secp128r1", SEC_OID_SECG_EC_SECP128R1}, |
michael@0 | 1935 | { "secp128r2", SEC_OID_SECG_EC_SECP128R2}, |
michael@0 | 1936 | |
michael@0 | 1937 | { "sect113r1", SEC_OID_SECG_EC_SECT113R1}, |
michael@0 | 1938 | { "sect113r2", SEC_OID_SECG_EC_SECT113R2}, |
michael@0 | 1939 | { "sect131r1", SEC_OID_SECG_EC_SECT131R1}, |
michael@0 | 1940 | { "sect131r2", SEC_OID_SECG_EC_SECT131R2}, |
michael@0 | 1941 | }; |
michael@0 | 1942 | |
michael@0 | 1943 | static SECItem * |
michael@0 | 1944 | getECParams(const char *curve) |
michael@0 | 1945 | { |
michael@0 | 1946 | SECItem *ecparams; |
michael@0 | 1947 | SECOidData *oidData = NULL; |
michael@0 | 1948 | SECOidTag curveOidTag = SEC_OID_UNKNOWN; /* default */ |
michael@0 | 1949 | int i, numCurves; |
michael@0 | 1950 | |
michael@0 | 1951 | if (curve != NULL) { |
michael@0 | 1952 | numCurves = sizeof(nameTagPair)/sizeof(CurveNameTagPair); |
michael@0 | 1953 | for (i = 0; ((i < numCurves) && (curveOidTag == SEC_OID_UNKNOWN)); |
michael@0 | 1954 | i++) { |
michael@0 | 1955 | if (PL_strcmp(curve, nameTagPair[i].curveName) == 0) |
michael@0 | 1956 | curveOidTag = nameTagPair[i].curveOidTag; |
michael@0 | 1957 | } |
michael@0 | 1958 | } |
michael@0 | 1959 | |
michael@0 | 1960 | /* Return NULL if curve name is not recognized */ |
michael@0 | 1961 | if ((curveOidTag == SEC_OID_UNKNOWN) || |
michael@0 | 1962 | (oidData = SECOID_FindOIDByTag(curveOidTag)) == NULL) { |
michael@0 | 1963 | fprintf(stderr, "Unrecognized elliptic curve %s\n", curve); |
michael@0 | 1964 | return NULL; |
michael@0 | 1965 | } |
michael@0 | 1966 | |
michael@0 | 1967 | ecparams = SECITEM_AllocItem(NULL, NULL, (2 + oidData->oid.len)); |
michael@0 | 1968 | |
michael@0 | 1969 | /* |
michael@0 | 1970 | * ecparams->data needs to contain the ASN encoding of an object ID (OID) |
michael@0 | 1971 | * representing the named curve. The actual OID is in |
michael@0 | 1972 | * oidData->oid.data so we simply prepend 0x06 and OID length |
michael@0 | 1973 | */ |
michael@0 | 1974 | ecparams->data[0] = SEC_ASN1_OBJECT_ID; |
michael@0 | 1975 | ecparams->data[1] = oidData->oid.len; |
michael@0 | 1976 | memcpy(ecparams->data + 2, oidData->oid.data, oidData->oid.len); |
michael@0 | 1977 | |
michael@0 | 1978 | return ecparams; |
michael@0 | 1979 | } |
michael@0 | 1980 | |
michael@0 | 1981 | /* |
michael@0 | 1982 | * Perform the ECDSA Key Pair Generation Test. |
michael@0 | 1983 | * |
michael@0 | 1984 | * reqfn is the pathname of the REQUEST file. |
michael@0 | 1985 | * |
michael@0 | 1986 | * The output RESPONSE file is written to stdout. |
michael@0 | 1987 | */ |
michael@0 | 1988 | void |
michael@0 | 1989 | ecdsa_keypair_test(char *reqfn) |
michael@0 | 1990 | { |
michael@0 | 1991 | char buf[256]; /* holds one line from the input REQUEST file |
michael@0 | 1992 | * or to the output RESPONSE file. |
michael@0 | 1993 | * needs to be large enough to hold the longest |
michael@0 | 1994 | * line "Qx = <144 hex digits>\n". |
michael@0 | 1995 | */ |
michael@0 | 1996 | FILE *ecdsareq; /* input stream from the REQUEST file */ |
michael@0 | 1997 | FILE *ecdsaresp; /* output stream to the RESPONSE file */ |
michael@0 | 1998 | char curve[16]; /* "nistxddd" */ |
michael@0 | 1999 | ECParams *ecparams; |
michael@0 | 2000 | int N; |
michael@0 | 2001 | int i; |
michael@0 | 2002 | unsigned int len; |
michael@0 | 2003 | |
michael@0 | 2004 | ecdsareq = fopen(reqfn, "r"); |
michael@0 | 2005 | ecdsaresp = stdout; |
michael@0 | 2006 | strcpy(curve, "nist"); |
michael@0 | 2007 | while (fgets(buf, sizeof buf, ecdsareq) != NULL) { |
michael@0 | 2008 | /* a comment or blank line */ |
michael@0 | 2009 | if (buf[0] == '#' || buf[0] == '\n') { |
michael@0 | 2010 | fputs(buf, ecdsaresp); |
michael@0 | 2011 | continue; |
michael@0 | 2012 | } |
michael@0 | 2013 | /* [X-ddd] */ |
michael@0 | 2014 | if (buf[0] == '[') { |
michael@0 | 2015 | const char *src; |
michael@0 | 2016 | char *dst; |
michael@0 | 2017 | SECItem *encodedparams; |
michael@0 | 2018 | |
michael@0 | 2019 | src = &buf[1]; |
michael@0 | 2020 | dst = &curve[4]; |
michael@0 | 2021 | *dst++ = tolower(*src); |
michael@0 | 2022 | src += 2; /* skip the hyphen */ |
michael@0 | 2023 | *dst++ = *src++; |
michael@0 | 2024 | *dst++ = *src++; |
michael@0 | 2025 | *dst++ = *src++; |
michael@0 | 2026 | *dst = '\0'; |
michael@0 | 2027 | encodedparams = getECParams(curve); |
michael@0 | 2028 | if (encodedparams == NULL) { |
michael@0 | 2029 | goto loser; |
michael@0 | 2030 | } |
michael@0 | 2031 | if (EC_DecodeParams(encodedparams, &ecparams) != SECSuccess) { |
michael@0 | 2032 | goto loser; |
michael@0 | 2033 | } |
michael@0 | 2034 | SECITEM_FreeItem(encodedparams, PR_TRUE); |
michael@0 | 2035 | fputs(buf, ecdsaresp); |
michael@0 | 2036 | continue; |
michael@0 | 2037 | } |
michael@0 | 2038 | /* N = x */ |
michael@0 | 2039 | if (buf[0] == 'N') { |
michael@0 | 2040 | if (sscanf(buf, "N = %d", &N) != 1) { |
michael@0 | 2041 | goto loser; |
michael@0 | 2042 | } |
michael@0 | 2043 | for (i = 0; i < N; i++) { |
michael@0 | 2044 | ECPrivateKey *ecpriv; |
michael@0 | 2045 | |
michael@0 | 2046 | if (EC_NewKey(ecparams, &ecpriv) != SECSuccess) { |
michael@0 | 2047 | goto loser; |
michael@0 | 2048 | } |
michael@0 | 2049 | fputs("d = ", ecdsaresp); |
michael@0 | 2050 | to_hex_str(buf, ecpriv->privateValue.data, |
michael@0 | 2051 | ecpriv->privateValue.len); |
michael@0 | 2052 | fputs(buf, ecdsaresp); |
michael@0 | 2053 | fputc('\n', ecdsaresp); |
michael@0 | 2054 | if (EC_ValidatePublicKey(ecparams, &ecpriv->publicValue) |
michael@0 | 2055 | != SECSuccess) { |
michael@0 | 2056 | goto loser; |
michael@0 | 2057 | } |
michael@0 | 2058 | len = ecpriv->publicValue.len; |
michael@0 | 2059 | if (len%2 == 0) { |
michael@0 | 2060 | goto loser; |
michael@0 | 2061 | } |
michael@0 | 2062 | len = (len-1)/2; |
michael@0 | 2063 | if (ecpriv->publicValue.data[0] |
michael@0 | 2064 | != EC_POINT_FORM_UNCOMPRESSED) { |
michael@0 | 2065 | goto loser; |
michael@0 | 2066 | } |
michael@0 | 2067 | fputs("Qx = ", ecdsaresp); |
michael@0 | 2068 | to_hex_str(buf, &ecpriv->publicValue.data[1], len); |
michael@0 | 2069 | fputs(buf, ecdsaresp); |
michael@0 | 2070 | fputc('\n', ecdsaresp); |
michael@0 | 2071 | fputs("Qy = ", ecdsaresp); |
michael@0 | 2072 | to_hex_str(buf, &ecpriv->publicValue.data[1+len], len); |
michael@0 | 2073 | fputs(buf, ecdsaresp); |
michael@0 | 2074 | fputc('\n', ecdsaresp); |
michael@0 | 2075 | fputc('\n', ecdsaresp); |
michael@0 | 2076 | PORT_FreeArena(ecpriv->ecParams.arena, PR_TRUE); |
michael@0 | 2077 | } |
michael@0 | 2078 | PORT_FreeArena(ecparams->arena, PR_FALSE); |
michael@0 | 2079 | continue; |
michael@0 | 2080 | } |
michael@0 | 2081 | } |
michael@0 | 2082 | loser: |
michael@0 | 2083 | fclose(ecdsareq); |
michael@0 | 2084 | } |
michael@0 | 2085 | |
michael@0 | 2086 | /* |
michael@0 | 2087 | * Perform the ECDSA Public Key Validation Test. |
michael@0 | 2088 | * |
michael@0 | 2089 | * reqfn is the pathname of the REQUEST file. |
michael@0 | 2090 | * |
michael@0 | 2091 | * The output RESPONSE file is written to stdout. |
michael@0 | 2092 | */ |
michael@0 | 2093 | void |
michael@0 | 2094 | ecdsa_pkv_test(char *reqfn) |
michael@0 | 2095 | { |
michael@0 | 2096 | char buf[256]; /* holds one line from the input REQUEST file. |
michael@0 | 2097 | * needs to be large enough to hold the longest |
michael@0 | 2098 | * line "Qx = <144 hex digits>\n". |
michael@0 | 2099 | */ |
michael@0 | 2100 | FILE *ecdsareq; /* input stream from the REQUEST file */ |
michael@0 | 2101 | FILE *ecdsaresp; /* output stream to the RESPONSE file */ |
michael@0 | 2102 | char curve[16]; /* "nistxddd" */ |
michael@0 | 2103 | ECParams *ecparams = NULL; |
michael@0 | 2104 | SECItem pubkey; |
michael@0 | 2105 | unsigned int i; |
michael@0 | 2106 | unsigned int len; |
michael@0 | 2107 | PRBool keyvalid = PR_TRUE; |
michael@0 | 2108 | |
michael@0 | 2109 | ecdsareq = fopen(reqfn, "r"); |
michael@0 | 2110 | ecdsaresp = stdout; |
michael@0 | 2111 | strcpy(curve, "nist"); |
michael@0 | 2112 | pubkey.data = NULL; |
michael@0 | 2113 | while (fgets(buf, sizeof buf, ecdsareq) != NULL) { |
michael@0 | 2114 | /* a comment or blank line */ |
michael@0 | 2115 | if (buf[0] == '#' || buf[0] == '\n') { |
michael@0 | 2116 | fputs(buf, ecdsaresp); |
michael@0 | 2117 | continue; |
michael@0 | 2118 | } |
michael@0 | 2119 | /* [X-ddd] */ |
michael@0 | 2120 | if (buf[0] == '[') { |
michael@0 | 2121 | const char *src; |
michael@0 | 2122 | char *dst; |
michael@0 | 2123 | SECItem *encodedparams; |
michael@0 | 2124 | |
michael@0 | 2125 | src = &buf[1]; |
michael@0 | 2126 | dst = &curve[4]; |
michael@0 | 2127 | *dst++ = tolower(*src); |
michael@0 | 2128 | src += 2; /* skip the hyphen */ |
michael@0 | 2129 | *dst++ = *src++; |
michael@0 | 2130 | *dst++ = *src++; |
michael@0 | 2131 | *dst++ = *src++; |
michael@0 | 2132 | *dst = '\0'; |
michael@0 | 2133 | if (ecparams != NULL) { |
michael@0 | 2134 | PORT_FreeArena(ecparams->arena, PR_FALSE); |
michael@0 | 2135 | ecparams = NULL; |
michael@0 | 2136 | } |
michael@0 | 2137 | encodedparams = getECParams(curve); |
michael@0 | 2138 | if (encodedparams == NULL) { |
michael@0 | 2139 | goto loser; |
michael@0 | 2140 | } |
michael@0 | 2141 | if (EC_DecodeParams(encodedparams, &ecparams) != SECSuccess) { |
michael@0 | 2142 | goto loser; |
michael@0 | 2143 | } |
michael@0 | 2144 | SECITEM_FreeItem(encodedparams, PR_TRUE); |
michael@0 | 2145 | len = (ecparams->fieldID.size + 7) >> 3; |
michael@0 | 2146 | if (pubkey.data != NULL) { |
michael@0 | 2147 | PORT_Free(pubkey.data); |
michael@0 | 2148 | pubkey.data = NULL; |
michael@0 | 2149 | } |
michael@0 | 2150 | SECITEM_AllocItem(NULL, &pubkey, 2*len+1); |
michael@0 | 2151 | if (pubkey.data == NULL) { |
michael@0 | 2152 | goto loser; |
michael@0 | 2153 | } |
michael@0 | 2154 | pubkey.data[0] = EC_POINT_FORM_UNCOMPRESSED; |
michael@0 | 2155 | fputs(buf, ecdsaresp); |
michael@0 | 2156 | continue; |
michael@0 | 2157 | } |
michael@0 | 2158 | /* Qx = ... */ |
michael@0 | 2159 | if (strncmp(buf, "Qx", 2) == 0) { |
michael@0 | 2160 | fputs(buf, ecdsaresp); |
michael@0 | 2161 | i = 2; |
michael@0 | 2162 | while (isspace(buf[i]) || buf[i] == '=') { |
michael@0 | 2163 | i++; |
michael@0 | 2164 | } |
michael@0 | 2165 | keyvalid = from_hex_str(&pubkey.data[1], len, &buf[i]); |
michael@0 | 2166 | continue; |
michael@0 | 2167 | } |
michael@0 | 2168 | /* Qy = ... */ |
michael@0 | 2169 | if (strncmp(buf, "Qy", 2) == 0) { |
michael@0 | 2170 | fputs(buf, ecdsaresp); |
michael@0 | 2171 | if (!keyvalid) { |
michael@0 | 2172 | fputs("Result = F\n", ecdsaresp); |
michael@0 | 2173 | continue; |
michael@0 | 2174 | } |
michael@0 | 2175 | i = 2; |
michael@0 | 2176 | while (isspace(buf[i]) || buf[i] == '=') { |
michael@0 | 2177 | i++; |
michael@0 | 2178 | } |
michael@0 | 2179 | keyvalid = from_hex_str(&pubkey.data[1+len], len, &buf[i]); |
michael@0 | 2180 | if (!keyvalid) { |
michael@0 | 2181 | fputs("Result = F\n", ecdsaresp); |
michael@0 | 2182 | continue; |
michael@0 | 2183 | } |
michael@0 | 2184 | if (EC_ValidatePublicKey(ecparams, &pubkey) == SECSuccess) { |
michael@0 | 2185 | fputs("Result = P\n", ecdsaresp); |
michael@0 | 2186 | } else if (PORT_GetError() == SEC_ERROR_BAD_KEY) { |
michael@0 | 2187 | fputs("Result = F\n", ecdsaresp); |
michael@0 | 2188 | } else { |
michael@0 | 2189 | goto loser; |
michael@0 | 2190 | } |
michael@0 | 2191 | continue; |
michael@0 | 2192 | } |
michael@0 | 2193 | } |
michael@0 | 2194 | loser: |
michael@0 | 2195 | if (ecparams != NULL) { |
michael@0 | 2196 | PORT_FreeArena(ecparams->arena, PR_FALSE); |
michael@0 | 2197 | } |
michael@0 | 2198 | if (pubkey.data != NULL) { |
michael@0 | 2199 | PORT_Free(pubkey.data); |
michael@0 | 2200 | } |
michael@0 | 2201 | fclose(ecdsareq); |
michael@0 | 2202 | } |
michael@0 | 2203 | |
michael@0 | 2204 | /* |
michael@0 | 2205 | * Perform the ECDSA Signature Generation Test. |
michael@0 | 2206 | * |
michael@0 | 2207 | * reqfn is the pathname of the REQUEST file. |
michael@0 | 2208 | * |
michael@0 | 2209 | * The output RESPONSE file is written to stdout. |
michael@0 | 2210 | */ |
michael@0 | 2211 | void |
michael@0 | 2212 | ecdsa_siggen_test(char *reqfn) |
michael@0 | 2213 | { |
michael@0 | 2214 | char buf[1024]; /* holds one line from the input REQUEST file |
michael@0 | 2215 | * or to the output RESPONSE file. |
michael@0 | 2216 | * needs to be large enough to hold the longest |
michael@0 | 2217 | * line "Msg = <256 hex digits>\n". |
michael@0 | 2218 | */ |
michael@0 | 2219 | FILE *ecdsareq; /* input stream from the REQUEST file */ |
michael@0 | 2220 | FILE *ecdsaresp; /* output stream to the RESPONSE file */ |
michael@0 | 2221 | char curve[16]; /* "nistxddd" */ |
michael@0 | 2222 | ECParams *ecparams = NULL; |
michael@0 | 2223 | int i, j; |
michael@0 | 2224 | unsigned int len; |
michael@0 | 2225 | unsigned char msg[512]; /* message to be signed (<= 128 bytes) */ |
michael@0 | 2226 | unsigned int msglen; |
michael@0 | 2227 | unsigned char sha1[20]; /* SHA-1 hash (160 bits) */ |
michael@0 | 2228 | unsigned char sig[2*MAX_ECKEY_LEN]; |
michael@0 | 2229 | SECItem signature, digest; |
michael@0 | 2230 | |
michael@0 | 2231 | ecdsareq = fopen(reqfn, "r"); |
michael@0 | 2232 | ecdsaresp = stdout; |
michael@0 | 2233 | strcpy(curve, "nist"); |
michael@0 | 2234 | while (fgets(buf, sizeof buf, ecdsareq) != NULL) { |
michael@0 | 2235 | /* a comment or blank line */ |
michael@0 | 2236 | if (buf[0] == '#' || buf[0] == '\n') { |
michael@0 | 2237 | fputs(buf, ecdsaresp); |
michael@0 | 2238 | continue; |
michael@0 | 2239 | } |
michael@0 | 2240 | /* [X-ddd] */ |
michael@0 | 2241 | if (buf[0] == '[') { |
michael@0 | 2242 | const char *src; |
michael@0 | 2243 | char *dst; |
michael@0 | 2244 | SECItem *encodedparams; |
michael@0 | 2245 | |
michael@0 | 2246 | src = &buf[1]; |
michael@0 | 2247 | dst = &curve[4]; |
michael@0 | 2248 | *dst++ = tolower(*src); |
michael@0 | 2249 | src += 2; /* skip the hyphen */ |
michael@0 | 2250 | *dst++ = *src++; |
michael@0 | 2251 | *dst++ = *src++; |
michael@0 | 2252 | *dst++ = *src++; |
michael@0 | 2253 | *dst = '\0'; |
michael@0 | 2254 | if (ecparams != NULL) { |
michael@0 | 2255 | PORT_FreeArena(ecparams->arena, PR_FALSE); |
michael@0 | 2256 | ecparams = NULL; |
michael@0 | 2257 | } |
michael@0 | 2258 | encodedparams = getECParams(curve); |
michael@0 | 2259 | if (encodedparams == NULL) { |
michael@0 | 2260 | goto loser; |
michael@0 | 2261 | } |
michael@0 | 2262 | if (EC_DecodeParams(encodedparams, &ecparams) != SECSuccess) { |
michael@0 | 2263 | goto loser; |
michael@0 | 2264 | } |
michael@0 | 2265 | SECITEM_FreeItem(encodedparams, PR_TRUE); |
michael@0 | 2266 | fputs(buf, ecdsaresp); |
michael@0 | 2267 | continue; |
michael@0 | 2268 | } |
michael@0 | 2269 | /* Msg = ... */ |
michael@0 | 2270 | if (strncmp(buf, "Msg", 3) == 0) { |
michael@0 | 2271 | ECPrivateKey *ecpriv; |
michael@0 | 2272 | |
michael@0 | 2273 | i = 3; |
michael@0 | 2274 | while (isspace(buf[i]) || buf[i] == '=') { |
michael@0 | 2275 | i++; |
michael@0 | 2276 | } |
michael@0 | 2277 | for (j=0; isxdigit(buf[i]); i+=2,j++) { |
michael@0 | 2278 | hex_to_byteval(&buf[i], &msg[j]); |
michael@0 | 2279 | } |
michael@0 | 2280 | msglen = j; |
michael@0 | 2281 | if (SHA1_HashBuf(sha1, msg, msglen) != SECSuccess) { |
michael@0 | 2282 | goto loser; |
michael@0 | 2283 | } |
michael@0 | 2284 | fputs(buf, ecdsaresp); |
michael@0 | 2285 | |
michael@0 | 2286 | if (EC_NewKey(ecparams, &ecpriv) != SECSuccess) { |
michael@0 | 2287 | goto loser; |
michael@0 | 2288 | } |
michael@0 | 2289 | if (EC_ValidatePublicKey(ecparams, &ecpriv->publicValue) |
michael@0 | 2290 | != SECSuccess) { |
michael@0 | 2291 | goto loser; |
michael@0 | 2292 | } |
michael@0 | 2293 | len = ecpriv->publicValue.len; |
michael@0 | 2294 | if (len%2 == 0) { |
michael@0 | 2295 | goto loser; |
michael@0 | 2296 | } |
michael@0 | 2297 | len = (len-1)/2; |
michael@0 | 2298 | if (ecpriv->publicValue.data[0] != EC_POINT_FORM_UNCOMPRESSED) { |
michael@0 | 2299 | goto loser; |
michael@0 | 2300 | } |
michael@0 | 2301 | fputs("Qx = ", ecdsaresp); |
michael@0 | 2302 | to_hex_str(buf, &ecpriv->publicValue.data[1], len); |
michael@0 | 2303 | fputs(buf, ecdsaresp); |
michael@0 | 2304 | fputc('\n', ecdsaresp); |
michael@0 | 2305 | fputs("Qy = ", ecdsaresp); |
michael@0 | 2306 | to_hex_str(buf, &ecpriv->publicValue.data[1+len], len); |
michael@0 | 2307 | fputs(buf, ecdsaresp); |
michael@0 | 2308 | fputc('\n', ecdsaresp); |
michael@0 | 2309 | |
michael@0 | 2310 | digest.type = siBuffer; |
michael@0 | 2311 | digest.data = sha1; |
michael@0 | 2312 | digest.len = sizeof sha1; |
michael@0 | 2313 | signature.type = siBuffer; |
michael@0 | 2314 | signature.data = sig; |
michael@0 | 2315 | signature.len = sizeof sig; |
michael@0 | 2316 | if (ECDSA_SignDigest(ecpriv, &signature, &digest) != SECSuccess) { |
michael@0 | 2317 | goto loser; |
michael@0 | 2318 | } |
michael@0 | 2319 | len = signature.len; |
michael@0 | 2320 | if (len%2 != 0) { |
michael@0 | 2321 | goto loser; |
michael@0 | 2322 | } |
michael@0 | 2323 | len = len/2; |
michael@0 | 2324 | fputs("R = ", ecdsaresp); |
michael@0 | 2325 | to_hex_str(buf, &signature.data[0], len); |
michael@0 | 2326 | fputs(buf, ecdsaresp); |
michael@0 | 2327 | fputc('\n', ecdsaresp); |
michael@0 | 2328 | fputs("S = ", ecdsaresp); |
michael@0 | 2329 | to_hex_str(buf, &signature.data[len], len); |
michael@0 | 2330 | fputs(buf, ecdsaresp); |
michael@0 | 2331 | fputc('\n', ecdsaresp); |
michael@0 | 2332 | |
michael@0 | 2333 | PORT_FreeArena(ecpriv->ecParams.arena, PR_TRUE); |
michael@0 | 2334 | continue; |
michael@0 | 2335 | } |
michael@0 | 2336 | } |
michael@0 | 2337 | loser: |
michael@0 | 2338 | if (ecparams != NULL) { |
michael@0 | 2339 | PORT_FreeArena(ecparams->arena, PR_FALSE); |
michael@0 | 2340 | } |
michael@0 | 2341 | fclose(ecdsareq); |
michael@0 | 2342 | } |
michael@0 | 2343 | |
michael@0 | 2344 | /* |
michael@0 | 2345 | * Perform the ECDSA Signature Verification Test. |
michael@0 | 2346 | * |
michael@0 | 2347 | * reqfn is the pathname of the REQUEST file. |
michael@0 | 2348 | * |
michael@0 | 2349 | * The output RESPONSE file is written to stdout. |
michael@0 | 2350 | */ |
michael@0 | 2351 | void |
michael@0 | 2352 | ecdsa_sigver_test(char *reqfn) |
michael@0 | 2353 | { |
michael@0 | 2354 | char buf[1024]; /* holds one line from the input REQUEST file. |
michael@0 | 2355 | * needs to be large enough to hold the longest |
michael@0 | 2356 | * line "Msg = <256 hex digits>\n". |
michael@0 | 2357 | */ |
michael@0 | 2358 | FILE *ecdsareq; /* input stream from the REQUEST file */ |
michael@0 | 2359 | FILE *ecdsaresp; /* output stream to the RESPONSE file */ |
michael@0 | 2360 | char curve[16]; /* "nistxddd" */ |
michael@0 | 2361 | ECPublicKey ecpub; |
michael@0 | 2362 | unsigned int i, j; |
michael@0 | 2363 | unsigned int flen; /* length in bytes of the field size */ |
michael@0 | 2364 | unsigned int olen; /* length in bytes of the base point order */ |
michael@0 | 2365 | unsigned char msg[512]; /* message that was signed (<= 128 bytes) */ |
michael@0 | 2366 | unsigned int msglen; |
michael@0 | 2367 | unsigned char sha1[20]; /* SHA-1 hash (160 bits) */ |
michael@0 | 2368 | unsigned char sig[2*MAX_ECKEY_LEN]; |
michael@0 | 2369 | SECItem signature, digest; |
michael@0 | 2370 | PRBool keyvalid = PR_TRUE; |
michael@0 | 2371 | PRBool sigvalid = PR_TRUE; |
michael@0 | 2372 | |
michael@0 | 2373 | ecdsareq = fopen(reqfn, "r"); |
michael@0 | 2374 | ecdsaresp = stdout; |
michael@0 | 2375 | ecpub.ecParams.arena = NULL; |
michael@0 | 2376 | strcpy(curve, "nist"); |
michael@0 | 2377 | while (fgets(buf, sizeof buf, ecdsareq) != NULL) { |
michael@0 | 2378 | /* a comment or blank line */ |
michael@0 | 2379 | if (buf[0] == '#' || buf[0] == '\n') { |
michael@0 | 2380 | fputs(buf, ecdsaresp); |
michael@0 | 2381 | continue; |
michael@0 | 2382 | } |
michael@0 | 2383 | /* [X-ddd] */ |
michael@0 | 2384 | if (buf[0] == '[') { |
michael@0 | 2385 | const char *src; |
michael@0 | 2386 | char *dst; |
michael@0 | 2387 | SECItem *encodedparams; |
michael@0 | 2388 | ECParams *ecparams; |
michael@0 | 2389 | |
michael@0 | 2390 | src = &buf[1]; |
michael@0 | 2391 | dst = &curve[4]; |
michael@0 | 2392 | *dst++ = tolower(*src); |
michael@0 | 2393 | src += 2; /* skip the hyphen */ |
michael@0 | 2394 | *dst++ = *src++; |
michael@0 | 2395 | *dst++ = *src++; |
michael@0 | 2396 | *dst++ = *src++; |
michael@0 | 2397 | *dst = '\0'; |
michael@0 | 2398 | encodedparams = getECParams(curve); |
michael@0 | 2399 | if (encodedparams == NULL) { |
michael@0 | 2400 | goto loser; |
michael@0 | 2401 | } |
michael@0 | 2402 | if (EC_DecodeParams(encodedparams, &ecparams) != SECSuccess) { |
michael@0 | 2403 | goto loser; |
michael@0 | 2404 | } |
michael@0 | 2405 | SECITEM_FreeItem(encodedparams, PR_TRUE); |
michael@0 | 2406 | if (ecpub.ecParams.arena != NULL) { |
michael@0 | 2407 | PORT_FreeArena(ecpub.ecParams.arena, PR_FALSE); |
michael@0 | 2408 | } |
michael@0 | 2409 | ecpub.ecParams.arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); |
michael@0 | 2410 | if (ecpub.ecParams.arena == NULL) { |
michael@0 | 2411 | goto loser; |
michael@0 | 2412 | } |
michael@0 | 2413 | if (EC_CopyParams(ecpub.ecParams.arena, &ecpub.ecParams, ecparams) |
michael@0 | 2414 | != SECSuccess) { |
michael@0 | 2415 | goto loser; |
michael@0 | 2416 | } |
michael@0 | 2417 | PORT_FreeArena(ecparams->arena, PR_FALSE); |
michael@0 | 2418 | flen = (ecpub.ecParams.fieldID.size + 7) >> 3; |
michael@0 | 2419 | olen = ecpub.ecParams.order.len; |
michael@0 | 2420 | if (2*olen > sizeof sig) { |
michael@0 | 2421 | goto loser; |
michael@0 | 2422 | } |
michael@0 | 2423 | ecpub.publicValue.type = siBuffer; |
michael@0 | 2424 | ecpub.publicValue.data = NULL; |
michael@0 | 2425 | ecpub.publicValue.len = 0; |
michael@0 | 2426 | SECITEM_AllocItem(ecpub.ecParams.arena, |
michael@0 | 2427 | &ecpub.publicValue, 2*flen+1); |
michael@0 | 2428 | if (ecpub.publicValue.data == NULL) { |
michael@0 | 2429 | goto loser; |
michael@0 | 2430 | } |
michael@0 | 2431 | ecpub.publicValue.data[0] = EC_POINT_FORM_UNCOMPRESSED; |
michael@0 | 2432 | fputs(buf, ecdsaresp); |
michael@0 | 2433 | continue; |
michael@0 | 2434 | } |
michael@0 | 2435 | /* Msg = ... */ |
michael@0 | 2436 | if (strncmp(buf, "Msg", 3) == 0) { |
michael@0 | 2437 | i = 3; |
michael@0 | 2438 | while (isspace(buf[i]) || buf[i] == '=') { |
michael@0 | 2439 | i++; |
michael@0 | 2440 | } |
michael@0 | 2441 | for (j=0; isxdigit(buf[i]); i+=2,j++) { |
michael@0 | 2442 | hex_to_byteval(&buf[i], &msg[j]); |
michael@0 | 2443 | } |
michael@0 | 2444 | msglen = j; |
michael@0 | 2445 | if (SHA1_HashBuf(sha1, msg, msglen) != SECSuccess) { |
michael@0 | 2446 | goto loser; |
michael@0 | 2447 | } |
michael@0 | 2448 | fputs(buf, ecdsaresp); |
michael@0 | 2449 | |
michael@0 | 2450 | digest.type = siBuffer; |
michael@0 | 2451 | digest.data = sha1; |
michael@0 | 2452 | digest.len = sizeof sha1; |
michael@0 | 2453 | |
michael@0 | 2454 | continue; |
michael@0 | 2455 | } |
michael@0 | 2456 | /* Qx = ... */ |
michael@0 | 2457 | if (strncmp(buf, "Qx", 2) == 0) { |
michael@0 | 2458 | fputs(buf, ecdsaresp); |
michael@0 | 2459 | i = 2; |
michael@0 | 2460 | while (isspace(buf[i]) || buf[i] == '=') { |
michael@0 | 2461 | i++; |
michael@0 | 2462 | } |
michael@0 | 2463 | keyvalid = from_hex_str(&ecpub.publicValue.data[1], flen, |
michael@0 | 2464 | &buf[i]); |
michael@0 | 2465 | continue; |
michael@0 | 2466 | } |
michael@0 | 2467 | /* Qy = ... */ |
michael@0 | 2468 | if (strncmp(buf, "Qy", 2) == 0) { |
michael@0 | 2469 | fputs(buf, ecdsaresp); |
michael@0 | 2470 | if (!keyvalid) { |
michael@0 | 2471 | continue; |
michael@0 | 2472 | } |
michael@0 | 2473 | i = 2; |
michael@0 | 2474 | while (isspace(buf[i]) || buf[i] == '=') { |
michael@0 | 2475 | i++; |
michael@0 | 2476 | } |
michael@0 | 2477 | keyvalid = from_hex_str(&ecpub.publicValue.data[1+flen], flen, |
michael@0 | 2478 | &buf[i]); |
michael@0 | 2479 | if (!keyvalid) { |
michael@0 | 2480 | continue; |
michael@0 | 2481 | } |
michael@0 | 2482 | if (EC_ValidatePublicKey(&ecpub.ecParams, &ecpub.publicValue) |
michael@0 | 2483 | != SECSuccess) { |
michael@0 | 2484 | if (PORT_GetError() == SEC_ERROR_BAD_KEY) { |
michael@0 | 2485 | keyvalid = PR_FALSE; |
michael@0 | 2486 | } else { |
michael@0 | 2487 | goto loser; |
michael@0 | 2488 | } |
michael@0 | 2489 | } |
michael@0 | 2490 | continue; |
michael@0 | 2491 | } |
michael@0 | 2492 | /* R = ... */ |
michael@0 | 2493 | if (buf[0] == 'R') { |
michael@0 | 2494 | fputs(buf, ecdsaresp); |
michael@0 | 2495 | i = 1; |
michael@0 | 2496 | while (isspace(buf[i]) || buf[i] == '=') { |
michael@0 | 2497 | i++; |
michael@0 | 2498 | } |
michael@0 | 2499 | sigvalid = from_hex_str(sig, olen, &buf[i]); |
michael@0 | 2500 | continue; |
michael@0 | 2501 | } |
michael@0 | 2502 | /* S = ... */ |
michael@0 | 2503 | if (buf[0] == 'S') { |
michael@0 | 2504 | fputs(buf, ecdsaresp); |
michael@0 | 2505 | i = 1; |
michael@0 | 2506 | while (isspace(buf[i]) || buf[i] == '=') { |
michael@0 | 2507 | i++; |
michael@0 | 2508 | } |
michael@0 | 2509 | if (sigvalid) { |
michael@0 | 2510 | sigvalid = from_hex_str(&sig[olen], olen, &buf[i]); |
michael@0 | 2511 | } |
michael@0 | 2512 | signature.type = siBuffer; |
michael@0 | 2513 | signature.data = sig; |
michael@0 | 2514 | signature.len = 2*olen; |
michael@0 | 2515 | |
michael@0 | 2516 | if (!keyvalid || !sigvalid) { |
michael@0 | 2517 | fputs("Result = F\n", ecdsaresp); |
michael@0 | 2518 | } else if (ECDSA_VerifyDigest(&ecpub, &signature, &digest) |
michael@0 | 2519 | == SECSuccess) { |
michael@0 | 2520 | fputs("Result = P\n", ecdsaresp); |
michael@0 | 2521 | } else { |
michael@0 | 2522 | fputs("Result = F\n", ecdsaresp); |
michael@0 | 2523 | } |
michael@0 | 2524 | continue; |
michael@0 | 2525 | } |
michael@0 | 2526 | } |
michael@0 | 2527 | loser: |
michael@0 | 2528 | if (ecpub.ecParams.arena != NULL) { |
michael@0 | 2529 | PORT_FreeArena(ecpub.ecParams.arena, PR_FALSE); |
michael@0 | 2530 | } |
michael@0 | 2531 | fclose(ecdsareq); |
michael@0 | 2532 | } |
michael@0 | 2533 | #endif /* NSS_DISABLE_ECC */ |
michael@0 | 2534 | |
michael@0 | 2535 | |
michael@0 | 2536 | /* |
michael@0 | 2537 | * Read a value from the test and allocate the result. |
michael@0 | 2538 | */ |
michael@0 | 2539 | static unsigned char * |
michael@0 | 2540 | alloc_value(char *buf, int *len) |
michael@0 | 2541 | { |
michael@0 | 2542 | unsigned char * value; |
michael@0 | 2543 | int i, count; |
michael@0 | 2544 | |
michael@0 | 2545 | if (strncmp(buf, "<None>", 6) == 0) { |
michael@0 | 2546 | *len = 0; |
michael@0 | 2547 | return NULL; |
michael@0 | 2548 | } |
michael@0 | 2549 | |
michael@0 | 2550 | /* find the length of the number */ |
michael@0 | 2551 | for (count = 0; isxdigit(buf[count]); count++); |
michael@0 | 2552 | *len = count/2; |
michael@0 | 2553 | |
michael@0 | 2554 | if (*len == 0) { |
michael@0 | 2555 | return NULL; |
michael@0 | 2556 | } |
michael@0 | 2557 | |
michael@0 | 2558 | value = PORT_Alloc(*len); |
michael@0 | 2559 | if (!value) { |
michael@0 | 2560 | *len = 0; |
michael@0 | 2561 | return NULL; |
michael@0 | 2562 | } |
michael@0 | 2563 | |
michael@0 | 2564 | for (i=0; i<*len; buf+=2 , i++) { |
michael@0 | 2565 | hex_to_byteval(buf, &value[i]); |
michael@0 | 2566 | } |
michael@0 | 2567 | |
michael@0 | 2568 | |
michael@0 | 2569 | return value; |
michael@0 | 2570 | } |
michael@0 | 2571 | |
michael@0 | 2572 | PRBool |
michael@0 | 2573 | isblankline(char *b) |
michael@0 | 2574 | { |
michael@0 | 2575 | while (isspace(*b)) b++; |
michael@0 | 2576 | if ((*b == '\n') || (*b == 0)) { |
michael@0 | 2577 | return PR_TRUE; |
michael@0 | 2578 | } |
michael@0 | 2579 | return PR_FALSE; |
michael@0 | 2580 | } |
michael@0 | 2581 | |
michael@0 | 2582 | static int debug = 0; |
michael@0 | 2583 | |
michael@0 | 2584 | /* |
michael@0 | 2585 | * Perform the Hash_DRBG (CAVS) for the RNG algorithm |
michael@0 | 2586 | * |
michael@0 | 2587 | * reqfn is the pathname of the REQUEST file. |
michael@0 | 2588 | * |
michael@0 | 2589 | * The output RESPONSE file is written to stdout. |
michael@0 | 2590 | */ |
michael@0 | 2591 | void |
michael@0 | 2592 | drbg(char *reqfn) |
michael@0 | 2593 | { |
michael@0 | 2594 | char buf[2000]; /* test case has some very long lines, returned bits |
michael@0 | 2595 | * as high as 800 bytes (6400 bits). That 1600 byte |
michael@0 | 2596 | * plus a tag */ |
michael@0 | 2597 | char buf2[2000]; |
michael@0 | 2598 | FILE *rngreq; /* input stream from the REQUEST file */ |
michael@0 | 2599 | FILE *rngresp; /* output stream to the RESPONSE file */ |
michael@0 | 2600 | |
michael@0 | 2601 | unsigned int i, j; |
michael@0 | 2602 | PRBool predictionResistance = PR_FALSE; |
michael@0 | 2603 | unsigned char *nonce = NULL; |
michael@0 | 2604 | int nonceLen = 0; |
michael@0 | 2605 | unsigned char *personalizationString = NULL; |
michael@0 | 2606 | int personalizationStringLen = 0; |
michael@0 | 2607 | unsigned char *additionalInput = NULL; |
michael@0 | 2608 | int additionalInputLen = 0; |
michael@0 | 2609 | unsigned char *entropyInput = NULL; |
michael@0 | 2610 | int entropyInputLen = 0; |
michael@0 | 2611 | unsigned char predictedreturn_bytes[SHA256_LENGTH]; |
michael@0 | 2612 | unsigned char return_bytes[SHA256_LENGTH]; |
michael@0 | 2613 | int return_bytes_len = SHA256_LENGTH; |
michael@0 | 2614 | enum { NONE, INSTANTIATE, GENERATE, RESEED, RESULT } command = |
michael@0 | 2615 | NONE; |
michael@0 | 2616 | PRBool genResult = PR_FALSE; |
michael@0 | 2617 | SECStatus rv; |
michael@0 | 2618 | |
michael@0 | 2619 | rngreq = fopen(reqfn, "r"); |
michael@0 | 2620 | rngresp = stdout; |
michael@0 | 2621 | while (fgets(buf, sizeof buf, rngreq) != NULL) { |
michael@0 | 2622 | switch (command) { |
michael@0 | 2623 | case INSTANTIATE: |
michael@0 | 2624 | if (debug) { |
michael@0 | 2625 | fputs("# PRNGTEST_Instantiate(",rngresp); |
michael@0 | 2626 | to_hex_str(buf2,entropyInput, entropyInputLen); |
michael@0 | 2627 | fputs(buf2,rngresp); |
michael@0 | 2628 | fprintf(rngresp,",%d,",entropyInputLen); |
michael@0 | 2629 | to_hex_str(buf2,nonce, nonceLen); |
michael@0 | 2630 | fputs(buf2,rngresp); |
michael@0 | 2631 | fprintf(rngresp,",%d,",nonceLen); |
michael@0 | 2632 | to_hex_str(buf2,personalizationString, |
michael@0 | 2633 | personalizationStringLen); |
michael@0 | 2634 | fputs(buf2,rngresp); |
michael@0 | 2635 | fprintf(rngresp,",%d)\n", personalizationStringLen); |
michael@0 | 2636 | } |
michael@0 | 2637 | rv = PRNGTEST_Instantiate(entropyInput, entropyInputLen, |
michael@0 | 2638 | nonce, nonceLen, |
michael@0 | 2639 | personalizationString, |
michael@0 | 2640 | personalizationStringLen); |
michael@0 | 2641 | if (rv != SECSuccess) { |
michael@0 | 2642 | goto loser; |
michael@0 | 2643 | } |
michael@0 | 2644 | break; |
michael@0 | 2645 | |
michael@0 | 2646 | case GENERATE: |
michael@0 | 2647 | case RESULT: |
michael@0 | 2648 | memset(return_bytes, 0, return_bytes_len); |
michael@0 | 2649 | if (debug) { |
michael@0 | 2650 | fputs("# PRNGTEST_Generate(returnbytes",rngresp); |
michael@0 | 2651 | fprintf(rngresp,",%d,", return_bytes_len); |
michael@0 | 2652 | to_hex_str(buf2,additionalInput, additionalInputLen); |
michael@0 | 2653 | fputs(buf2,rngresp); |
michael@0 | 2654 | fprintf(rngresp,",%d)\n",additionalInputLen); |
michael@0 | 2655 | } |
michael@0 | 2656 | rv = PRNGTEST_Generate((PRUint8 *) return_bytes, |
michael@0 | 2657 | return_bytes_len, |
michael@0 | 2658 | (PRUint8 *) additionalInput, |
michael@0 | 2659 | additionalInputLen); |
michael@0 | 2660 | if (rv != SECSuccess) { |
michael@0 | 2661 | goto loser; |
michael@0 | 2662 | } |
michael@0 | 2663 | |
michael@0 | 2664 | if (command == RESULT) { |
michael@0 | 2665 | fputs("ReturnedBits = ", rngresp); |
michael@0 | 2666 | to_hex_str(buf2, return_bytes, return_bytes_len); |
michael@0 | 2667 | fputs(buf2, rngresp); |
michael@0 | 2668 | fputc('\n', rngresp); |
michael@0 | 2669 | if (debug) { |
michael@0 | 2670 | fputs("# PRNGTEST_Uninstantiate()\n",rngresp); |
michael@0 | 2671 | } |
michael@0 | 2672 | rv = PRNGTEST_Uninstantiate(); |
michael@0 | 2673 | if (rv != SECSuccess) { |
michael@0 | 2674 | goto loser; |
michael@0 | 2675 | } |
michael@0 | 2676 | } else if (debug) { |
michael@0 | 2677 | fputs("#ReturnedBits = ", rngresp); |
michael@0 | 2678 | to_hex_str(buf2, return_bytes, return_bytes_len); |
michael@0 | 2679 | fputs(buf2, rngresp); |
michael@0 | 2680 | fputc('\n', rngresp); |
michael@0 | 2681 | } |
michael@0 | 2682 | |
michael@0 | 2683 | memset(additionalInput, 0, additionalInputLen); |
michael@0 | 2684 | break; |
michael@0 | 2685 | |
michael@0 | 2686 | case RESEED: |
michael@0 | 2687 | if (entropyInput || additionalInput) { |
michael@0 | 2688 | if (debug) { |
michael@0 | 2689 | fputs("# PRNGTEST_Reseed(",rngresp); |
michael@0 | 2690 | fprintf(rngresp,",%d,", return_bytes_len); |
michael@0 | 2691 | to_hex_str(buf2,entropyInput, entropyInputLen); |
michael@0 | 2692 | fputs(buf2,rngresp); |
michael@0 | 2693 | fprintf(rngresp,",%d,", entropyInputLen); |
michael@0 | 2694 | to_hex_str(buf2,additionalInput, additionalInputLen); |
michael@0 | 2695 | fputs(buf2,rngresp); |
michael@0 | 2696 | fprintf(rngresp,",%d)\n",additionalInputLen); |
michael@0 | 2697 | } |
michael@0 | 2698 | rv = PRNGTEST_Reseed(entropyInput, entropyInputLen, |
michael@0 | 2699 | additionalInput, additionalInputLen); |
michael@0 | 2700 | if (rv != SECSuccess) { |
michael@0 | 2701 | goto loser; |
michael@0 | 2702 | } |
michael@0 | 2703 | } |
michael@0 | 2704 | memset(entropyInput, 0, entropyInputLen); |
michael@0 | 2705 | memset(additionalInput, 0, additionalInputLen); |
michael@0 | 2706 | break; |
michael@0 | 2707 | case NONE: |
michael@0 | 2708 | break; |
michael@0 | 2709 | |
michael@0 | 2710 | } |
michael@0 | 2711 | command = NONE; |
michael@0 | 2712 | |
michael@0 | 2713 | /* a comment or blank line */ |
michael@0 | 2714 | if (buf[0] == '#' || buf[0] == '\n' || buf[0] == '\r' ) { |
michael@0 | 2715 | fputs(buf, rngresp); |
michael@0 | 2716 | continue; |
michael@0 | 2717 | } |
michael@0 | 2718 | |
michael@0 | 2719 | /* [Hash - SHA256] */ |
michael@0 | 2720 | if (strncmp(buf, "[SHA-256]", 9) == 0) { |
michael@0 | 2721 | fputs(buf, rngresp); |
michael@0 | 2722 | continue; |
michael@0 | 2723 | } |
michael@0 | 2724 | |
michael@0 | 2725 | if (strncmp(buf, "[PredictionResistance", 21) == 0) { |
michael@0 | 2726 | i = 21; |
michael@0 | 2727 | while (isspace(buf[i]) || buf[i] == '=') { |
michael@0 | 2728 | i++; |
michael@0 | 2729 | } |
michael@0 | 2730 | if (strncmp(buf, "False", 5) == 0) { |
michael@0 | 2731 | predictionResistance = PR_FALSE; |
michael@0 | 2732 | } else { |
michael@0 | 2733 | predictionResistance = PR_TRUE; |
michael@0 | 2734 | } |
michael@0 | 2735 | |
michael@0 | 2736 | fputs(buf, rngresp); |
michael@0 | 2737 | continue; |
michael@0 | 2738 | } |
michael@0 | 2739 | |
michael@0 | 2740 | if (strncmp(buf, "[EntropyInputLen", 16) == 0) { |
michael@0 | 2741 | if (entropyInput) { |
michael@0 | 2742 | PORT_ZFree(entropyInput, entropyInputLen); |
michael@0 | 2743 | entropyInput = NULL; |
michael@0 | 2744 | entropyInputLen = 0; |
michael@0 | 2745 | } |
michael@0 | 2746 | if (sscanf(buf, "[EntropyInputLen = %d]", &entropyInputLen) != 1) { |
michael@0 | 2747 | goto loser; |
michael@0 | 2748 | } |
michael@0 | 2749 | entropyInputLen = entropyInputLen/8; |
michael@0 | 2750 | if (entropyInputLen > 0) { |
michael@0 | 2751 | entropyInput = PORT_Alloc(entropyInputLen); |
michael@0 | 2752 | } |
michael@0 | 2753 | fputs(buf, rngresp); |
michael@0 | 2754 | continue; |
michael@0 | 2755 | } |
michael@0 | 2756 | |
michael@0 | 2757 | if (strncmp(buf, "[NonceLen", 9) == 0) { |
michael@0 | 2758 | if (nonce) { |
michael@0 | 2759 | PORT_ZFree(nonce, nonceLen); |
michael@0 | 2760 | nonce = NULL; |
michael@0 | 2761 | nonceLen = 0; |
michael@0 | 2762 | } |
michael@0 | 2763 | |
michael@0 | 2764 | if (sscanf(buf, "[NonceLen = %d]", &nonceLen) != 1) { |
michael@0 | 2765 | goto loser; |
michael@0 | 2766 | } |
michael@0 | 2767 | nonceLen = nonceLen/8; |
michael@0 | 2768 | if (nonceLen > 0) { |
michael@0 | 2769 | nonce = PORT_Alloc(nonceLen); |
michael@0 | 2770 | } |
michael@0 | 2771 | fputs(buf, rngresp); |
michael@0 | 2772 | continue; |
michael@0 | 2773 | } |
michael@0 | 2774 | |
michael@0 | 2775 | if (strncmp(buf, "[PersonalizationStringLen", 16) == 0) { |
michael@0 | 2776 | if (personalizationString) { |
michael@0 | 2777 | PORT_ZFree(personalizationString, personalizationStringLen); |
michael@0 | 2778 | personalizationString = NULL; |
michael@0 | 2779 | personalizationStringLen = 0; |
michael@0 | 2780 | } |
michael@0 | 2781 | |
michael@0 | 2782 | if (sscanf(buf, "[PersonalizationStringLen = %d]", &personalizationStringLen) != 1) { |
michael@0 | 2783 | goto loser; |
michael@0 | 2784 | } |
michael@0 | 2785 | personalizationStringLen = personalizationStringLen / 8; |
michael@0 | 2786 | if (personalizationStringLen > 0) { |
michael@0 | 2787 | personalizationString = PORT_Alloc(personalizationStringLen); |
michael@0 | 2788 | } |
michael@0 | 2789 | fputs(buf, rngresp); |
michael@0 | 2790 | |
michael@0 | 2791 | continue; |
michael@0 | 2792 | } |
michael@0 | 2793 | |
michael@0 | 2794 | if (strncmp(buf, "[AdditionalInputLen", 16) == 0) { |
michael@0 | 2795 | if (additionalInput) { |
michael@0 | 2796 | PORT_ZFree(additionalInput, additionalInputLen); |
michael@0 | 2797 | additionalInput = NULL; |
michael@0 | 2798 | additionalInputLen = 0; |
michael@0 | 2799 | } |
michael@0 | 2800 | |
michael@0 | 2801 | if (sscanf(buf, "[AdditionalInputLen = %d]", &additionalInputLen) != 1) { |
michael@0 | 2802 | goto loser; |
michael@0 | 2803 | } |
michael@0 | 2804 | additionalInputLen = additionalInputLen/8; |
michael@0 | 2805 | if (additionalInputLen > 0) { |
michael@0 | 2806 | additionalInput = PORT_Alloc(additionalInputLen); |
michael@0 | 2807 | } |
michael@0 | 2808 | fputs(buf, rngresp); |
michael@0 | 2809 | continue; |
michael@0 | 2810 | } |
michael@0 | 2811 | |
michael@0 | 2812 | if (strncmp(buf, "COUNT", 5) == 0) { |
michael@0 | 2813 | /* zeroize the variables for the test with this data set */ |
michael@0 | 2814 | if (entropyInput) { |
michael@0 | 2815 | memset(entropyInput, 0, entropyInputLen); |
michael@0 | 2816 | } |
michael@0 | 2817 | if (nonce) { |
michael@0 | 2818 | memset(nonce, 0, nonceLen); |
michael@0 | 2819 | } |
michael@0 | 2820 | if (personalizationString) { |
michael@0 | 2821 | memset(personalizationString, 0, personalizationStringLen); |
michael@0 | 2822 | } |
michael@0 | 2823 | if (additionalInput) { |
michael@0 | 2824 | memset(additionalInput, 0, additionalInputLen); |
michael@0 | 2825 | } |
michael@0 | 2826 | genResult = PR_FALSE; |
michael@0 | 2827 | |
michael@0 | 2828 | fputs(buf, rngresp); |
michael@0 | 2829 | continue; |
michael@0 | 2830 | } |
michael@0 | 2831 | |
michael@0 | 2832 | /* EntropyInputReseed = ... */ |
michael@0 | 2833 | if (strncmp(buf, "EntropyInputReseed", 18) == 0) { |
michael@0 | 2834 | if (entropyInput) { |
michael@0 | 2835 | memset(entropyInput, 0, entropyInputLen); |
michael@0 | 2836 | i = 18; |
michael@0 | 2837 | while (isspace(buf[i]) || buf[i] == '=') { |
michael@0 | 2838 | i++; |
michael@0 | 2839 | } |
michael@0 | 2840 | |
michael@0 | 2841 | for (j=0; isxdigit(buf[i]); i+=2,j++) { /*j<entropyInputLen*/ |
michael@0 | 2842 | hex_to_byteval(&buf[i], &entropyInput[j]); |
michael@0 | 2843 | } |
michael@0 | 2844 | } |
michael@0 | 2845 | fputs(buf, rngresp); |
michael@0 | 2846 | continue; |
michael@0 | 2847 | } |
michael@0 | 2848 | |
michael@0 | 2849 | /* AttionalInputReseed = ... */ |
michael@0 | 2850 | if (strncmp(buf, "AdditionalInputReseed", 21) == 0) { |
michael@0 | 2851 | if (additionalInput) { |
michael@0 | 2852 | memset(additionalInput, 0, additionalInputLen); |
michael@0 | 2853 | i = 21; |
michael@0 | 2854 | while (isspace(buf[i]) || buf[i] == '=') { |
michael@0 | 2855 | i++; |
michael@0 | 2856 | } |
michael@0 | 2857 | for (j=0; isxdigit(buf[i]); i+=2,j++) { /*j<additionalInputLen*/ |
michael@0 | 2858 | hex_to_byteval(&buf[i], &additionalInput[j]); |
michael@0 | 2859 | } |
michael@0 | 2860 | } |
michael@0 | 2861 | command = RESEED; |
michael@0 | 2862 | fputs(buf, rngresp); |
michael@0 | 2863 | continue; |
michael@0 | 2864 | } |
michael@0 | 2865 | |
michael@0 | 2866 | /* Entropy input = ... */ |
michael@0 | 2867 | if (strncmp(buf, "EntropyInput", 12) == 0) { |
michael@0 | 2868 | i = 12; |
michael@0 | 2869 | while (isspace(buf[i]) || buf[i] == '=') { |
michael@0 | 2870 | i++; |
michael@0 | 2871 | } |
michael@0 | 2872 | for (j=0; isxdigit(buf[i]); i+=2,j++) { /*j<entropyInputLen*/ |
michael@0 | 2873 | hex_to_byteval(&buf[i], &entropyInput[j]); |
michael@0 | 2874 | } |
michael@0 | 2875 | fputs(buf, rngresp); |
michael@0 | 2876 | continue; |
michael@0 | 2877 | } |
michael@0 | 2878 | |
michael@0 | 2879 | /* nouce = ... */ |
michael@0 | 2880 | if (strncmp(buf, "Nonce", 5) == 0) { |
michael@0 | 2881 | i = 5; |
michael@0 | 2882 | while (isspace(buf[i]) || buf[i] == '=') { |
michael@0 | 2883 | i++; |
michael@0 | 2884 | } |
michael@0 | 2885 | for (j=0; isxdigit(buf[i]); i+=2,j++) { /*j<nonceLen*/ |
michael@0 | 2886 | hex_to_byteval(&buf[i], &nonce[j]); |
michael@0 | 2887 | } |
michael@0 | 2888 | fputs(buf, rngresp); |
michael@0 | 2889 | continue; |
michael@0 | 2890 | } |
michael@0 | 2891 | |
michael@0 | 2892 | /* Personalization string = ... */ |
michael@0 | 2893 | if (strncmp(buf, "PersonalizationString", 21) == 0) { |
michael@0 | 2894 | if (personalizationString) { |
michael@0 | 2895 | i = 21; |
michael@0 | 2896 | while (isspace(buf[i]) || buf[i] == '=') { |
michael@0 | 2897 | i++; |
michael@0 | 2898 | } |
michael@0 | 2899 | for (j=0; isxdigit(buf[i]); i+=2,j++) { /*j<personalizationStringLen*/ |
michael@0 | 2900 | hex_to_byteval(&buf[i], &personalizationString[j]); |
michael@0 | 2901 | } |
michael@0 | 2902 | } |
michael@0 | 2903 | fputs(buf, rngresp); |
michael@0 | 2904 | command = INSTANTIATE; |
michael@0 | 2905 | continue; |
michael@0 | 2906 | } |
michael@0 | 2907 | |
michael@0 | 2908 | /* Additional input = ... */ |
michael@0 | 2909 | if (strncmp(buf, "AdditionalInput", 15) == 0) { |
michael@0 | 2910 | if (additionalInput) { |
michael@0 | 2911 | i = 15; |
michael@0 | 2912 | while (isspace(buf[i]) || buf[i] == '=') { |
michael@0 | 2913 | i++; |
michael@0 | 2914 | } |
michael@0 | 2915 | for (j=0; isxdigit(buf[i]); i+=2,j++) { /*j<additionalInputLen*/ |
michael@0 | 2916 | hex_to_byteval(&buf[i], &additionalInput[j]); |
michael@0 | 2917 | } |
michael@0 | 2918 | } |
michael@0 | 2919 | if (genResult) { |
michael@0 | 2920 | command = RESULT; |
michael@0 | 2921 | } else { |
michael@0 | 2922 | command = GENERATE; |
michael@0 | 2923 | genResult = PR_TRUE; /* next time generate result */ |
michael@0 | 2924 | } |
michael@0 | 2925 | fputs(buf, rngresp); |
michael@0 | 2926 | continue; |
michael@0 | 2927 | } |
michael@0 | 2928 | |
michael@0 | 2929 | /* Returned bits = ... */ |
michael@0 | 2930 | if (strncmp(buf, "ReturnedBits", 12) == 0) { |
michael@0 | 2931 | i = 12; |
michael@0 | 2932 | while (isspace(buf[i]) || buf[i] == '=') { |
michael@0 | 2933 | i++; |
michael@0 | 2934 | } |
michael@0 | 2935 | for (j=0; isxdigit(buf[i]); i+=2,j++) { /*j<additionalInputLen*/ |
michael@0 | 2936 | hex_to_byteval(&buf[i], &predictedreturn_bytes[j]); |
michael@0 | 2937 | } |
michael@0 | 2938 | |
michael@0 | 2939 | if (memcmp(return_bytes, |
michael@0 | 2940 | predictedreturn_bytes, return_bytes_len) != 0) { |
michael@0 | 2941 | if (debug) { |
michael@0 | 2942 | fprintf(rngresp, "# Generate failed:\n"); |
michael@0 | 2943 | fputs( "# predicted=", rngresp); |
michael@0 | 2944 | to_hex_str(buf, predictedreturn_bytes, |
michael@0 | 2945 | return_bytes_len); |
michael@0 | 2946 | fputs(buf, rngresp); |
michael@0 | 2947 | fputs("\n# actual = ", rngresp); |
michael@0 | 2948 | fputs(buf2, rngresp); |
michael@0 | 2949 | fputc('\n', rngresp); |
michael@0 | 2950 | |
michael@0 | 2951 | } else { |
michael@0 | 2952 | fprintf(stderr, "Generate failed:\n"); |
michael@0 | 2953 | fputs( " predicted=", stderr); |
michael@0 | 2954 | to_hex_str(buf, predictedreturn_bytes, |
michael@0 | 2955 | return_bytes_len); |
michael@0 | 2956 | fputs(buf, stderr); |
michael@0 | 2957 | fputs("\n actual = ", stderr); |
michael@0 | 2958 | fputs(buf2, stderr); |
michael@0 | 2959 | fputc('\n', stderr); |
michael@0 | 2960 | } |
michael@0 | 2961 | } |
michael@0 | 2962 | memset(predictedreturn_bytes, 0 , sizeof predictedreturn_bytes); |
michael@0 | 2963 | |
michael@0 | 2964 | continue; |
michael@0 | 2965 | } |
michael@0 | 2966 | } |
michael@0 | 2967 | loser: |
michael@0 | 2968 | fclose(rngreq); |
michael@0 | 2969 | } |
michael@0 | 2970 | |
michael@0 | 2971 | /* |
michael@0 | 2972 | * Perform the RNG Variable Seed Test (VST) for the RNG algorithm |
michael@0 | 2973 | * "DSA - Generation of X", used both as specified and as a generic |
michael@0 | 2974 | * purpose RNG. The presence of "Q = ..." in the REQUEST file |
michael@0 | 2975 | * indicates we are using the algorithm as specified. |
michael@0 | 2976 | * |
michael@0 | 2977 | * reqfn is the pathname of the REQUEST file. |
michael@0 | 2978 | * |
michael@0 | 2979 | * The output RESPONSE file is written to stdout. |
michael@0 | 2980 | */ |
michael@0 | 2981 | void |
michael@0 | 2982 | rng_vst(char *reqfn) |
michael@0 | 2983 | { |
michael@0 | 2984 | char buf[256]; /* holds one line from the input REQUEST file. |
michael@0 | 2985 | * needs to be large enough to hold the longest |
michael@0 | 2986 | * line "XSeed = <128 hex digits>\n". |
michael@0 | 2987 | */ |
michael@0 | 2988 | FILE *rngreq; /* input stream from the REQUEST file */ |
michael@0 | 2989 | FILE *rngresp; /* output stream to the RESPONSE file */ |
michael@0 | 2990 | unsigned int i, j; |
michael@0 | 2991 | unsigned char Q[DSA1_SUBPRIME_LEN]; |
michael@0 | 2992 | PRBool hasQ = PR_FALSE; |
michael@0 | 2993 | unsigned int b; /* 160 <= b <= 512, b is a multiple of 8 */ |
michael@0 | 2994 | unsigned char XKey[512/8]; |
michael@0 | 2995 | unsigned char XSeed[512/8]; |
michael@0 | 2996 | unsigned char GENX[DSA1_SIGNATURE_LEN]; |
michael@0 | 2997 | unsigned char DSAX[DSA1_SUBPRIME_LEN]; |
michael@0 | 2998 | SECStatus rv; |
michael@0 | 2999 | |
michael@0 | 3000 | rngreq = fopen(reqfn, "r"); |
michael@0 | 3001 | rngresp = stdout; |
michael@0 | 3002 | while (fgets(buf, sizeof buf, rngreq) != NULL) { |
michael@0 | 3003 | /* a comment or blank line */ |
michael@0 | 3004 | if (buf[0] == '#' || buf[0] == '\n') { |
michael@0 | 3005 | fputs(buf, rngresp); |
michael@0 | 3006 | continue; |
michael@0 | 3007 | } |
michael@0 | 3008 | /* [Xchange - SHA1] */ |
michael@0 | 3009 | if (buf[0] == '[') { |
michael@0 | 3010 | fputs(buf, rngresp); |
michael@0 | 3011 | continue; |
michael@0 | 3012 | } |
michael@0 | 3013 | /* Q = ... */ |
michael@0 | 3014 | if (buf[0] == 'Q') { |
michael@0 | 3015 | i = 1; |
michael@0 | 3016 | while (isspace(buf[i]) || buf[i] == '=') { |
michael@0 | 3017 | i++; |
michael@0 | 3018 | } |
michael@0 | 3019 | for (j=0; j<sizeof Q; i+=2,j++) { |
michael@0 | 3020 | hex_to_byteval(&buf[i], &Q[j]); |
michael@0 | 3021 | } |
michael@0 | 3022 | fputs(buf, rngresp); |
michael@0 | 3023 | hasQ = PR_TRUE; |
michael@0 | 3024 | continue; |
michael@0 | 3025 | } |
michael@0 | 3026 | /* "COUNT = x" begins a new data set */ |
michael@0 | 3027 | if (strncmp(buf, "COUNT", 5) == 0) { |
michael@0 | 3028 | /* zeroize the variables for the test with this data set */ |
michael@0 | 3029 | b = 0; |
michael@0 | 3030 | memset(XKey, 0, sizeof XKey); |
michael@0 | 3031 | memset(XSeed, 0, sizeof XSeed); |
michael@0 | 3032 | fputs(buf, rngresp); |
michael@0 | 3033 | continue; |
michael@0 | 3034 | } |
michael@0 | 3035 | /* b = ... */ |
michael@0 | 3036 | if (buf[0] == 'b') { |
michael@0 | 3037 | i = 1; |
michael@0 | 3038 | while (isspace(buf[i]) || buf[i] == '=') { |
michael@0 | 3039 | i++; |
michael@0 | 3040 | } |
michael@0 | 3041 | b = atoi(&buf[i]); |
michael@0 | 3042 | if (b < 160 || b > 512 || b%8 != 0) { |
michael@0 | 3043 | goto loser; |
michael@0 | 3044 | } |
michael@0 | 3045 | fputs(buf, rngresp); |
michael@0 | 3046 | continue; |
michael@0 | 3047 | } |
michael@0 | 3048 | /* XKey = ... */ |
michael@0 | 3049 | if (strncmp(buf, "XKey", 4) == 0) { |
michael@0 | 3050 | i = 4; |
michael@0 | 3051 | while (isspace(buf[i]) || buf[i] == '=') { |
michael@0 | 3052 | i++; |
michael@0 | 3053 | } |
michael@0 | 3054 | for (j=0; j<b/8; i+=2,j++) { |
michael@0 | 3055 | hex_to_byteval(&buf[i], &XKey[j]); |
michael@0 | 3056 | } |
michael@0 | 3057 | fputs(buf, rngresp); |
michael@0 | 3058 | continue; |
michael@0 | 3059 | } |
michael@0 | 3060 | /* XSeed = ... */ |
michael@0 | 3061 | if (strncmp(buf, "XSeed", 5) == 0) { |
michael@0 | 3062 | i = 5; |
michael@0 | 3063 | while (isspace(buf[i]) || buf[i] == '=') { |
michael@0 | 3064 | i++; |
michael@0 | 3065 | } |
michael@0 | 3066 | for (j=0; j<b/8; i+=2,j++) { |
michael@0 | 3067 | hex_to_byteval(&buf[i], &XSeed[j]); |
michael@0 | 3068 | } |
michael@0 | 3069 | fputs(buf, rngresp); |
michael@0 | 3070 | |
michael@0 | 3071 | rv = FIPS186Change_GenerateX(XKey, XSeed, GENX); |
michael@0 | 3072 | if (rv != SECSuccess) { |
michael@0 | 3073 | goto loser; |
michael@0 | 3074 | } |
michael@0 | 3075 | fputs("X = ", rngresp); |
michael@0 | 3076 | if (hasQ) { |
michael@0 | 3077 | rv = FIPS186Change_ReduceModQForDSA(GENX, Q, DSAX); |
michael@0 | 3078 | if (rv != SECSuccess) { |
michael@0 | 3079 | goto loser; |
michael@0 | 3080 | } |
michael@0 | 3081 | to_hex_str(buf, DSAX, sizeof DSAX); |
michael@0 | 3082 | } else { |
michael@0 | 3083 | to_hex_str(buf, GENX, sizeof GENX); |
michael@0 | 3084 | } |
michael@0 | 3085 | fputs(buf, rngresp); |
michael@0 | 3086 | fputc('\n', rngresp); |
michael@0 | 3087 | continue; |
michael@0 | 3088 | } |
michael@0 | 3089 | } |
michael@0 | 3090 | loser: |
michael@0 | 3091 | fclose(rngreq); |
michael@0 | 3092 | } |
michael@0 | 3093 | |
michael@0 | 3094 | /* |
michael@0 | 3095 | * Perform the RNG Monte Carlo Test (MCT) for the RNG algorithm |
michael@0 | 3096 | * "DSA - Generation of X", used both as specified and as a generic |
michael@0 | 3097 | * purpose RNG. The presence of "Q = ..." in the REQUEST file |
michael@0 | 3098 | * indicates we are using the algorithm as specified. |
michael@0 | 3099 | * |
michael@0 | 3100 | * reqfn is the pathname of the REQUEST file. |
michael@0 | 3101 | * |
michael@0 | 3102 | * The output RESPONSE file is written to stdout. |
michael@0 | 3103 | */ |
michael@0 | 3104 | void |
michael@0 | 3105 | rng_mct(char *reqfn) |
michael@0 | 3106 | { |
michael@0 | 3107 | char buf[256]; /* holds one line from the input REQUEST file. |
michael@0 | 3108 | * needs to be large enough to hold the longest |
michael@0 | 3109 | * line "XSeed = <128 hex digits>\n". |
michael@0 | 3110 | */ |
michael@0 | 3111 | FILE *rngreq; /* input stream from the REQUEST file */ |
michael@0 | 3112 | FILE *rngresp; /* output stream to the RESPONSE file */ |
michael@0 | 3113 | unsigned int i, j; |
michael@0 | 3114 | unsigned char Q[DSA1_SUBPRIME_LEN]; |
michael@0 | 3115 | PRBool hasQ = PR_FALSE; |
michael@0 | 3116 | unsigned int b; /* 160 <= b <= 512, b is a multiple of 8 */ |
michael@0 | 3117 | unsigned char XKey[512/8]; |
michael@0 | 3118 | unsigned char XSeed[512/8]; |
michael@0 | 3119 | unsigned char GENX[2*SHA1_LENGTH]; |
michael@0 | 3120 | unsigned char DSAX[DSA1_SUBPRIME_LEN]; |
michael@0 | 3121 | SECStatus rv; |
michael@0 | 3122 | |
michael@0 | 3123 | rngreq = fopen(reqfn, "r"); |
michael@0 | 3124 | rngresp = stdout; |
michael@0 | 3125 | while (fgets(buf, sizeof buf, rngreq) != NULL) { |
michael@0 | 3126 | /* a comment or blank line */ |
michael@0 | 3127 | if (buf[0] == '#' || buf[0] == '\n') { |
michael@0 | 3128 | fputs(buf, rngresp); |
michael@0 | 3129 | continue; |
michael@0 | 3130 | } |
michael@0 | 3131 | /* [Xchange - SHA1] */ |
michael@0 | 3132 | if (buf[0] == '[') { |
michael@0 | 3133 | fputs(buf, rngresp); |
michael@0 | 3134 | continue; |
michael@0 | 3135 | } |
michael@0 | 3136 | /* Q = ... */ |
michael@0 | 3137 | if (buf[0] == 'Q') { |
michael@0 | 3138 | i = 1; |
michael@0 | 3139 | while (isspace(buf[i]) || buf[i] == '=') { |
michael@0 | 3140 | i++; |
michael@0 | 3141 | } |
michael@0 | 3142 | for (j=0; j<sizeof Q; i+=2,j++) { |
michael@0 | 3143 | hex_to_byteval(&buf[i], &Q[j]); |
michael@0 | 3144 | } |
michael@0 | 3145 | fputs(buf, rngresp); |
michael@0 | 3146 | hasQ = PR_TRUE; |
michael@0 | 3147 | continue; |
michael@0 | 3148 | } |
michael@0 | 3149 | /* "COUNT = x" begins a new data set */ |
michael@0 | 3150 | if (strncmp(buf, "COUNT", 5) == 0) { |
michael@0 | 3151 | /* zeroize the variables for the test with this data set */ |
michael@0 | 3152 | b = 0; |
michael@0 | 3153 | memset(XKey, 0, sizeof XKey); |
michael@0 | 3154 | memset(XSeed, 0, sizeof XSeed); |
michael@0 | 3155 | fputs(buf, rngresp); |
michael@0 | 3156 | continue; |
michael@0 | 3157 | } |
michael@0 | 3158 | /* b = ... */ |
michael@0 | 3159 | if (buf[0] == 'b') { |
michael@0 | 3160 | i = 1; |
michael@0 | 3161 | while (isspace(buf[i]) || buf[i] == '=') { |
michael@0 | 3162 | i++; |
michael@0 | 3163 | } |
michael@0 | 3164 | b = atoi(&buf[i]); |
michael@0 | 3165 | if (b < 160 || b > 512 || b%8 != 0) { |
michael@0 | 3166 | goto loser; |
michael@0 | 3167 | } |
michael@0 | 3168 | fputs(buf, rngresp); |
michael@0 | 3169 | continue; |
michael@0 | 3170 | } |
michael@0 | 3171 | /* XKey = ... */ |
michael@0 | 3172 | if (strncmp(buf, "XKey", 4) == 0) { |
michael@0 | 3173 | i = 4; |
michael@0 | 3174 | while (isspace(buf[i]) || buf[i] == '=') { |
michael@0 | 3175 | i++; |
michael@0 | 3176 | } |
michael@0 | 3177 | for (j=0; j<b/8; i+=2,j++) { |
michael@0 | 3178 | hex_to_byteval(&buf[i], &XKey[j]); |
michael@0 | 3179 | } |
michael@0 | 3180 | fputs(buf, rngresp); |
michael@0 | 3181 | continue; |
michael@0 | 3182 | } |
michael@0 | 3183 | /* XSeed = ... */ |
michael@0 | 3184 | if (strncmp(buf, "XSeed", 5) == 0) { |
michael@0 | 3185 | unsigned int k; |
michael@0 | 3186 | i = 5; |
michael@0 | 3187 | while (isspace(buf[i]) || buf[i] == '=') { |
michael@0 | 3188 | i++; |
michael@0 | 3189 | } |
michael@0 | 3190 | for (j=0; j<b/8; i+=2,j++) { |
michael@0 | 3191 | hex_to_byteval(&buf[i], &XSeed[j]); |
michael@0 | 3192 | } |
michael@0 | 3193 | fputs(buf, rngresp); |
michael@0 | 3194 | |
michael@0 | 3195 | for (k = 0; k < 10000; k++) { |
michael@0 | 3196 | rv = FIPS186Change_GenerateX(XKey, XSeed, GENX); |
michael@0 | 3197 | if (rv != SECSuccess) { |
michael@0 | 3198 | goto loser; |
michael@0 | 3199 | } |
michael@0 | 3200 | } |
michael@0 | 3201 | fputs("X = ", rngresp); |
michael@0 | 3202 | if (hasQ) { |
michael@0 | 3203 | rv = FIPS186Change_ReduceModQForDSA(GENX, Q, DSAX); |
michael@0 | 3204 | if (rv != SECSuccess) { |
michael@0 | 3205 | goto loser; |
michael@0 | 3206 | } |
michael@0 | 3207 | to_hex_str(buf, DSAX, sizeof DSAX); |
michael@0 | 3208 | } else { |
michael@0 | 3209 | to_hex_str(buf, GENX, sizeof GENX); |
michael@0 | 3210 | } |
michael@0 | 3211 | fputs(buf, rngresp); |
michael@0 | 3212 | fputc('\n', rngresp); |
michael@0 | 3213 | continue; |
michael@0 | 3214 | } |
michael@0 | 3215 | } |
michael@0 | 3216 | loser: |
michael@0 | 3217 | fclose(rngreq); |
michael@0 | 3218 | } |
michael@0 | 3219 | |
michael@0 | 3220 | /* |
michael@0 | 3221 | * HASH_ functions are available to full NSS apps and internally inside |
michael@0 | 3222 | * freebl, but not exported to users of freebl. Create short stubs to |
michael@0 | 3223 | * replace the functionality for fipstest. |
michael@0 | 3224 | */ |
michael@0 | 3225 | SECStatus |
michael@0 | 3226 | fips_hashBuf(HASH_HashType type, unsigned char *hashBuf, |
michael@0 | 3227 | unsigned char *msg, int len) |
michael@0 | 3228 | { |
michael@0 | 3229 | SECStatus rv = SECFailure; |
michael@0 | 3230 | |
michael@0 | 3231 | switch (type) { |
michael@0 | 3232 | case HASH_AlgSHA1: |
michael@0 | 3233 | rv = SHA1_HashBuf(hashBuf, msg, len); |
michael@0 | 3234 | break; |
michael@0 | 3235 | case HASH_AlgSHA224: |
michael@0 | 3236 | rv = SHA224_HashBuf(hashBuf, msg, len); |
michael@0 | 3237 | break; |
michael@0 | 3238 | case HASH_AlgSHA256: |
michael@0 | 3239 | rv = SHA256_HashBuf(hashBuf, msg, len); |
michael@0 | 3240 | break; |
michael@0 | 3241 | case HASH_AlgSHA384: |
michael@0 | 3242 | rv = SHA384_HashBuf(hashBuf, msg, len); |
michael@0 | 3243 | break; |
michael@0 | 3244 | case HASH_AlgSHA512: |
michael@0 | 3245 | rv = SHA512_HashBuf(hashBuf, msg, len); |
michael@0 | 3246 | break; |
michael@0 | 3247 | default: |
michael@0 | 3248 | break; |
michael@0 | 3249 | } |
michael@0 | 3250 | return rv; |
michael@0 | 3251 | } |
michael@0 | 3252 | |
michael@0 | 3253 | int |
michael@0 | 3254 | fips_hashLen(HASH_HashType type) |
michael@0 | 3255 | { |
michael@0 | 3256 | int len = 0; |
michael@0 | 3257 | |
michael@0 | 3258 | switch (type) { |
michael@0 | 3259 | case HASH_AlgSHA1: |
michael@0 | 3260 | len = SHA1_LENGTH; |
michael@0 | 3261 | break; |
michael@0 | 3262 | case HASH_AlgSHA224: |
michael@0 | 3263 | len = SHA224_LENGTH; |
michael@0 | 3264 | break; |
michael@0 | 3265 | case HASH_AlgSHA256: |
michael@0 | 3266 | len = SHA256_LENGTH; |
michael@0 | 3267 | break; |
michael@0 | 3268 | case HASH_AlgSHA384: |
michael@0 | 3269 | len = SHA384_LENGTH; |
michael@0 | 3270 | break; |
michael@0 | 3271 | case HASH_AlgSHA512: |
michael@0 | 3272 | len = SHA512_LENGTH; |
michael@0 | 3273 | break; |
michael@0 | 3274 | default: |
michael@0 | 3275 | break; |
michael@0 | 3276 | } |
michael@0 | 3277 | return len; |
michael@0 | 3278 | } |
michael@0 | 3279 | |
michael@0 | 3280 | SECOidTag |
michael@0 | 3281 | fips_hashOid(HASH_HashType type) |
michael@0 | 3282 | { |
michael@0 | 3283 | SECOidTag oid = SEC_OID_UNKNOWN; |
michael@0 | 3284 | |
michael@0 | 3285 | switch (type) { |
michael@0 | 3286 | case HASH_AlgSHA1: |
michael@0 | 3287 | oid = SEC_OID_SHA1; |
michael@0 | 3288 | break; |
michael@0 | 3289 | case HASH_AlgSHA224: |
michael@0 | 3290 | oid = SEC_OID_SHA224; |
michael@0 | 3291 | break; |
michael@0 | 3292 | case HASH_AlgSHA256: |
michael@0 | 3293 | oid = SEC_OID_SHA256; |
michael@0 | 3294 | break; |
michael@0 | 3295 | case HASH_AlgSHA384: |
michael@0 | 3296 | oid = SEC_OID_SHA384; |
michael@0 | 3297 | break; |
michael@0 | 3298 | case HASH_AlgSHA512: |
michael@0 | 3299 | oid = SEC_OID_SHA512; |
michael@0 | 3300 | break; |
michael@0 | 3301 | default: |
michael@0 | 3302 | break; |
michael@0 | 3303 | } |
michael@0 | 3304 | return oid; |
michael@0 | 3305 | } |
michael@0 | 3306 | |
michael@0 | 3307 | HASH_HashType |
michael@0 | 3308 | sha_get_hashType(int hashbits) |
michael@0 | 3309 | { |
michael@0 | 3310 | HASH_HashType hashType = HASH_AlgNULL; |
michael@0 | 3311 | |
michael@0 | 3312 | switch (hashbits) { |
michael@0 | 3313 | case 1: |
michael@0 | 3314 | case (SHA1_LENGTH*PR_BITS_PER_BYTE): |
michael@0 | 3315 | hashType = HASH_AlgSHA1; |
michael@0 | 3316 | break; |
michael@0 | 3317 | case (SHA224_LENGTH*PR_BITS_PER_BYTE): |
michael@0 | 3318 | hashType = HASH_AlgSHA224; |
michael@0 | 3319 | break; |
michael@0 | 3320 | case (SHA256_LENGTH*PR_BITS_PER_BYTE): |
michael@0 | 3321 | hashType = HASH_AlgSHA256; |
michael@0 | 3322 | break; |
michael@0 | 3323 | case (SHA384_LENGTH*PR_BITS_PER_BYTE): |
michael@0 | 3324 | hashType = HASH_AlgSHA384; |
michael@0 | 3325 | break; |
michael@0 | 3326 | case (SHA512_LENGTH*PR_BITS_PER_BYTE): |
michael@0 | 3327 | hashType = HASH_AlgSHA512; |
michael@0 | 3328 | break; |
michael@0 | 3329 | default: |
michael@0 | 3330 | break; |
michael@0 | 3331 | } |
michael@0 | 3332 | return hashType; |
michael@0 | 3333 | } |
michael@0 | 3334 | |
michael@0 | 3335 | /* |
michael@0 | 3336 | * Calculate the SHA Message Digest |
michael@0 | 3337 | * |
michael@0 | 3338 | * MD = Message digest |
michael@0 | 3339 | * MDLen = length of Message Digest and SHA_Type |
michael@0 | 3340 | * msg = message to digest |
michael@0 | 3341 | * msgLen = length of message to digest |
michael@0 | 3342 | */ |
michael@0 | 3343 | SECStatus sha_calcMD(unsigned char *MD, unsigned int MDLen, unsigned char *msg, unsigned int msgLen) |
michael@0 | 3344 | { |
michael@0 | 3345 | HASH_HashType hashType = sha_get_hashType(MDLen*PR_BITS_PER_BYTE); |
michael@0 | 3346 | |
michael@0 | 3347 | return fips_hashBuf(hashType, MD, msg, msgLen); |
michael@0 | 3348 | } |
michael@0 | 3349 | |
michael@0 | 3350 | /* |
michael@0 | 3351 | * Perform the SHA Monte Carlo Test |
michael@0 | 3352 | * |
michael@0 | 3353 | * MDLen = length of Message Digest and SHA_Type |
michael@0 | 3354 | * seed = input seed value |
michael@0 | 3355 | * resp = is the output response file. |
michael@0 | 3356 | */ |
michael@0 | 3357 | SECStatus sha_mct_test(unsigned int MDLen, unsigned char *seed, FILE *resp) |
michael@0 | 3358 | { |
michael@0 | 3359 | int i, j; |
michael@0 | 3360 | unsigned int msgLen = MDLen*3; |
michael@0 | 3361 | unsigned char MD_i3[HASH_LENGTH_MAX]; /* MD[i-3] */ |
michael@0 | 3362 | unsigned char MD_i2[HASH_LENGTH_MAX]; /* MD[i-2] */ |
michael@0 | 3363 | unsigned char MD_i1[HASH_LENGTH_MAX]; /* MD[i-1] */ |
michael@0 | 3364 | unsigned char MD_i[HASH_LENGTH_MAX]; /* MD[i] */ |
michael@0 | 3365 | unsigned char msg[HASH_LENGTH_MAX*3]; |
michael@0 | 3366 | char buf[HASH_LENGTH_MAX*2 + 1]; /* MAX buf MD_i as a hex string */ |
michael@0 | 3367 | |
michael@0 | 3368 | for (j=0; j<100; j++) { |
michael@0 | 3369 | /* MD_0 = MD_1 = MD_2 = seed */ |
michael@0 | 3370 | memcpy(MD_i3, seed, MDLen); |
michael@0 | 3371 | memcpy(MD_i2, seed, MDLen); |
michael@0 | 3372 | memcpy(MD_i1, seed, MDLen); |
michael@0 | 3373 | |
michael@0 | 3374 | for (i=3; i < 1003; i++) { |
michael@0 | 3375 | /* Mi = MD[i-3] || MD [i-2] || MD [i-1] */ |
michael@0 | 3376 | memcpy(msg, MD_i3, MDLen); |
michael@0 | 3377 | memcpy(&msg[MDLen], MD_i2, MDLen); |
michael@0 | 3378 | memcpy(&msg[MDLen*2], MD_i1,MDLen); |
michael@0 | 3379 | |
michael@0 | 3380 | /* MDi = SHA(Msg) */ |
michael@0 | 3381 | if (sha_calcMD(MD_i, MDLen, |
michael@0 | 3382 | msg, msgLen) != SECSuccess) { |
michael@0 | 3383 | return SECFailure; |
michael@0 | 3384 | } |
michael@0 | 3385 | |
michael@0 | 3386 | /* save MD[i-3] MD[i-2] MD[i-1] */ |
michael@0 | 3387 | memcpy(MD_i3, MD_i2, MDLen); |
michael@0 | 3388 | memcpy(MD_i2, MD_i1, MDLen); |
michael@0 | 3389 | memcpy(MD_i1, MD_i, MDLen); |
michael@0 | 3390 | |
michael@0 | 3391 | } |
michael@0 | 3392 | |
michael@0 | 3393 | /* seed = MD_i */ |
michael@0 | 3394 | memcpy(seed, MD_i, MDLen); |
michael@0 | 3395 | |
michael@0 | 3396 | sprintf(buf, "COUNT = %d\n", j); |
michael@0 | 3397 | fputs(buf, resp); |
michael@0 | 3398 | |
michael@0 | 3399 | /* output MD_i */ |
michael@0 | 3400 | fputs("MD = ", resp); |
michael@0 | 3401 | to_hex_str(buf, MD_i, MDLen); |
michael@0 | 3402 | fputs(buf, resp); |
michael@0 | 3403 | fputc('\n', resp); |
michael@0 | 3404 | } |
michael@0 | 3405 | |
michael@0 | 3406 | return SECSuccess; |
michael@0 | 3407 | } |
michael@0 | 3408 | |
michael@0 | 3409 | /* |
michael@0 | 3410 | * Perform the SHA Tests. |
michael@0 | 3411 | * |
michael@0 | 3412 | * reqfn is the pathname of the input REQUEST file. |
michael@0 | 3413 | * |
michael@0 | 3414 | * The output RESPONSE file is written to stdout. |
michael@0 | 3415 | */ |
michael@0 | 3416 | void sha_test(char *reqfn) |
michael@0 | 3417 | { |
michael@0 | 3418 | unsigned int i, j; |
michael@0 | 3419 | unsigned int MDlen; /* the length of the Message Digest in Bytes */ |
michael@0 | 3420 | unsigned int msgLen; /* the length of the input Message in Bytes */ |
michael@0 | 3421 | unsigned char *msg = NULL; /* holds the message to digest.*/ |
michael@0 | 3422 | size_t bufSize = 25608; /*MAX buffer size */ |
michael@0 | 3423 | char *buf = NULL; /* holds one line from the input REQUEST file.*/ |
michael@0 | 3424 | unsigned char seed[HASH_LENGTH_MAX]; /* max size of seed 64 bytes */ |
michael@0 | 3425 | unsigned char MD[HASH_LENGTH_MAX]; /* message digest */ |
michael@0 | 3426 | |
michael@0 | 3427 | FILE *req = NULL; /* input stream from the REQUEST file */ |
michael@0 | 3428 | FILE *resp; /* output stream to the RESPONSE file */ |
michael@0 | 3429 | |
michael@0 | 3430 | buf = PORT_ZAlloc(bufSize); |
michael@0 | 3431 | if (buf == NULL) { |
michael@0 | 3432 | goto loser; |
michael@0 | 3433 | } |
michael@0 | 3434 | |
michael@0 | 3435 | /* zeroize the variables for the test with this data set */ |
michael@0 | 3436 | memset(seed, 0, sizeof seed); |
michael@0 | 3437 | |
michael@0 | 3438 | req = fopen(reqfn, "r"); |
michael@0 | 3439 | resp = stdout; |
michael@0 | 3440 | while (fgets(buf, bufSize, req) != NULL) { |
michael@0 | 3441 | |
michael@0 | 3442 | /* a comment or blank line */ |
michael@0 | 3443 | if (buf[0] == '#' || buf[0] == '\n') { |
michael@0 | 3444 | fputs(buf, resp); |
michael@0 | 3445 | continue; |
michael@0 | 3446 | } |
michael@0 | 3447 | /* [L = Length of the Message Digest and sha_type */ |
michael@0 | 3448 | if (buf[0] == '[') { |
michael@0 | 3449 | if (strncmp(&buf[1], "L ", 1) == 0) { |
michael@0 | 3450 | i = 2; |
michael@0 | 3451 | while (isspace(buf[i]) || buf[i] == '=') { |
michael@0 | 3452 | i++; |
michael@0 | 3453 | } |
michael@0 | 3454 | MDlen = atoi(&buf[i]); |
michael@0 | 3455 | fputs(buf, resp); |
michael@0 | 3456 | continue; |
michael@0 | 3457 | } |
michael@0 | 3458 | } |
michael@0 | 3459 | /* Len = Length of the Input Message Length ... */ |
michael@0 | 3460 | if (strncmp(buf, "Len", 3) == 0) { |
michael@0 | 3461 | i = 3; |
michael@0 | 3462 | while (isspace(buf[i]) || buf[i] == '=') { |
michael@0 | 3463 | i++; |
michael@0 | 3464 | } |
michael@0 | 3465 | if (msg) { |
michael@0 | 3466 | PORT_ZFree(msg,msgLen); |
michael@0 | 3467 | msg = NULL; |
michael@0 | 3468 | } |
michael@0 | 3469 | msgLen = atoi(&buf[i]); /* in bits */ |
michael@0 | 3470 | if (msgLen%8 != 0) { |
michael@0 | 3471 | fprintf(stderr, "SHA tests are incorrectly configured for " |
michael@0 | 3472 | "BIT oriented implementations\n"); |
michael@0 | 3473 | goto loser; |
michael@0 | 3474 | } |
michael@0 | 3475 | msgLen = msgLen/8; /* convert to bytes */ |
michael@0 | 3476 | fputs(buf, resp); |
michael@0 | 3477 | msg = PORT_ZAlloc(msgLen); |
michael@0 | 3478 | if (msg == NULL && msgLen != 0) { |
michael@0 | 3479 | goto loser; |
michael@0 | 3480 | } |
michael@0 | 3481 | continue; |
michael@0 | 3482 | } |
michael@0 | 3483 | /* MSG = ... */ |
michael@0 | 3484 | if (strncmp(buf, "Msg", 3) == 0) { |
michael@0 | 3485 | i = 3; |
michael@0 | 3486 | while (isspace(buf[i]) || buf[i] == '=') { |
michael@0 | 3487 | i++; |
michael@0 | 3488 | } |
michael@0 | 3489 | for (j=0; j< msgLen; i+=2,j++) { |
michael@0 | 3490 | hex_to_byteval(&buf[i], &msg[j]); |
michael@0 | 3491 | } |
michael@0 | 3492 | fputs(buf, resp); |
michael@0 | 3493 | /* calculate the Message Digest */ |
michael@0 | 3494 | memset(MD, 0, sizeof MD); |
michael@0 | 3495 | if (sha_calcMD(MD, MDlen, |
michael@0 | 3496 | msg, msgLen) != SECSuccess) { |
michael@0 | 3497 | goto loser; |
michael@0 | 3498 | } |
michael@0 | 3499 | |
michael@0 | 3500 | fputs("MD = ", resp); |
michael@0 | 3501 | to_hex_str(buf, MD, MDlen); |
michael@0 | 3502 | fputs(buf, resp); |
michael@0 | 3503 | fputc('\n', resp); |
michael@0 | 3504 | |
michael@0 | 3505 | continue; |
michael@0 | 3506 | } |
michael@0 | 3507 | /* Seed = ... */ |
michael@0 | 3508 | if (strncmp(buf, "Seed", 4) == 0) { |
michael@0 | 3509 | i = 4; |
michael@0 | 3510 | while (isspace(buf[i]) || buf[i] == '=') { |
michael@0 | 3511 | i++; |
michael@0 | 3512 | } |
michael@0 | 3513 | for (j=0; j<sizeof seed; i+=2,j++) { |
michael@0 | 3514 | hex_to_byteval(&buf[i], &seed[j]); |
michael@0 | 3515 | } |
michael@0 | 3516 | |
michael@0 | 3517 | fputs(buf, resp); |
michael@0 | 3518 | fputc('\n', resp); |
michael@0 | 3519 | |
michael@0 | 3520 | /* do the Monte Carlo test */ |
michael@0 | 3521 | if (sha_mct_test(MDlen, seed, resp) != SECSuccess) { |
michael@0 | 3522 | goto loser; |
michael@0 | 3523 | } |
michael@0 | 3524 | |
michael@0 | 3525 | continue; |
michael@0 | 3526 | } |
michael@0 | 3527 | } |
michael@0 | 3528 | loser: |
michael@0 | 3529 | if (req) { |
michael@0 | 3530 | fclose(req); |
michael@0 | 3531 | } |
michael@0 | 3532 | if (buf) { |
michael@0 | 3533 | PORT_ZFree(buf, bufSize); |
michael@0 | 3534 | } |
michael@0 | 3535 | if (msg) { |
michael@0 | 3536 | PORT_ZFree(msg, msgLen); |
michael@0 | 3537 | } |
michael@0 | 3538 | } |
michael@0 | 3539 | |
michael@0 | 3540 | /****************************************************/ |
michael@0 | 3541 | /* HMAC SHA-X calc */ |
michael@0 | 3542 | /* hmac_computed - the computed HMAC */ |
michael@0 | 3543 | /* hmac_length - the length of the computed HMAC */ |
michael@0 | 3544 | /* secret_key - secret key to HMAC */ |
michael@0 | 3545 | /* secret_key_length - length of secret key, */ |
michael@0 | 3546 | /* message - message to HMAC */ |
michael@0 | 3547 | /* message_length - length ofthe message */ |
michael@0 | 3548 | /****************************************************/ |
michael@0 | 3549 | static SECStatus |
michael@0 | 3550 | hmac_calc(unsigned char *hmac_computed, |
michael@0 | 3551 | const unsigned int hmac_length, |
michael@0 | 3552 | const unsigned char *secret_key, |
michael@0 | 3553 | const unsigned int secret_key_length, |
michael@0 | 3554 | const unsigned char *message, |
michael@0 | 3555 | const unsigned int message_length, |
michael@0 | 3556 | const HASH_HashType hashAlg ) |
michael@0 | 3557 | { |
michael@0 | 3558 | SECStatus hmac_status = SECFailure; |
michael@0 | 3559 | HMACContext *cx = NULL; |
michael@0 | 3560 | SECHashObject *hashObj = NULL; |
michael@0 | 3561 | unsigned int bytes_hashed = 0; |
michael@0 | 3562 | |
michael@0 | 3563 | hashObj = (SECHashObject *) HASH_GetRawHashObject(hashAlg); |
michael@0 | 3564 | |
michael@0 | 3565 | if (!hashObj) |
michael@0 | 3566 | return( SECFailure ); |
michael@0 | 3567 | |
michael@0 | 3568 | cx = HMAC_Create(hashObj, secret_key, |
michael@0 | 3569 | secret_key_length, |
michael@0 | 3570 | PR_TRUE); /* PR_TRUE for in FIPS mode */ |
michael@0 | 3571 | |
michael@0 | 3572 | if (cx == NULL) |
michael@0 | 3573 | return( SECFailure ); |
michael@0 | 3574 | |
michael@0 | 3575 | HMAC_Begin(cx); |
michael@0 | 3576 | HMAC_Update(cx, message, message_length); |
michael@0 | 3577 | hmac_status = HMAC_Finish(cx, hmac_computed, &bytes_hashed, |
michael@0 | 3578 | hmac_length); |
michael@0 | 3579 | |
michael@0 | 3580 | HMAC_Destroy(cx, PR_TRUE); |
michael@0 | 3581 | |
michael@0 | 3582 | return( hmac_status ); |
michael@0 | 3583 | } |
michael@0 | 3584 | |
michael@0 | 3585 | /* |
michael@0 | 3586 | * Perform the HMAC Tests. |
michael@0 | 3587 | * |
michael@0 | 3588 | * reqfn is the pathname of the input REQUEST file. |
michael@0 | 3589 | * |
michael@0 | 3590 | * The output RESPONSE file is written to stdout. |
michael@0 | 3591 | */ |
michael@0 | 3592 | void hmac_test(char *reqfn) |
michael@0 | 3593 | { |
michael@0 | 3594 | unsigned int i, j; |
michael@0 | 3595 | size_t bufSize = 400; /* MAX buffer size */ |
michael@0 | 3596 | char *buf = NULL; /* holds one line from the input REQUEST file.*/ |
michael@0 | 3597 | unsigned int keyLen; /* Key Length */ |
michael@0 | 3598 | unsigned char key[200]; /* key MAX size = 184 */ |
michael@0 | 3599 | unsigned int msgLen = 128; /* the length of the input */ |
michael@0 | 3600 | /* Message is always 128 Bytes */ |
michael@0 | 3601 | unsigned char *msg = NULL; /* holds the message to digest.*/ |
michael@0 | 3602 | unsigned int HMACLen; /* the length of the HMAC Bytes */ |
michael@0 | 3603 | unsigned int TLen; /* the length of the requested */ |
michael@0 | 3604 | /* truncated HMAC Bytes */ |
michael@0 | 3605 | unsigned char HMAC[HASH_LENGTH_MAX]; /* computed HMAC */ |
michael@0 | 3606 | unsigned char expectedHMAC[HASH_LENGTH_MAX]; /* for .fax files that have */ |
michael@0 | 3607 | /* supplied known answer */ |
michael@0 | 3608 | HASH_HashType hash_alg; /* HMAC type */ |
michael@0 | 3609 | |
michael@0 | 3610 | |
michael@0 | 3611 | FILE *req = NULL; /* input stream from the REQUEST file */ |
michael@0 | 3612 | FILE *resp; /* output stream to the RESPONSE file */ |
michael@0 | 3613 | |
michael@0 | 3614 | buf = PORT_ZAlloc(bufSize); |
michael@0 | 3615 | if (buf == NULL) { |
michael@0 | 3616 | goto loser; |
michael@0 | 3617 | } |
michael@0 | 3618 | msg = PORT_ZAlloc(msgLen); |
michael@0 | 3619 | if (msg == NULL) { |
michael@0 | 3620 | goto loser; |
michael@0 | 3621 | } |
michael@0 | 3622 | |
michael@0 | 3623 | req = fopen(reqfn, "r"); |
michael@0 | 3624 | resp = stdout; |
michael@0 | 3625 | while (fgets(buf, bufSize, req) != NULL) { |
michael@0 | 3626 | if (strncmp(buf, "Mac", 3) == 0) { |
michael@0 | 3627 | i = 3; |
michael@0 | 3628 | while (isspace(buf[i]) || buf[i] == '=') { |
michael@0 | 3629 | i++; |
michael@0 | 3630 | } |
michael@0 | 3631 | memset(expectedHMAC, 0, HASH_LENGTH_MAX); |
michael@0 | 3632 | for (j=0; isxdigit(buf[i]); i+=2,j++) { |
michael@0 | 3633 | hex_to_byteval(&buf[i], &expectedHMAC[j]); |
michael@0 | 3634 | } |
michael@0 | 3635 | if (memcmp(HMAC, expectedHMAC, TLen) != 0) { |
michael@0 | 3636 | fprintf(stderr, "Generate failed:\n"); |
michael@0 | 3637 | fputs( " expected=", stderr); |
michael@0 | 3638 | to_hex_str(buf, expectedHMAC, |
michael@0 | 3639 | TLen); |
michael@0 | 3640 | fputs(buf, stderr); |
michael@0 | 3641 | fputs("\n generated=", stderr); |
michael@0 | 3642 | to_hex_str(buf, HMAC, |
michael@0 | 3643 | TLen); |
michael@0 | 3644 | fputs(buf, stderr); |
michael@0 | 3645 | fputc('\n', stderr); |
michael@0 | 3646 | } |
michael@0 | 3647 | } |
michael@0 | 3648 | |
michael@0 | 3649 | /* a comment or blank line */ |
michael@0 | 3650 | if (buf[0] == '#' || buf[0] == '\n') { |
michael@0 | 3651 | fputs(buf, resp); |
michael@0 | 3652 | continue; |
michael@0 | 3653 | } |
michael@0 | 3654 | /* [L = Length of the MAC and HASH_type */ |
michael@0 | 3655 | if (buf[0] == '[') { |
michael@0 | 3656 | if (strncmp(&buf[1], "L ", 1) == 0) { |
michael@0 | 3657 | i = 2; |
michael@0 | 3658 | while (isspace(buf[i]) || buf[i] == '=') { |
michael@0 | 3659 | i++; |
michael@0 | 3660 | } |
michael@0 | 3661 | /* HMACLen will get reused for Tlen */ |
michael@0 | 3662 | HMACLen = atoi(&buf[i]); |
michael@0 | 3663 | hash_alg = sha_get_hashType(HMACLen*PR_BITS_PER_BYTE); |
michael@0 | 3664 | if (hash_alg == HASH_AlgNULL) { |
michael@0 | 3665 | goto loser; |
michael@0 | 3666 | } |
michael@0 | 3667 | fputs(buf, resp); |
michael@0 | 3668 | continue; |
michael@0 | 3669 | } |
michael@0 | 3670 | } |
michael@0 | 3671 | /* Count = test iteration number*/ |
michael@0 | 3672 | if (strncmp(buf, "Count ", 5) == 0) { |
michael@0 | 3673 | /* count can just be put into resp file */ |
michael@0 | 3674 | fputs(buf, resp); |
michael@0 | 3675 | /* zeroize the variables for the test with this data set */ |
michael@0 | 3676 | keyLen = 0; |
michael@0 | 3677 | TLen = 0; |
michael@0 | 3678 | memset(key, 0, sizeof key); |
michael@0 | 3679 | memset(msg, 0, msgLen); |
michael@0 | 3680 | memset(HMAC, 0, sizeof HMAC); |
michael@0 | 3681 | continue; |
michael@0 | 3682 | } |
michael@0 | 3683 | /* KLen = Length of the Input Secret Key ... */ |
michael@0 | 3684 | if (strncmp(buf, "Klen", 4) == 0) { |
michael@0 | 3685 | i = 4; |
michael@0 | 3686 | while (isspace(buf[i]) || buf[i] == '=') { |
michael@0 | 3687 | i++; |
michael@0 | 3688 | } |
michael@0 | 3689 | keyLen = atoi(&buf[i]); /* in bytes */ |
michael@0 | 3690 | fputs(buf, resp); |
michael@0 | 3691 | continue; |
michael@0 | 3692 | } |
michael@0 | 3693 | /* key = the secret key for the key to MAC */ |
michael@0 | 3694 | if (strncmp(buf, "Key", 3) == 0) { |
michael@0 | 3695 | i = 3; |
michael@0 | 3696 | while (isspace(buf[i]) || buf[i] == '=') { |
michael@0 | 3697 | i++; |
michael@0 | 3698 | } |
michael@0 | 3699 | for (j=0; j< keyLen; i+=2,j++) { |
michael@0 | 3700 | hex_to_byteval(&buf[i], &key[j]); |
michael@0 | 3701 | } |
michael@0 | 3702 | fputs(buf, resp); |
michael@0 | 3703 | } |
michael@0 | 3704 | /* TLen = Length of the calculated HMAC */ |
michael@0 | 3705 | if (strncmp(buf, "Tlen", 4) == 0) { |
michael@0 | 3706 | i = 4; |
michael@0 | 3707 | while (isspace(buf[i]) || buf[i] == '=') { |
michael@0 | 3708 | i++; |
michael@0 | 3709 | } |
michael@0 | 3710 | TLen = atoi(&buf[i]); /* in bytes */ |
michael@0 | 3711 | fputs(buf, resp); |
michael@0 | 3712 | continue; |
michael@0 | 3713 | } |
michael@0 | 3714 | /* MSG = to HMAC always 128 bytes for these tests */ |
michael@0 | 3715 | if (strncmp(buf, "Msg", 3) == 0) { |
michael@0 | 3716 | i = 3; |
michael@0 | 3717 | while (isspace(buf[i]) || buf[i] == '=') { |
michael@0 | 3718 | i++; |
michael@0 | 3719 | } |
michael@0 | 3720 | for (j=0; j< msgLen; i+=2,j++) { |
michael@0 | 3721 | hex_to_byteval(&buf[i], &msg[j]); |
michael@0 | 3722 | } |
michael@0 | 3723 | fputs(buf, resp); |
michael@0 | 3724 | /* calculate the HMAC and output */ |
michael@0 | 3725 | if (hmac_calc(HMAC, HMACLen, key, keyLen, |
michael@0 | 3726 | msg, msgLen, hash_alg) != SECSuccess) { |
michael@0 | 3727 | goto loser; |
michael@0 | 3728 | } |
michael@0 | 3729 | fputs("MAC = ", resp); |
michael@0 | 3730 | to_hex_str(buf, HMAC, TLen); |
michael@0 | 3731 | fputs(buf, resp); |
michael@0 | 3732 | fputc('\n', resp); |
michael@0 | 3733 | continue; |
michael@0 | 3734 | } |
michael@0 | 3735 | } |
michael@0 | 3736 | loser: |
michael@0 | 3737 | if (req) { |
michael@0 | 3738 | fclose(req); |
michael@0 | 3739 | } |
michael@0 | 3740 | if (buf) { |
michael@0 | 3741 | PORT_ZFree(buf, bufSize); |
michael@0 | 3742 | } |
michael@0 | 3743 | if (msg) { |
michael@0 | 3744 | PORT_ZFree(msg, msgLen); |
michael@0 | 3745 | } |
michael@0 | 3746 | } |
michael@0 | 3747 | |
michael@0 | 3748 | /* |
michael@0 | 3749 | * Perform the DSA Key Pair Generation Test. |
michael@0 | 3750 | * |
michael@0 | 3751 | * reqfn is the pathname of the REQUEST file. |
michael@0 | 3752 | * |
michael@0 | 3753 | * The output RESPONSE file is written to stdout. |
michael@0 | 3754 | */ |
michael@0 | 3755 | void |
michael@0 | 3756 | dsa_keypair_test(char *reqfn) |
michael@0 | 3757 | { |
michael@0 | 3758 | char buf[800]; /* holds one line from the input REQUEST file |
michael@0 | 3759 | * or to the output RESPONSE file. |
michael@0 | 3760 | * 800 to hold (384 public key (x2 for HEX) + 1'\n' |
michael@0 | 3761 | */ |
michael@0 | 3762 | FILE *dsareq; /* input stream from the REQUEST file */ |
michael@0 | 3763 | FILE *dsaresp; /* output stream to the RESPONSE file */ |
michael@0 | 3764 | int count; |
michael@0 | 3765 | int N; |
michael@0 | 3766 | int L; |
michael@0 | 3767 | int i; |
michael@0 | 3768 | PQGParams *pqg = NULL; |
michael@0 | 3769 | PQGVerify *vfy = NULL; |
michael@0 | 3770 | PRBool use_dsa1 = PR_FALSE; |
michael@0 | 3771 | int keySizeIndex; /* index for valid key sizes */ |
michael@0 | 3772 | |
michael@0 | 3773 | dsareq = fopen(reqfn, "r"); |
michael@0 | 3774 | dsaresp = stdout; |
michael@0 | 3775 | while (fgets(buf, sizeof buf, dsareq) != NULL) { |
michael@0 | 3776 | /* a comment or blank line */ |
michael@0 | 3777 | if (buf[0] == '#' || buf[0] == '\n') { |
michael@0 | 3778 | fputs(buf, dsaresp); |
michael@0 | 3779 | continue; |
michael@0 | 3780 | } |
michael@0 | 3781 | |
michael@0 | 3782 | /* [Mod = x] */ |
michael@0 | 3783 | if (buf[0] == '[') { |
michael@0 | 3784 | if(pqg!=NULL) { |
michael@0 | 3785 | PQG_DestroyParams(pqg); |
michael@0 | 3786 | pqg = NULL; |
michael@0 | 3787 | } |
michael@0 | 3788 | if(vfy!=NULL) { |
michael@0 | 3789 | PQG_DestroyVerify(vfy); |
michael@0 | 3790 | vfy = NULL; |
michael@0 | 3791 | } |
michael@0 | 3792 | |
michael@0 | 3793 | if (sscanf(buf, "[mod = L=%d, N=%d]", &L, &N) != 2) { |
michael@0 | 3794 | use_dsa1 = PR_TRUE; |
michael@0 | 3795 | if (sscanf(buf, "[mod = %d]", &L) != 1) { |
michael@0 | 3796 | goto loser; |
michael@0 | 3797 | } |
michael@0 | 3798 | } |
michael@0 | 3799 | fputs(buf, dsaresp); |
michael@0 | 3800 | fputc('\n', dsaresp); |
michael@0 | 3801 | |
michael@0 | 3802 | if (use_dsa1) { |
michael@0 | 3803 | /************************************************************* |
michael@0 | 3804 | * PQG_ParamGenSeedLen doesn't take a key size, it takes an |
michael@0 | 3805 | * index that points to a valid key size. |
michael@0 | 3806 | */ |
michael@0 | 3807 | keySizeIndex = PQG_PBITS_TO_INDEX(L); |
michael@0 | 3808 | if(keySizeIndex == -1 || L<512 || L>1024) { |
michael@0 | 3809 | fprintf(dsaresp, |
michael@0 | 3810 | "DSA key size must be a multiple of 64 between 512 " |
michael@0 | 3811 | "and 1024, inclusive"); |
michael@0 | 3812 | goto loser; |
michael@0 | 3813 | } |
michael@0 | 3814 | |
michael@0 | 3815 | /* Generate the parameters P, Q, and G */ |
michael@0 | 3816 | if (PQG_ParamGenSeedLen(keySizeIndex, PQG_TEST_SEED_BYTES, |
michael@0 | 3817 | &pqg, &vfy) != SECSuccess) { |
michael@0 | 3818 | fprintf(dsaresp, |
michael@0 | 3819 | "ERROR: Unable to generate PQG parameters"); |
michael@0 | 3820 | goto loser; |
michael@0 | 3821 | } |
michael@0 | 3822 | } else { |
michael@0 | 3823 | if (PQG_ParamGenV2(L, N, N, &pqg, &vfy) != SECSuccess) { |
michael@0 | 3824 | fprintf(dsaresp, |
michael@0 | 3825 | "ERROR: Unable to generate PQG parameters"); |
michael@0 | 3826 | goto loser; |
michael@0 | 3827 | } |
michael@0 | 3828 | } |
michael@0 | 3829 | |
michael@0 | 3830 | /* output P, Q, and G */ |
michael@0 | 3831 | to_hex_str(buf, pqg->prime.data, pqg->prime.len); |
michael@0 | 3832 | fprintf(dsaresp, "P = %s\n", buf); |
michael@0 | 3833 | to_hex_str(buf, pqg->subPrime.data, pqg->subPrime.len); |
michael@0 | 3834 | fprintf(dsaresp, "Q = %s\n", buf); |
michael@0 | 3835 | to_hex_str(buf, pqg->base.data, pqg->base.len); |
michael@0 | 3836 | fprintf(dsaresp, "G = %s\n\n", buf); |
michael@0 | 3837 | continue; |
michael@0 | 3838 | } |
michael@0 | 3839 | /* N = ...*/ |
michael@0 | 3840 | if (buf[0] == 'N') { |
michael@0 | 3841 | |
michael@0 | 3842 | if (sscanf(buf, "N = %d", &count) != 1) { |
michael@0 | 3843 | goto loser; |
michael@0 | 3844 | } |
michael@0 | 3845 | /* Generate a DSA key, and output the key pair for N times */ |
michael@0 | 3846 | for (i = 0; i < count; i++) { |
michael@0 | 3847 | DSAPrivateKey *dsakey = NULL; |
michael@0 | 3848 | if (DSA_NewKey(pqg, &dsakey) != SECSuccess) { |
michael@0 | 3849 | fprintf(dsaresp, "ERROR: Unable to generate DSA key"); |
michael@0 | 3850 | goto loser; |
michael@0 | 3851 | } |
michael@0 | 3852 | to_hex_str(buf, dsakey->privateValue.data, |
michael@0 | 3853 | dsakey->privateValue.len); |
michael@0 | 3854 | fprintf(dsaresp, "X = %s\n", buf); |
michael@0 | 3855 | to_hex_str(buf, dsakey->publicValue.data, |
michael@0 | 3856 | dsakey->publicValue.len); |
michael@0 | 3857 | fprintf(dsaresp, "Y = %s\n\n", buf); |
michael@0 | 3858 | PORT_FreeArena(dsakey->params.arena, PR_TRUE); |
michael@0 | 3859 | dsakey = NULL; |
michael@0 | 3860 | } |
michael@0 | 3861 | continue; |
michael@0 | 3862 | } |
michael@0 | 3863 | |
michael@0 | 3864 | } |
michael@0 | 3865 | loser: |
michael@0 | 3866 | fclose(dsareq); |
michael@0 | 3867 | } |
michael@0 | 3868 | |
michael@0 | 3869 | /* |
michael@0 | 3870 | * pqg generation type |
michael@0 | 3871 | */ |
michael@0 | 3872 | typedef enum { |
michael@0 | 3873 | FIPS186_1,/* Generate/Verify P,Q & G according to FIPS 186-1 */ |
michael@0 | 3874 | A_1_1_2, /* Generate Probable P & Q */ |
michael@0 | 3875 | A_1_1_3, /* Verify Probable P & Q */ |
michael@0 | 3876 | A_1_2_2, /* Verify Provable P & Q */ |
michael@0 | 3877 | A_2_1, /* Generate Unverifiable G */ |
michael@0 | 3878 | A_2_2, /* Assure Unverifiable G */ |
michael@0 | 3879 | A_2_3, /* Generate Verifiable G */ |
michael@0 | 3880 | A_2_4 /* Verify Verifiable G */ |
michael@0 | 3881 | } dsa_pqg_type; |
michael@0 | 3882 | |
michael@0 | 3883 | /* |
michael@0 | 3884 | * Perform the DSA Domain Parameter Validation Test. |
michael@0 | 3885 | * |
michael@0 | 3886 | * reqfn is the pathname of the REQUEST file. |
michael@0 | 3887 | * |
michael@0 | 3888 | * The output RESPONSE file is written to stdout. |
michael@0 | 3889 | */ |
michael@0 | 3890 | void |
michael@0 | 3891 | dsa_pqgver_test(char *reqfn) |
michael@0 | 3892 | { |
michael@0 | 3893 | char buf[800]; /* holds one line from the input REQUEST file |
michael@0 | 3894 | * or to the output RESPONSE file. |
michael@0 | 3895 | * 800 to hold (384 public key (x2 for HEX) + P = ... |
michael@0 | 3896 | */ |
michael@0 | 3897 | FILE *dsareq; /* input stream from the REQUEST file */ |
michael@0 | 3898 | FILE *dsaresp; /* output stream to the RESPONSE file */ |
michael@0 | 3899 | int N; |
michael@0 | 3900 | int L; |
michael@0 | 3901 | unsigned int i, j; |
michael@0 | 3902 | PQGParams pqg; |
michael@0 | 3903 | PQGVerify vfy; |
michael@0 | 3904 | unsigned int pghSize; /* size for p, g, and h */ |
michael@0 | 3905 | dsa_pqg_type type = FIPS186_1; |
michael@0 | 3906 | |
michael@0 | 3907 | dsareq = fopen(reqfn, "r"); |
michael@0 | 3908 | dsaresp = stdout; |
michael@0 | 3909 | memset(&pqg, 0, sizeof(pqg)); |
michael@0 | 3910 | memset(&vfy, 0, sizeof(vfy)); |
michael@0 | 3911 | |
michael@0 | 3912 | while (fgets(buf, sizeof buf, dsareq) != NULL) { |
michael@0 | 3913 | /* a comment or blank line */ |
michael@0 | 3914 | if (buf[0] == '#' || buf[0] == '\n') { |
michael@0 | 3915 | fputs(buf, dsaresp); |
michael@0 | 3916 | continue; |
michael@0 | 3917 | } |
michael@0 | 3918 | |
michael@0 | 3919 | /* [A.xxxxx ] */ |
michael@0 | 3920 | if (buf[0] == '[' && buf[1] == 'A') { |
michael@0 | 3921 | |
michael@0 | 3922 | if (strncmp(&buf[1],"A.1.1.3",7) == 0) { |
michael@0 | 3923 | type = A_1_1_3; |
michael@0 | 3924 | } else if (strncmp(&buf[1],"A.2.2",5) == 0) { |
michael@0 | 3925 | type = A_2_2; |
michael@0 | 3926 | } else if (strncmp(&buf[1],"A.2.4",5) == 0) { |
michael@0 | 3927 | type = A_2_4; |
michael@0 | 3928 | } else if (strncmp(&buf[1],"A.1.2.2",7) == 0) { |
michael@0 | 3929 | type = A_1_2_2; |
michael@0 | 3930 | /* validate our output from PQGGEN */ |
michael@0 | 3931 | } else if (strncmp(&buf[1],"A.1.1.2",7) == 0) { |
michael@0 | 3932 | type = A_2_4; /* validate PQ and G together */ |
michael@0 | 3933 | } else { |
michael@0 | 3934 | fprintf(stderr, "Unknown dsa ver test %s\n", &buf[1]); |
michael@0 | 3935 | exit(1); |
michael@0 | 3936 | } |
michael@0 | 3937 | |
michael@0 | 3938 | fputs(buf, dsaresp); |
michael@0 | 3939 | continue; |
michael@0 | 3940 | } |
michael@0 | 3941 | |
michael@0 | 3942 | |
michael@0 | 3943 | /* [Mod = x] */ |
michael@0 | 3944 | if (buf[0] == '[') { |
michael@0 | 3945 | |
michael@0 | 3946 | if (type == FIPS186_1) { |
michael@0 | 3947 | N=160; |
michael@0 | 3948 | if (sscanf(buf, "[mod = %d]", &L) != 1) { |
michael@0 | 3949 | goto loser; |
michael@0 | 3950 | } |
michael@0 | 3951 | } else if (sscanf(buf, "[mod = L=%d, N=%d", &L, &N) != 2) { |
michael@0 | 3952 | goto loser; |
michael@0 | 3953 | } |
michael@0 | 3954 | |
michael@0 | 3955 | if (pqg.prime.data) { /* P */ |
michael@0 | 3956 | SECITEM_ZfreeItem(&pqg.prime, PR_FALSE); |
michael@0 | 3957 | } |
michael@0 | 3958 | if (pqg.subPrime.data) { /* Q */ |
michael@0 | 3959 | SECITEM_ZfreeItem(&pqg.subPrime, PR_FALSE); |
michael@0 | 3960 | } |
michael@0 | 3961 | if (pqg.base.data) { /* G */ |
michael@0 | 3962 | SECITEM_ZfreeItem(&pqg.base, PR_FALSE); |
michael@0 | 3963 | } |
michael@0 | 3964 | if (vfy.seed.data) { /* seed */ |
michael@0 | 3965 | SECITEM_ZfreeItem(&vfy.seed, PR_FALSE); |
michael@0 | 3966 | } |
michael@0 | 3967 | if (vfy.h.data) { /* H */ |
michael@0 | 3968 | SECITEM_ZfreeItem(&vfy.h, PR_FALSE); |
michael@0 | 3969 | } |
michael@0 | 3970 | |
michael@0 | 3971 | fputs(buf, dsaresp); |
michael@0 | 3972 | |
michael@0 | 3973 | /*calculate the size of p, g, and h then allocate items */ |
michael@0 | 3974 | pghSize = L/8; |
michael@0 | 3975 | |
michael@0 | 3976 | pqg.base.data = vfy.h.data = NULL; |
michael@0 | 3977 | vfy.seed.len = pqg.base.len = vfy.h.len = 0; |
michael@0 | 3978 | SECITEM_AllocItem(NULL, &pqg.prime, pghSize); |
michael@0 | 3979 | SECITEM_AllocItem(NULL, &vfy.seed, pghSize*3); |
michael@0 | 3980 | if (type == A_2_2) { |
michael@0 | 3981 | SECITEM_AllocItem(NULL, &vfy.h, pghSize); |
michael@0 | 3982 | vfy.h.len = pghSize; |
michael@0 | 3983 | } else if (type == A_2_4) { |
michael@0 | 3984 | SECITEM_AllocItem(NULL, &vfy.h, 1); |
michael@0 | 3985 | vfy.h.len = 1; |
michael@0 | 3986 | } |
michael@0 | 3987 | pqg.prime.len = pghSize; |
michael@0 | 3988 | /* q is always N bits */ |
michael@0 | 3989 | SECITEM_AllocItem(NULL, &pqg.subPrime, N/8); |
michael@0 | 3990 | pqg.subPrime.len = N/8; |
michael@0 | 3991 | vfy.counter = -1; |
michael@0 | 3992 | |
michael@0 | 3993 | continue; |
michael@0 | 3994 | } |
michael@0 | 3995 | /* P = ... */ |
michael@0 | 3996 | if (buf[0] == 'P') { |
michael@0 | 3997 | i = 1; |
michael@0 | 3998 | while (isspace(buf[i]) || buf[i] == '=') { |
michael@0 | 3999 | i++; |
michael@0 | 4000 | } |
michael@0 | 4001 | for (j=0; j< pqg.prime.len; i+=2,j++) { |
michael@0 | 4002 | hex_to_byteval(&buf[i], &pqg.prime.data[j]); |
michael@0 | 4003 | } |
michael@0 | 4004 | |
michael@0 | 4005 | fputs(buf, dsaresp); |
michael@0 | 4006 | continue; |
michael@0 | 4007 | } |
michael@0 | 4008 | |
michael@0 | 4009 | /* Q = ... */ |
michael@0 | 4010 | if (buf[0] == 'Q') { |
michael@0 | 4011 | i = 1; |
michael@0 | 4012 | while (isspace(buf[i]) || buf[i] == '=') { |
michael@0 | 4013 | i++; |
michael@0 | 4014 | } |
michael@0 | 4015 | for (j=0; j< pqg.subPrime.len; i+=2,j++) { |
michael@0 | 4016 | hex_to_byteval(&buf[i], &pqg.subPrime.data[j]); |
michael@0 | 4017 | } |
michael@0 | 4018 | |
michael@0 | 4019 | fputs(buf, dsaresp); |
michael@0 | 4020 | continue; |
michael@0 | 4021 | } |
michael@0 | 4022 | |
michael@0 | 4023 | /* G = ... */ |
michael@0 | 4024 | if (buf[0] == 'G') { |
michael@0 | 4025 | i = 1; |
michael@0 | 4026 | if (pqg.base.data) { |
michael@0 | 4027 | SECITEM_ZfreeItem(&pqg.base, PR_FALSE); |
michael@0 | 4028 | } |
michael@0 | 4029 | SECITEM_AllocItem(NULL, &pqg.base, pghSize); |
michael@0 | 4030 | while (isspace(buf[i]) || buf[i] == '=') { |
michael@0 | 4031 | i++; |
michael@0 | 4032 | } |
michael@0 | 4033 | for (j=0; j< pqg.base.len; i+=2,j++) { |
michael@0 | 4034 | hex_to_byteval(&buf[i], &pqg.base.data[j]); |
michael@0 | 4035 | } |
michael@0 | 4036 | |
michael@0 | 4037 | fputs(buf, dsaresp); |
michael@0 | 4038 | continue; |
michael@0 | 4039 | } |
michael@0 | 4040 | |
michael@0 | 4041 | /* Seed = ... or domain_parameter_seed = ... */ |
michael@0 | 4042 | if (strncmp(buf, "Seed", 4) == 0) { |
michael@0 | 4043 | i = 4; |
michael@0 | 4044 | } else if (strncmp(buf, "domain_parameter_seed", 21) == 0) { |
michael@0 | 4045 | i = 21; |
michael@0 | 4046 | } else if (strncmp(buf,"firstseed",9) == 0) { |
michael@0 | 4047 | i = 9; |
michael@0 | 4048 | } else { |
michael@0 | 4049 | i = 0; |
michael@0 | 4050 | } |
michael@0 | 4051 | if (i) { |
michael@0 | 4052 | while (isspace(buf[i]) || buf[i] == '=') { |
michael@0 | 4053 | i++; |
michael@0 | 4054 | } |
michael@0 | 4055 | for (j=0; isxdigit(buf[i]); i+=2,j++) { |
michael@0 | 4056 | hex_to_byteval(&buf[i], &vfy.seed.data[j]); |
michael@0 | 4057 | } |
michael@0 | 4058 | vfy.seed.len = j; |
michael@0 | 4059 | |
michael@0 | 4060 | fputs(buf, dsaresp); |
michael@0 | 4061 | if (type == A_2_4) { |
michael@0 | 4062 | SECStatus result; |
michael@0 | 4063 | |
michael@0 | 4064 | /* Verify the Parameters */ |
michael@0 | 4065 | SECStatus rv = PQG_VerifyParams(&pqg, &vfy, &result); |
michael@0 | 4066 | if (rv != SECSuccess) { |
michael@0 | 4067 | goto loser; |
michael@0 | 4068 | } |
michael@0 | 4069 | if (result == SECSuccess) { |
michael@0 | 4070 | fprintf(dsaresp, "Result = P\n"); |
michael@0 | 4071 | } else { |
michael@0 | 4072 | fprintf(dsaresp, "Result = F\n"); |
michael@0 | 4073 | } |
michael@0 | 4074 | } |
michael@0 | 4075 | continue; |
michael@0 | 4076 | } |
michael@0 | 4077 | if ((strncmp(buf,"pseed",5) == 0) || |
michael@0 | 4078 | (strncmp(buf,"qseed",5) == 0)) |
michael@0 | 4079 | { |
michael@0 | 4080 | i = 5; |
michael@0 | 4081 | while (isspace(buf[i]) || buf[i] == '=') { |
michael@0 | 4082 | i++; |
michael@0 | 4083 | } |
michael@0 | 4084 | for (j=vfy.seed.len; isxdigit(buf[i]); i+=2,j++) { |
michael@0 | 4085 | hex_to_byteval(&buf[i], &vfy.seed.data[j]); |
michael@0 | 4086 | } |
michael@0 | 4087 | vfy.seed.len = j; |
michael@0 | 4088 | fputs(buf, dsaresp); |
michael@0 | 4089 | |
michael@0 | 4090 | continue; |
michael@0 | 4091 | } |
michael@0 | 4092 | if (strncmp(buf, "index", 4) == 0) { |
michael@0 | 4093 | i=5; |
michael@0 | 4094 | while (isspace(buf[i]) || buf[i] == '=') { |
michael@0 | 4095 | i++; |
michael@0 | 4096 | } |
michael@0 | 4097 | hex_to_byteval(&buf[i], &vfy.h.data[0]); |
michael@0 | 4098 | vfy.h.len = 1; |
michael@0 | 4099 | fputs(buf, dsaresp); |
michael@0 | 4100 | } |
michael@0 | 4101 | |
michael@0 | 4102 | /* c = ... or counter=*/ |
michael@0 | 4103 | if (buf[0] == 'c') { |
michael@0 | 4104 | if (strncmp(buf,"counter", 7) == 0) { |
michael@0 | 4105 | if (sscanf(buf, "counter = %u", &vfy.counter) != 1) { |
michael@0 | 4106 | goto loser; |
michael@0 | 4107 | } |
michael@0 | 4108 | } else { |
michael@0 | 4109 | if (sscanf(buf, "c = %u", &vfy.counter) != 1) { |
michael@0 | 4110 | goto loser; |
michael@0 | 4111 | } |
michael@0 | 4112 | } |
michael@0 | 4113 | |
michael@0 | 4114 | fputs(buf, dsaresp); |
michael@0 | 4115 | if (type == A_1_1_3) { |
michael@0 | 4116 | SECStatus result; |
michael@0 | 4117 | /* only verify P and Q, we have everything now. do it */ |
michael@0 | 4118 | SECStatus rv = PQG_VerifyParams(&pqg, &vfy, &result); |
michael@0 | 4119 | if (rv != SECSuccess) { |
michael@0 | 4120 | goto loser; |
michael@0 | 4121 | } |
michael@0 | 4122 | if (result == SECSuccess) { |
michael@0 | 4123 | fprintf(dsaresp, "Result = P\n"); |
michael@0 | 4124 | } else { |
michael@0 | 4125 | fprintf(dsaresp, "Result = F\n"); |
michael@0 | 4126 | } |
michael@0 | 4127 | fprintf(dsaresp, "\n"); |
michael@0 | 4128 | } |
michael@0 | 4129 | continue; |
michael@0 | 4130 | } |
michael@0 | 4131 | if (strncmp(buf,"pgen_counter", 12) == 0) { |
michael@0 | 4132 | if (sscanf(buf, "pgen_counter = %u", &vfy.counter) != 1) { |
michael@0 | 4133 | goto loser; |
michael@0 | 4134 | } |
michael@0 | 4135 | fputs(buf, dsaresp); |
michael@0 | 4136 | continue; |
michael@0 | 4137 | } |
michael@0 | 4138 | if (strncmp(buf,"qgen_counter", 12) == 0) { |
michael@0 | 4139 | fputs(buf, dsaresp); |
michael@0 | 4140 | if (type == A_1_2_2) { |
michael@0 | 4141 | SECStatus result; |
michael@0 | 4142 | /* only verify P and Q, we have everything now. do it */ |
michael@0 | 4143 | SECStatus rv = PQG_VerifyParams(&pqg, &vfy, &result); |
michael@0 | 4144 | if (rv != SECSuccess) { |
michael@0 | 4145 | goto loser; |
michael@0 | 4146 | } |
michael@0 | 4147 | if (result == SECSuccess) { |
michael@0 | 4148 | fprintf(dsaresp, "Result = P\n"); |
michael@0 | 4149 | } else { |
michael@0 | 4150 | fprintf(dsaresp, "Result = F\n"); |
michael@0 | 4151 | } |
michael@0 | 4152 | fprintf(dsaresp, "\n"); |
michael@0 | 4153 | } |
michael@0 | 4154 | continue; |
michael@0 | 4155 | } |
michael@0 | 4156 | /* H = ... */ |
michael@0 | 4157 | if (buf[0] == 'H') { |
michael@0 | 4158 | SECStatus rv, result = SECFailure; |
michael@0 | 4159 | |
michael@0 | 4160 | i = 1; |
michael@0 | 4161 | while (isspace(buf[i]) || buf[i] == '=') { |
michael@0 | 4162 | i++; |
michael@0 | 4163 | } |
michael@0 | 4164 | for (j=0; isxdigit(buf[i]); i+=2,j++) { |
michael@0 | 4165 | hex_to_byteval(&buf[i], &vfy.h.data[j]); |
michael@0 | 4166 | } |
michael@0 | 4167 | vfy.h.len = j; |
michael@0 | 4168 | fputs(buf, dsaresp); |
michael@0 | 4169 | |
michael@0 | 4170 | /* this should be a byte value. Remove the leading zeros. If |
michael@0 | 4171 | * it doesn't reduce to a byte, PQG_VerifyParams will catch it |
michael@0 | 4172 | if (type == A_2_2) { |
michael@0 | 4173 | data_save = vfy.h.data; |
michael@0 | 4174 | while(vfy.h.data[0] && (vfy.h.len > 1)) { |
michael@0 | 4175 | vfy.h.data++; |
michael@0 | 4176 | vfy.h.len--; |
michael@0 | 4177 | } |
michael@0 | 4178 | } */ |
michael@0 | 4179 | |
michael@0 | 4180 | /* Verify the Parameters */ |
michael@0 | 4181 | rv = PQG_VerifyParams(&pqg, &vfy, &result); |
michael@0 | 4182 | if (rv != SECSuccess) { |
michael@0 | 4183 | goto loser; |
michael@0 | 4184 | } |
michael@0 | 4185 | if (result == SECSuccess) { |
michael@0 | 4186 | fprintf(dsaresp, "Result = P\n"); |
michael@0 | 4187 | } else { |
michael@0 | 4188 | fprintf(dsaresp, "Result = F\n"); |
michael@0 | 4189 | } |
michael@0 | 4190 | fprintf(dsaresp, "\n"); |
michael@0 | 4191 | continue; |
michael@0 | 4192 | } |
michael@0 | 4193 | } |
michael@0 | 4194 | loser: |
michael@0 | 4195 | fclose(dsareq); |
michael@0 | 4196 | if (pqg.prime.data) { /* P */ |
michael@0 | 4197 | SECITEM_ZfreeItem(&pqg.prime, PR_FALSE); |
michael@0 | 4198 | } |
michael@0 | 4199 | if (pqg.subPrime.data) { /* Q */ |
michael@0 | 4200 | SECITEM_ZfreeItem(&pqg.subPrime, PR_FALSE); |
michael@0 | 4201 | } |
michael@0 | 4202 | if (pqg.base.data) { /* G */ |
michael@0 | 4203 | SECITEM_ZfreeItem(&pqg.base, PR_FALSE); |
michael@0 | 4204 | } |
michael@0 | 4205 | if (vfy.seed.data) { /* seed */ |
michael@0 | 4206 | SECITEM_ZfreeItem(&vfy.seed, PR_FALSE); |
michael@0 | 4207 | } |
michael@0 | 4208 | if (vfy.h.data) { /* H */ |
michael@0 | 4209 | SECITEM_ZfreeItem(&vfy.h, PR_FALSE); |
michael@0 | 4210 | } |
michael@0 | 4211 | |
michael@0 | 4212 | } |
michael@0 | 4213 | |
michael@0 | 4214 | /* |
michael@0 | 4215 | * Perform the DSA Public Key Validation Test. |
michael@0 | 4216 | * |
michael@0 | 4217 | * reqfn is the pathname of the REQUEST file. |
michael@0 | 4218 | * |
michael@0 | 4219 | * The output RESPONSE file is written to stdout. |
michael@0 | 4220 | */ |
michael@0 | 4221 | void |
michael@0 | 4222 | dsa_pqggen_test(char *reqfn) |
michael@0 | 4223 | { |
michael@0 | 4224 | char buf[800]; /* holds one line from the input REQUEST file |
michael@0 | 4225 | * or to the output RESPONSE file. |
michael@0 | 4226 | * 800 to hold seed = (384 public key (x2 for HEX) |
michael@0 | 4227 | */ |
michael@0 | 4228 | FILE *dsareq; /* input stream from the REQUEST file */ |
michael@0 | 4229 | FILE *dsaresp; /* output stream to the RESPONSE file */ |
michael@0 | 4230 | int count; /* number of times to generate parameters */ |
michael@0 | 4231 | int N; |
michael@0 | 4232 | int L; |
michael@0 | 4233 | int i; |
michael@0 | 4234 | unsigned int j; |
michael@0 | 4235 | PQGParams *pqg = NULL; |
michael@0 | 4236 | PQGVerify *vfy = NULL; |
michael@0 | 4237 | unsigned int keySizeIndex; |
michael@0 | 4238 | dsa_pqg_type type = FIPS186_1; |
michael@0 | 4239 | |
michael@0 | 4240 | dsareq = fopen(reqfn, "r"); |
michael@0 | 4241 | dsaresp = stdout; |
michael@0 | 4242 | while (fgets(buf, sizeof buf, dsareq) != NULL) { |
michael@0 | 4243 | /* a comment or blank line */ |
michael@0 | 4244 | if (buf[0] == '#' || buf[0] == '\n') { |
michael@0 | 4245 | fputs(buf, dsaresp); |
michael@0 | 4246 | continue; |
michael@0 | 4247 | } |
michael@0 | 4248 | |
michael@0 | 4249 | /* [A.xxxxx ] */ |
michael@0 | 4250 | if (buf[0] == '[' && buf[1] == 'A') { |
michael@0 | 4251 | if (strncmp(&buf[1],"A.1.1.2",7) == 0) { |
michael@0 | 4252 | type = A_1_1_2; |
michael@0 | 4253 | } else if (strncmp(&buf[1],"A.2.1",5) == 0) { |
michael@0 | 4254 | fprintf(stderr, "NSS only Generates G with P&Q\n"); |
michael@0 | 4255 | exit(1); |
michael@0 | 4256 | } else if (strncmp(&buf[1],"A.2.3",5) == 0) { |
michael@0 | 4257 | fprintf(stderr, "NSS only Generates G with P&Q\n"); |
michael@0 | 4258 | exit(1); |
michael@0 | 4259 | } else if (strncmp(&buf[1],"A.1.2.1",7) == 0) { |
michael@0 | 4260 | fprintf(stderr, "NSS does not support Shawe-Taylor Primes\n"); |
michael@0 | 4261 | exit(1); |
michael@0 | 4262 | } else { |
michael@0 | 4263 | fprintf(stderr, "Unknown dsa ver test %s\n", &buf[1]); |
michael@0 | 4264 | exit(1); |
michael@0 | 4265 | } |
michael@0 | 4266 | fputs(buf, dsaresp); |
michael@0 | 4267 | continue; |
michael@0 | 4268 | } |
michael@0 | 4269 | |
michael@0 | 4270 | /* [Mod = ... ] */ |
michael@0 | 4271 | if (buf[0] == '[') { |
michael@0 | 4272 | |
michael@0 | 4273 | if (type == FIPS186_1) { |
michael@0 | 4274 | N=160; |
michael@0 | 4275 | if (sscanf(buf, "[mod = %d]", &L) != 1) { |
michael@0 | 4276 | goto loser; |
michael@0 | 4277 | } |
michael@0 | 4278 | } else if (sscanf(buf, "[mod = L=%d, N=%d", &L, &N) != 2) { |
michael@0 | 4279 | goto loser; |
michael@0 | 4280 | } |
michael@0 | 4281 | |
michael@0 | 4282 | fputs(buf, dsaresp); |
michael@0 | 4283 | fputc('\n', dsaresp); |
michael@0 | 4284 | |
michael@0 | 4285 | if (type == FIPS186_1) { |
michael@0 | 4286 | /************************************************************ |
michael@0 | 4287 | * PQG_ParamGenSeedLen doesn't take a key size, it takes an |
michael@0 | 4288 | * index that points to a valid key size. |
michael@0 | 4289 | */ |
michael@0 | 4290 | keySizeIndex = PQG_PBITS_TO_INDEX(L); |
michael@0 | 4291 | if(keySizeIndex == -1 || L<512 || L>1024) { |
michael@0 | 4292 | fprintf(dsaresp, |
michael@0 | 4293 | "DSA key size must be a multiple of 64 between 512 " |
michael@0 | 4294 | "and 1024, inclusive"); |
michael@0 | 4295 | goto loser; |
michael@0 | 4296 | } |
michael@0 | 4297 | } |
michael@0 | 4298 | continue; |
michael@0 | 4299 | } |
michael@0 | 4300 | /* N = ... */ |
michael@0 | 4301 | if (buf[0] == 'N') { |
michael@0 | 4302 | if (sscanf(buf, "N = %d", &count) != 1) { |
michael@0 | 4303 | goto loser; |
michael@0 | 4304 | } |
michael@0 | 4305 | for (i = 0; i < count; i++) { |
michael@0 | 4306 | SECStatus rv; |
michael@0 | 4307 | |
michael@0 | 4308 | if (type == FIPS186_1) { |
michael@0 | 4309 | rv = PQG_ParamGenSeedLen(keySizeIndex, PQG_TEST_SEED_BYTES, |
michael@0 | 4310 | &pqg, &vfy); |
michael@0 | 4311 | } else { |
michael@0 | 4312 | rv = PQG_ParamGenV2(L, N, N, &pqg, &vfy); |
michael@0 | 4313 | } |
michael@0 | 4314 | if (rv != SECSuccess) { |
michael@0 | 4315 | fprintf(dsaresp, |
michael@0 | 4316 | "ERROR: Unable to generate PQG parameters"); |
michael@0 | 4317 | goto loser; |
michael@0 | 4318 | } |
michael@0 | 4319 | to_hex_str(buf, pqg->prime.data, pqg->prime.len); |
michael@0 | 4320 | fprintf(dsaresp, "P = %s\n", buf); |
michael@0 | 4321 | to_hex_str(buf, pqg->subPrime.data, pqg->subPrime.len); |
michael@0 | 4322 | fprintf(dsaresp, "Q = %s\n", buf); |
michael@0 | 4323 | to_hex_str(buf, pqg->base.data, pqg->base.len); |
michael@0 | 4324 | fprintf(dsaresp, "G = %s\n", buf); |
michael@0 | 4325 | if (type == FIPS186_1) { |
michael@0 | 4326 | to_hex_str(buf, vfy->seed.data, vfy->seed.len); |
michael@0 | 4327 | fprintf(dsaresp, "Seed = %s\n", buf); |
michael@0 | 4328 | fprintf(dsaresp, "c = %d\n", vfy->counter); |
michael@0 | 4329 | to_hex_str(buf, vfy->h.data, vfy->h.len); |
michael@0 | 4330 | fputs("H = ", dsaresp); |
michael@0 | 4331 | for (j=vfy->h.len; j< pqg->prime.len; j++) { |
michael@0 | 4332 | fprintf(dsaresp, "00"); |
michael@0 | 4333 | } |
michael@0 | 4334 | fprintf(dsaresp, "%s\n", buf); |
michael@0 | 4335 | } else { |
michael@0 | 4336 | fprintf(dsaresp, "counter = %d\n", vfy->counter); |
michael@0 | 4337 | fprintf(dsaresp, "index = %02x\n", vfy->h.data[0]); |
michael@0 | 4338 | to_hex_str(buf, vfy->seed.data, vfy->seed.len); |
michael@0 | 4339 | fprintf(dsaresp, "domain_parameter_seed = %s\n", buf); |
michael@0 | 4340 | } |
michael@0 | 4341 | fputc('\n', dsaresp); |
michael@0 | 4342 | if(pqg!=NULL) { |
michael@0 | 4343 | PQG_DestroyParams(pqg); |
michael@0 | 4344 | pqg = NULL; |
michael@0 | 4345 | } |
michael@0 | 4346 | if(vfy!=NULL) { |
michael@0 | 4347 | PQG_DestroyVerify(vfy); |
michael@0 | 4348 | vfy = NULL; |
michael@0 | 4349 | } |
michael@0 | 4350 | } |
michael@0 | 4351 | |
michael@0 | 4352 | continue; |
michael@0 | 4353 | } |
michael@0 | 4354 | |
michael@0 | 4355 | } |
michael@0 | 4356 | loser: |
michael@0 | 4357 | fclose(dsareq); |
michael@0 | 4358 | if(pqg!=NULL) { |
michael@0 | 4359 | PQG_DestroyParams(pqg); |
michael@0 | 4360 | } |
michael@0 | 4361 | if(vfy!=NULL) { |
michael@0 | 4362 | PQG_DestroyVerify(vfy); |
michael@0 | 4363 | } |
michael@0 | 4364 | } |
michael@0 | 4365 | |
michael@0 | 4366 | |
michael@0 | 4367 | /* |
michael@0 | 4368 | * Perform the DSA Signature Generation Test. |
michael@0 | 4369 | * |
michael@0 | 4370 | * reqfn is the pathname of the REQUEST file. |
michael@0 | 4371 | * |
michael@0 | 4372 | * The output RESPONSE file is written to stdout. |
michael@0 | 4373 | */ |
michael@0 | 4374 | void |
michael@0 | 4375 | dsa_siggen_test(char *reqfn) |
michael@0 | 4376 | { |
michael@0 | 4377 | char buf[800]; /* holds one line from the input REQUEST file |
michael@0 | 4378 | * or to the output RESPONSE file. |
michael@0 | 4379 | * max for Msg = .... |
michael@0 | 4380 | */ |
michael@0 | 4381 | FILE *dsareq; /* input stream from the REQUEST file */ |
michael@0 | 4382 | FILE *dsaresp; /* output stream to the RESPONSE file */ |
michael@0 | 4383 | int modulus; |
michael@0 | 4384 | int L; |
michael@0 | 4385 | int N; |
michael@0 | 4386 | int i, j; |
michael@0 | 4387 | PRBool use_dsa1 = PR_FALSE; |
michael@0 | 4388 | PQGParams *pqg = NULL; |
michael@0 | 4389 | PQGVerify *vfy = NULL; |
michael@0 | 4390 | DSAPrivateKey *dsakey = NULL; |
michael@0 | 4391 | int keySizeIndex; /* index for valid key sizes */ |
michael@0 | 4392 | unsigned char hashBuf[HASH_LENGTH_MAX]; /* SHA-x hash (160-512 bits) */ |
michael@0 | 4393 | unsigned char sig[DSA_MAX_SIGNATURE_LEN]; |
michael@0 | 4394 | SECItem digest, signature; |
michael@0 | 4395 | HASH_HashType hashType = HASH_AlgNULL; |
michael@0 | 4396 | int hashNum = 0; |
michael@0 | 4397 | |
michael@0 | 4398 | dsareq = fopen(reqfn, "r"); |
michael@0 | 4399 | dsaresp = stdout; |
michael@0 | 4400 | |
michael@0 | 4401 | while (fgets(buf, sizeof buf, dsareq) != NULL) { |
michael@0 | 4402 | /* a comment or blank line */ |
michael@0 | 4403 | if (buf[0] == '#' || buf[0] == '\n') { |
michael@0 | 4404 | fputs(buf, dsaresp); |
michael@0 | 4405 | continue; |
michael@0 | 4406 | } |
michael@0 | 4407 | |
michael@0 | 4408 | /* [Mod = x] */ |
michael@0 | 4409 | if (buf[0] == '[') { |
michael@0 | 4410 | if(pqg!=NULL) { |
michael@0 | 4411 | PQG_DestroyParams(pqg); |
michael@0 | 4412 | pqg = NULL; |
michael@0 | 4413 | } |
michael@0 | 4414 | if(vfy!=NULL) { |
michael@0 | 4415 | PQG_DestroyVerify(vfy); |
michael@0 | 4416 | vfy = NULL; |
michael@0 | 4417 | } |
michael@0 | 4418 | if (dsakey != NULL) { |
michael@0 | 4419 | PORT_FreeArena(dsakey->params.arena, PR_TRUE); |
michael@0 | 4420 | dsakey = NULL; |
michael@0 | 4421 | } |
michael@0 | 4422 | |
michael@0 | 4423 | if (sscanf(buf, "[mod = L=%d, N=%d, SHA-%d]", &L, & N, |
michael@0 | 4424 | &hashNum) != 3) { |
michael@0 | 4425 | use_dsa1 = PR_TRUE; |
michael@0 | 4426 | hashNum = 1; |
michael@0 | 4427 | if (sscanf(buf, "[mod = %d]", &modulus) != 1) { |
michael@0 | 4428 | goto loser; |
michael@0 | 4429 | } |
michael@0 | 4430 | } |
michael@0 | 4431 | fputs(buf, dsaresp); |
michael@0 | 4432 | fputc('\n', dsaresp); |
michael@0 | 4433 | |
michael@0 | 4434 | /**************************************************************** |
michael@0 | 4435 | * PQG_ParamGenSeedLen doesn't take a key size, it takes an index |
michael@0 | 4436 | * that points to a valid key size. |
michael@0 | 4437 | */ |
michael@0 | 4438 | if (use_dsa1) { |
michael@0 | 4439 | keySizeIndex = PQG_PBITS_TO_INDEX(modulus); |
michael@0 | 4440 | if(keySizeIndex == -1 || modulus<512 || modulus>1024) { |
michael@0 | 4441 | fprintf(dsaresp, |
michael@0 | 4442 | "DSA key size must be a multiple of 64 between 512 " |
michael@0 | 4443 | "and 1024, inclusive"); |
michael@0 | 4444 | goto loser; |
michael@0 | 4445 | } |
michael@0 | 4446 | /* Generate PQG and output PQG */ |
michael@0 | 4447 | if (PQG_ParamGenSeedLen(keySizeIndex, PQG_TEST_SEED_BYTES, |
michael@0 | 4448 | &pqg, &vfy) != SECSuccess) { |
michael@0 | 4449 | fprintf(dsaresp, |
michael@0 | 4450 | "ERROR: Unable to generate PQG parameters"); |
michael@0 | 4451 | goto loser; |
michael@0 | 4452 | } |
michael@0 | 4453 | } else { |
michael@0 | 4454 | if (PQG_ParamGenV2(L, N, N, &pqg, &vfy) != SECSuccess) { |
michael@0 | 4455 | fprintf(dsaresp, |
michael@0 | 4456 | "ERROR: Unable to generate PQG parameters"); |
michael@0 | 4457 | goto loser; |
michael@0 | 4458 | } |
michael@0 | 4459 | } |
michael@0 | 4460 | to_hex_str(buf, pqg->prime.data, pqg->prime.len); |
michael@0 | 4461 | fprintf(dsaresp, "P = %s\n", buf); |
michael@0 | 4462 | to_hex_str(buf, pqg->subPrime.data, pqg->subPrime.len); |
michael@0 | 4463 | fprintf(dsaresp, "Q = %s\n", buf); |
michael@0 | 4464 | to_hex_str(buf, pqg->base.data, pqg->base.len); |
michael@0 | 4465 | fprintf(dsaresp, "G = %s\n", buf); |
michael@0 | 4466 | |
michael@0 | 4467 | /* create DSA Key */ |
michael@0 | 4468 | if (DSA_NewKey(pqg, &dsakey) != SECSuccess) { |
michael@0 | 4469 | fprintf(dsaresp, "ERROR: Unable to generate DSA key"); |
michael@0 | 4470 | goto loser; |
michael@0 | 4471 | } |
michael@0 | 4472 | |
michael@0 | 4473 | hashType = sha_get_hashType(hashNum); |
michael@0 | 4474 | if (hashType == HASH_AlgNULL) { |
michael@0 | 4475 | fprintf(dsaresp, "ERROR: invalid hash (SHA-%d)",hashNum); |
michael@0 | 4476 | goto loser; |
michael@0 | 4477 | } |
michael@0 | 4478 | continue; |
michael@0 | 4479 | } |
michael@0 | 4480 | |
michael@0 | 4481 | /* Msg = ... */ |
michael@0 | 4482 | if (strncmp(buf, "Msg", 3) == 0) { |
michael@0 | 4483 | unsigned char msg[128]; /* MAX msg 128 */ |
michael@0 | 4484 | unsigned int len = 0; |
michael@0 | 4485 | |
michael@0 | 4486 | if (hashType == HASH_AlgNULL) { |
michael@0 | 4487 | fprintf(dsaresp, "ERROR: Hash Alg not set"); |
michael@0 | 4488 | goto loser; |
michael@0 | 4489 | } |
michael@0 | 4490 | |
michael@0 | 4491 | memset(hashBuf, 0, sizeof hashBuf); |
michael@0 | 4492 | memset(sig, 0, sizeof sig); |
michael@0 | 4493 | |
michael@0 | 4494 | i = 3; |
michael@0 | 4495 | while (isspace(buf[i]) || buf[i] == '=') { |
michael@0 | 4496 | i++; |
michael@0 | 4497 | } |
michael@0 | 4498 | for (j=0; isxdigit(buf[i]); i+=2,j++) { |
michael@0 | 4499 | hex_to_byteval(&buf[i], &msg[j]); |
michael@0 | 4500 | } |
michael@0 | 4501 | if (fips_hashBuf(hashType, hashBuf, msg, j) != SECSuccess) { |
michael@0 | 4502 | fprintf(dsaresp, "ERROR: Unable to generate SHA% digest", |
michael@0 | 4503 | hashNum); |
michael@0 | 4504 | goto loser; |
michael@0 | 4505 | } |
michael@0 | 4506 | |
michael@0 | 4507 | |
michael@0 | 4508 | digest.type = siBuffer; |
michael@0 | 4509 | digest.data = hashBuf; |
michael@0 | 4510 | digest.len = fips_hashLen(hashType); |
michael@0 | 4511 | signature.type = siBuffer; |
michael@0 | 4512 | signature.data = sig; |
michael@0 | 4513 | signature.len = sizeof sig; |
michael@0 | 4514 | |
michael@0 | 4515 | if (DSA_SignDigest(dsakey, &signature, &digest) != SECSuccess) { |
michael@0 | 4516 | fprintf(dsaresp, "ERROR: Unable to generate DSA signature"); |
michael@0 | 4517 | goto loser; |
michael@0 | 4518 | } |
michael@0 | 4519 | len = signature.len; |
michael@0 | 4520 | if (len%2 != 0) { |
michael@0 | 4521 | goto loser; |
michael@0 | 4522 | } |
michael@0 | 4523 | len = len/2; |
michael@0 | 4524 | |
michael@0 | 4525 | /* output the orginal Msg, and generated Y, R, and S */ |
michael@0 | 4526 | fputs(buf, dsaresp); |
michael@0 | 4527 | to_hex_str(buf, dsakey->publicValue.data, |
michael@0 | 4528 | dsakey->publicValue.len); |
michael@0 | 4529 | fprintf(dsaresp, "Y = %s\n", buf); |
michael@0 | 4530 | to_hex_str(buf, &signature.data[0], len); |
michael@0 | 4531 | fprintf(dsaresp, "R = %s\n", buf); |
michael@0 | 4532 | to_hex_str(buf, &signature.data[len], len); |
michael@0 | 4533 | fprintf(dsaresp, "S = %s\n", buf); |
michael@0 | 4534 | fputc('\n', dsaresp); |
michael@0 | 4535 | continue; |
michael@0 | 4536 | } |
michael@0 | 4537 | |
michael@0 | 4538 | } |
michael@0 | 4539 | loser: |
michael@0 | 4540 | fclose(dsareq); |
michael@0 | 4541 | if(pqg != NULL) { |
michael@0 | 4542 | PQG_DestroyParams(pqg); |
michael@0 | 4543 | pqg = NULL; |
michael@0 | 4544 | } |
michael@0 | 4545 | if(vfy != NULL) { |
michael@0 | 4546 | PQG_DestroyVerify(vfy); |
michael@0 | 4547 | vfy = NULL; |
michael@0 | 4548 | } |
michael@0 | 4549 | if (dsakey) { |
michael@0 | 4550 | PORT_FreeArena(dsakey->params.arena, PR_TRUE); |
michael@0 | 4551 | dsakey = NULL; |
michael@0 | 4552 | } |
michael@0 | 4553 | } |
michael@0 | 4554 | |
michael@0 | 4555 | /* |
michael@0 | 4556 | * Perform the DSA Signature Verification Test. |
michael@0 | 4557 | * |
michael@0 | 4558 | * reqfn is the pathname of the REQUEST file. |
michael@0 | 4559 | * |
michael@0 | 4560 | * The output RESPONSE file is written to stdout. |
michael@0 | 4561 | */ |
michael@0 | 4562 | void |
michael@0 | 4563 | dsa_sigver_test(char *reqfn) |
michael@0 | 4564 | { |
michael@0 | 4565 | char buf[800]; /* holds one line from the input REQUEST file |
michael@0 | 4566 | * or to the output RESPONSE file. |
michael@0 | 4567 | * max for Msg = .... |
michael@0 | 4568 | */ |
michael@0 | 4569 | FILE *dsareq; /* input stream from the REQUEST file */ |
michael@0 | 4570 | FILE *dsaresp; /* output stream to the RESPONSE file */ |
michael@0 | 4571 | int L; |
michael@0 | 4572 | int N; |
michael@0 | 4573 | unsigned int i, j; |
michael@0 | 4574 | SECItem digest, signature; |
michael@0 | 4575 | DSAPublicKey pubkey; |
michael@0 | 4576 | unsigned int pgySize; /* size for p, g, and y */ |
michael@0 | 4577 | unsigned char hashBuf[HASH_LENGTH_MAX]; /* SHA-x hash (160-512 bits) */ |
michael@0 | 4578 | unsigned char sig[DSA_MAX_SIGNATURE_LEN]; |
michael@0 | 4579 | HASH_HashType hashType = HASH_AlgNULL; |
michael@0 | 4580 | int hashNum = 0; |
michael@0 | 4581 | |
michael@0 | 4582 | dsareq = fopen(reqfn, "r"); |
michael@0 | 4583 | dsaresp = stdout; |
michael@0 | 4584 | memset(&pubkey, 0, sizeof(pubkey)); |
michael@0 | 4585 | |
michael@0 | 4586 | while (fgets(buf, sizeof buf, dsareq) != NULL) { |
michael@0 | 4587 | /* a comment or blank line */ |
michael@0 | 4588 | if (buf[0] == '#' || buf[0] == '\n') { |
michael@0 | 4589 | fputs(buf, dsaresp); |
michael@0 | 4590 | continue; |
michael@0 | 4591 | } |
michael@0 | 4592 | |
michael@0 | 4593 | /* [Mod = x] */ |
michael@0 | 4594 | if (buf[0] == '[') { |
michael@0 | 4595 | |
michael@0 | 4596 | if (sscanf(buf, "[mod = L=%d, N=%d, SHA-%d]", &L, & N, |
michael@0 | 4597 | &hashNum) != 3) { |
michael@0 | 4598 | N=160; |
michael@0 | 4599 | hashNum = 1; |
michael@0 | 4600 | if (sscanf(buf, "[mod = %d]", &L) != 1) { |
michael@0 | 4601 | goto loser; |
michael@0 | 4602 | } |
michael@0 | 4603 | } |
michael@0 | 4604 | |
michael@0 | 4605 | if (pubkey.params.prime.data) { /* P */ |
michael@0 | 4606 | SECITEM_ZfreeItem(&pubkey.params.prime, PR_FALSE); |
michael@0 | 4607 | } |
michael@0 | 4608 | if (pubkey.params.subPrime.data) { /* Q */ |
michael@0 | 4609 | SECITEM_ZfreeItem(&pubkey.params.subPrime, PR_FALSE); |
michael@0 | 4610 | } |
michael@0 | 4611 | if (pubkey.params.base.data) { /* G */ |
michael@0 | 4612 | SECITEM_ZfreeItem(&pubkey.params.base, PR_FALSE); |
michael@0 | 4613 | } |
michael@0 | 4614 | if (pubkey.publicValue.data) { /* Y */ |
michael@0 | 4615 | SECITEM_ZfreeItem(&pubkey.publicValue, PR_FALSE); |
michael@0 | 4616 | } |
michael@0 | 4617 | fputs(buf, dsaresp); |
michael@0 | 4618 | |
michael@0 | 4619 | /* calculate the size of p, g, and y then allocate items */ |
michael@0 | 4620 | pgySize = L/8; |
michael@0 | 4621 | SECITEM_AllocItem(NULL, &pubkey.params.prime, pgySize); |
michael@0 | 4622 | SECITEM_AllocItem(NULL, &pubkey.params.base, pgySize); |
michael@0 | 4623 | SECITEM_AllocItem(NULL, &pubkey.publicValue, pgySize); |
michael@0 | 4624 | pubkey.params.prime.len = pubkey.params.base.len = pgySize; |
michael@0 | 4625 | pubkey.publicValue.len = pgySize; |
michael@0 | 4626 | |
michael@0 | 4627 | /* q always N/8 bytes */ |
michael@0 | 4628 | SECITEM_AllocItem(NULL, &pubkey.params.subPrime, N/8); |
michael@0 | 4629 | pubkey.params.subPrime.len = N/8; |
michael@0 | 4630 | |
michael@0 | 4631 | hashType = sha_get_hashType(hashNum); |
michael@0 | 4632 | if (hashType == HASH_AlgNULL) { |
michael@0 | 4633 | fprintf(dsaresp, "ERROR: invalid hash (SHA-%d)",hashNum); |
michael@0 | 4634 | goto loser; |
michael@0 | 4635 | } |
michael@0 | 4636 | |
michael@0 | 4637 | continue; |
michael@0 | 4638 | } |
michael@0 | 4639 | /* P = ... */ |
michael@0 | 4640 | if (buf[0] == 'P') { |
michael@0 | 4641 | i = 1; |
michael@0 | 4642 | while (isspace(buf[i]) || buf[i] == '=') { |
michael@0 | 4643 | i++; |
michael@0 | 4644 | } |
michael@0 | 4645 | memset(pubkey.params.prime.data, 0, pubkey.params.prime.len); |
michael@0 | 4646 | for (j=0; j< pubkey.params.prime.len; i+=2,j++) { |
michael@0 | 4647 | hex_to_byteval(&buf[i], &pubkey.params.prime.data[j]); |
michael@0 | 4648 | } |
michael@0 | 4649 | |
michael@0 | 4650 | fputs(buf, dsaresp); |
michael@0 | 4651 | continue; |
michael@0 | 4652 | } |
michael@0 | 4653 | |
michael@0 | 4654 | /* Q = ... */ |
michael@0 | 4655 | if (buf[0] == 'Q') { |
michael@0 | 4656 | i = 1; |
michael@0 | 4657 | while (isspace(buf[i]) || buf[i] == '=') { |
michael@0 | 4658 | i++; |
michael@0 | 4659 | } |
michael@0 | 4660 | memset(pubkey.params.subPrime.data, 0, pubkey.params.subPrime.len); |
michael@0 | 4661 | for (j=0; j< pubkey.params.subPrime.len; i+=2,j++) { |
michael@0 | 4662 | hex_to_byteval(&buf[i], &pubkey.params.subPrime.data[j]); |
michael@0 | 4663 | } |
michael@0 | 4664 | |
michael@0 | 4665 | fputs(buf, dsaresp); |
michael@0 | 4666 | continue; |
michael@0 | 4667 | } |
michael@0 | 4668 | |
michael@0 | 4669 | /* G = ... */ |
michael@0 | 4670 | if (buf[0] == 'G') { |
michael@0 | 4671 | i = 1; |
michael@0 | 4672 | while (isspace(buf[i]) || buf[i] == '=') { |
michael@0 | 4673 | i++; |
michael@0 | 4674 | } |
michael@0 | 4675 | memset(pubkey.params.base.data, 0, pubkey.params.base.len); |
michael@0 | 4676 | for (j=0; j< pubkey.params.base.len; i+=2,j++) { |
michael@0 | 4677 | hex_to_byteval(&buf[i], &pubkey.params.base.data[j]); |
michael@0 | 4678 | } |
michael@0 | 4679 | |
michael@0 | 4680 | fputs(buf, dsaresp); |
michael@0 | 4681 | continue; |
michael@0 | 4682 | } |
michael@0 | 4683 | |
michael@0 | 4684 | /* Msg = ... */ |
michael@0 | 4685 | if (strncmp(buf, "Msg", 3) == 0) { |
michael@0 | 4686 | unsigned char msg[128]; /* MAX msg 128 */ |
michael@0 | 4687 | memset(hashBuf, 0, sizeof hashBuf); |
michael@0 | 4688 | |
michael@0 | 4689 | if (hashType == HASH_AlgNULL) { |
michael@0 | 4690 | fprintf(dsaresp, "ERROR: Hash Alg not set"); |
michael@0 | 4691 | goto loser; |
michael@0 | 4692 | } |
michael@0 | 4693 | |
michael@0 | 4694 | i = 3; |
michael@0 | 4695 | while (isspace(buf[i]) || buf[i] == '=') { |
michael@0 | 4696 | i++; |
michael@0 | 4697 | } |
michael@0 | 4698 | for (j=0; isxdigit(buf[i]); i+=2,j++) { |
michael@0 | 4699 | hex_to_byteval(&buf[i], &msg[j]); |
michael@0 | 4700 | } |
michael@0 | 4701 | if (fips_hashBuf(hashType, hashBuf, msg, j) != SECSuccess) { |
michael@0 | 4702 | fprintf(dsaresp, "ERROR: Unable to generate SHA-%d digest", |
michael@0 | 4703 | hashNum); |
michael@0 | 4704 | goto loser; |
michael@0 | 4705 | } |
michael@0 | 4706 | |
michael@0 | 4707 | fputs(buf, dsaresp); |
michael@0 | 4708 | continue; |
michael@0 | 4709 | } |
michael@0 | 4710 | |
michael@0 | 4711 | /* Y = ... */ |
michael@0 | 4712 | if (buf[0] == 'Y') { |
michael@0 | 4713 | i = 1; |
michael@0 | 4714 | while (isspace(buf[i]) || buf[i] == '=') { |
michael@0 | 4715 | i++; |
michael@0 | 4716 | } |
michael@0 | 4717 | memset(pubkey.publicValue.data, 0, pubkey.params.subPrime.len); |
michael@0 | 4718 | for (j=0; j< pubkey.publicValue.len; i+=2,j++) { |
michael@0 | 4719 | hex_to_byteval(&buf[i], &pubkey.publicValue.data[j]); |
michael@0 | 4720 | } |
michael@0 | 4721 | |
michael@0 | 4722 | fputs(buf, dsaresp); |
michael@0 | 4723 | continue; |
michael@0 | 4724 | } |
michael@0 | 4725 | |
michael@0 | 4726 | /* R = ... */ |
michael@0 | 4727 | if (buf[0] == 'R') { |
michael@0 | 4728 | memset(sig, 0, sizeof sig); |
michael@0 | 4729 | i = 1; |
michael@0 | 4730 | while (isspace(buf[i]) || buf[i] == '=') { |
michael@0 | 4731 | i++; |
michael@0 | 4732 | } |
michael@0 | 4733 | for (j=0; j< pubkey.params.subPrime.len; i+=2,j++) { |
michael@0 | 4734 | hex_to_byteval(&buf[i], &sig[j]); |
michael@0 | 4735 | } |
michael@0 | 4736 | |
michael@0 | 4737 | fputs(buf, dsaresp); |
michael@0 | 4738 | continue; |
michael@0 | 4739 | } |
michael@0 | 4740 | |
michael@0 | 4741 | /* S = ... */ |
michael@0 | 4742 | if (buf[0] == 'S') { |
michael@0 | 4743 | if (hashType == HASH_AlgNULL) { |
michael@0 | 4744 | fprintf(dsaresp, "ERROR: Hash Alg not set"); |
michael@0 | 4745 | goto loser; |
michael@0 | 4746 | } |
michael@0 | 4747 | |
michael@0 | 4748 | i = 1; |
michael@0 | 4749 | while (isspace(buf[i]) || buf[i] == '=') { |
michael@0 | 4750 | i++; |
michael@0 | 4751 | } |
michael@0 | 4752 | for (j=pubkey.params.subPrime.len; |
michael@0 | 4753 | j< pubkey.params.subPrime.len*2; i+=2,j++) { |
michael@0 | 4754 | hex_to_byteval(&buf[i], &sig[j]); |
michael@0 | 4755 | } |
michael@0 | 4756 | fputs(buf, dsaresp); |
michael@0 | 4757 | |
michael@0 | 4758 | digest.type = siBuffer; |
michael@0 | 4759 | digest.data = hashBuf; |
michael@0 | 4760 | digest.len = fips_hashLen(hashType); |
michael@0 | 4761 | signature.type = siBuffer; |
michael@0 | 4762 | signature.data = sig; |
michael@0 | 4763 | signature.len = pubkey.params.subPrime.len*2; |
michael@0 | 4764 | |
michael@0 | 4765 | if (DSA_VerifyDigest(&pubkey, &signature, &digest) == SECSuccess) { |
michael@0 | 4766 | fprintf(dsaresp, "Result = P\n"); |
michael@0 | 4767 | } else { |
michael@0 | 4768 | fprintf(dsaresp, "Result = F\n"); |
michael@0 | 4769 | } |
michael@0 | 4770 | fprintf(dsaresp, "\n"); |
michael@0 | 4771 | continue; |
michael@0 | 4772 | } |
michael@0 | 4773 | } |
michael@0 | 4774 | loser: |
michael@0 | 4775 | fclose(dsareq); |
michael@0 | 4776 | if (pubkey.params.prime.data) { /* P */ |
michael@0 | 4777 | SECITEM_ZfreeItem(&pubkey.params.prime, PR_FALSE); |
michael@0 | 4778 | } |
michael@0 | 4779 | if (pubkey.params.subPrime.data) { /* Q */ |
michael@0 | 4780 | SECITEM_ZfreeItem(&pubkey.params.subPrime, PR_FALSE); |
michael@0 | 4781 | } |
michael@0 | 4782 | if (pubkey.params.base.data) { /* G */ |
michael@0 | 4783 | SECITEM_ZfreeItem(&pubkey.params.base, PR_FALSE); |
michael@0 | 4784 | } |
michael@0 | 4785 | if (pubkey.publicValue.data) { /* Y */ |
michael@0 | 4786 | SECITEM_ZfreeItem(&pubkey.publicValue, PR_FALSE); |
michael@0 | 4787 | } |
michael@0 | 4788 | } |
michael@0 | 4789 | |
michael@0 | 4790 | /* |
michael@0 | 4791 | * Perform the RSA Signature Generation Test. |
michael@0 | 4792 | * |
michael@0 | 4793 | * reqfn is the pathname of the REQUEST file. |
michael@0 | 4794 | * |
michael@0 | 4795 | * The output RESPONSE file is written to stdout. |
michael@0 | 4796 | */ |
michael@0 | 4797 | void |
michael@0 | 4798 | rsa_siggen_test(char *reqfn) |
michael@0 | 4799 | { |
michael@0 | 4800 | char buf[2*RSA_MAX_TEST_MODULUS_BYTES+1]; |
michael@0 | 4801 | /* buf holds one line from the input REQUEST file |
michael@0 | 4802 | * or to the output RESPONSE file. |
michael@0 | 4803 | * 2x for HEX output + 1 for \n |
michael@0 | 4804 | */ |
michael@0 | 4805 | FILE *rsareq; /* input stream from the REQUEST file */ |
michael@0 | 4806 | FILE *rsaresp; /* output stream to the RESPONSE file */ |
michael@0 | 4807 | int i, j; |
michael@0 | 4808 | unsigned char sha[HASH_LENGTH_MAX]; /* SHA digest */ |
michael@0 | 4809 | unsigned int shaLength = 0; /* length of SHA */ |
michael@0 | 4810 | HASH_HashType shaAlg = HASH_AlgNULL; /* type of SHA Alg */ |
michael@0 | 4811 | SECOidTag shaOid = SEC_OID_UNKNOWN; |
michael@0 | 4812 | int modulus; /* the Modulus size */ |
michael@0 | 4813 | int publicExponent = DEFAULT_RSA_PUBLIC_EXPONENT; |
michael@0 | 4814 | SECItem pe = {0, 0, 0 }; |
michael@0 | 4815 | unsigned char pubEx[4]; |
michael@0 | 4816 | int peCount = 0; |
michael@0 | 4817 | |
michael@0 | 4818 | RSAPrivateKey *rsaBlapiPrivKey = NULL; /* holds RSA private and |
michael@0 | 4819 | * public keys */ |
michael@0 | 4820 | RSAPublicKey *rsaBlapiPublicKey = NULL; /* hold RSA public key */ |
michael@0 | 4821 | |
michael@0 | 4822 | rsareq = fopen(reqfn, "r"); |
michael@0 | 4823 | rsaresp = stdout; |
michael@0 | 4824 | |
michael@0 | 4825 | /* calculate the exponent */ |
michael@0 | 4826 | for (i=0; i < 4; i++) { |
michael@0 | 4827 | if (peCount || (publicExponent & |
michael@0 | 4828 | ((unsigned long)0xff000000L >> (i*8)))) { |
michael@0 | 4829 | pubEx[peCount] = |
michael@0 | 4830 | (unsigned char)((publicExponent >> (3-i)*8) & 0xff); |
michael@0 | 4831 | peCount++; |
michael@0 | 4832 | } |
michael@0 | 4833 | } |
michael@0 | 4834 | pe.len = peCount; |
michael@0 | 4835 | pe.data = &pubEx[0]; |
michael@0 | 4836 | pe.type = siBuffer; |
michael@0 | 4837 | |
michael@0 | 4838 | while (fgets(buf, sizeof buf, rsareq) != NULL) { |
michael@0 | 4839 | /* a comment or blank line */ |
michael@0 | 4840 | if (buf[0] == '#' || buf[0] == '\n') { |
michael@0 | 4841 | fputs(buf, rsaresp); |
michael@0 | 4842 | continue; |
michael@0 | 4843 | } |
michael@0 | 4844 | |
michael@0 | 4845 | /* [mod = ...] */ |
michael@0 | 4846 | if (buf[0] == '[') { |
michael@0 | 4847 | |
michael@0 | 4848 | if (sscanf(buf, "[mod = %d]", &modulus) != 1) { |
michael@0 | 4849 | goto loser; |
michael@0 | 4850 | } |
michael@0 | 4851 | if (modulus > RSA_MAX_TEST_MODULUS_BITS) { |
michael@0 | 4852 | fprintf(rsaresp,"ERROR: modulus greater than test maximum\n"); |
michael@0 | 4853 | goto loser; |
michael@0 | 4854 | } |
michael@0 | 4855 | |
michael@0 | 4856 | fputs(buf, rsaresp); |
michael@0 | 4857 | |
michael@0 | 4858 | if (rsaBlapiPrivKey != NULL) { |
michael@0 | 4859 | PORT_FreeArena(rsaBlapiPrivKey->arena, PR_TRUE); |
michael@0 | 4860 | rsaBlapiPrivKey = NULL; |
michael@0 | 4861 | rsaBlapiPublicKey = NULL; |
michael@0 | 4862 | } |
michael@0 | 4863 | |
michael@0 | 4864 | rsaBlapiPrivKey = RSA_NewKey(modulus, &pe); |
michael@0 | 4865 | if (rsaBlapiPrivKey == NULL) { |
michael@0 | 4866 | fprintf(rsaresp, "Error unable to create RSA key\n"); |
michael@0 | 4867 | goto loser; |
michael@0 | 4868 | } |
michael@0 | 4869 | |
michael@0 | 4870 | to_hex_str(buf, rsaBlapiPrivKey->modulus.data, |
michael@0 | 4871 | rsaBlapiPrivKey->modulus.len); |
michael@0 | 4872 | fprintf(rsaresp, "\nn = %s\n\n", buf); |
michael@0 | 4873 | to_hex_str(buf, rsaBlapiPrivKey->publicExponent.data, |
michael@0 | 4874 | rsaBlapiPrivKey->publicExponent.len); |
michael@0 | 4875 | fprintf(rsaresp, "e = %s\n", buf); |
michael@0 | 4876 | /* convert private key to public key. Memory |
michael@0 | 4877 | * is freed with private key's arena */ |
michael@0 | 4878 | rsaBlapiPublicKey = (RSAPublicKey *)PORT_ArenaAlloc( |
michael@0 | 4879 | rsaBlapiPrivKey->arena, |
michael@0 | 4880 | sizeof(RSAPublicKey)); |
michael@0 | 4881 | |
michael@0 | 4882 | rsaBlapiPublicKey->modulus.len = rsaBlapiPrivKey->modulus.len; |
michael@0 | 4883 | rsaBlapiPublicKey->modulus.data = rsaBlapiPrivKey->modulus.data; |
michael@0 | 4884 | rsaBlapiPublicKey->publicExponent.len = |
michael@0 | 4885 | rsaBlapiPrivKey->publicExponent.len; |
michael@0 | 4886 | rsaBlapiPublicKey->publicExponent.data = |
michael@0 | 4887 | rsaBlapiPrivKey->publicExponent.data; |
michael@0 | 4888 | continue; |
michael@0 | 4889 | } |
michael@0 | 4890 | |
michael@0 | 4891 | /* SHAAlg = ... */ |
michael@0 | 4892 | if (strncmp(buf, "SHAAlg", 6) == 0) { |
michael@0 | 4893 | i = 6; |
michael@0 | 4894 | while (isspace(buf[i]) || buf[i] == '=') { |
michael@0 | 4895 | i++; |
michael@0 | 4896 | } |
michael@0 | 4897 | /* set the SHA Algorithm */ |
michael@0 | 4898 | if (strncmp(&buf[i], "SHA1", 4) == 0) { |
michael@0 | 4899 | shaAlg = HASH_AlgSHA1; |
michael@0 | 4900 | } else if (strncmp(&buf[i], "SHA224", 6) == 0) { |
michael@0 | 4901 | shaAlg = HASH_AlgSHA224; |
michael@0 | 4902 | } else if (strncmp(&buf[i], "SHA256", 6) == 0) { |
michael@0 | 4903 | shaAlg = HASH_AlgSHA256; |
michael@0 | 4904 | } else if (strncmp(&buf[i], "SHA384", 6)== 0) { |
michael@0 | 4905 | shaAlg = HASH_AlgSHA384; |
michael@0 | 4906 | } else if (strncmp(&buf[i], "SHA512", 6) == 0) { |
michael@0 | 4907 | shaAlg = HASH_AlgSHA512; |
michael@0 | 4908 | } else { |
michael@0 | 4909 | fprintf(rsaresp, "ERROR: Unable to find SHAAlg type"); |
michael@0 | 4910 | goto loser; |
michael@0 | 4911 | } |
michael@0 | 4912 | fputs(buf, rsaresp); |
michael@0 | 4913 | continue; |
michael@0 | 4914 | |
michael@0 | 4915 | } |
michael@0 | 4916 | /* Msg = ... */ |
michael@0 | 4917 | if (strncmp(buf, "Msg", 3) == 0) { |
michael@0 | 4918 | |
michael@0 | 4919 | unsigned char msg[128]; /* MAX msg 128 */ |
michael@0 | 4920 | unsigned int rsa_bytes_signed; |
michael@0 | 4921 | unsigned char rsa_computed_signature[RSA_MAX_TEST_MODULUS_BYTES]; |
michael@0 | 4922 | SECStatus rv = SECFailure; |
michael@0 | 4923 | NSSLOWKEYPublicKey * rsa_public_key; |
michael@0 | 4924 | NSSLOWKEYPrivateKey * rsa_private_key; |
michael@0 | 4925 | NSSLOWKEYPrivateKey low_RSA_private_key = { NULL, |
michael@0 | 4926 | NSSLOWKEYRSAKey, }; |
michael@0 | 4927 | NSSLOWKEYPublicKey low_RSA_public_key = { NULL, |
michael@0 | 4928 | NSSLOWKEYRSAKey, }; |
michael@0 | 4929 | |
michael@0 | 4930 | low_RSA_private_key.u.rsa = *rsaBlapiPrivKey; |
michael@0 | 4931 | low_RSA_public_key.u.rsa = *rsaBlapiPublicKey; |
michael@0 | 4932 | |
michael@0 | 4933 | rsa_private_key = &low_RSA_private_key; |
michael@0 | 4934 | rsa_public_key = &low_RSA_public_key; |
michael@0 | 4935 | |
michael@0 | 4936 | memset(sha, 0, sizeof sha); |
michael@0 | 4937 | memset(msg, 0, sizeof msg); |
michael@0 | 4938 | rsa_bytes_signed = 0; |
michael@0 | 4939 | memset(rsa_computed_signature, 0, sizeof rsa_computed_signature); |
michael@0 | 4940 | |
michael@0 | 4941 | i = 3; |
michael@0 | 4942 | while (isspace(buf[i]) || buf[i] == '=') { |
michael@0 | 4943 | i++; |
michael@0 | 4944 | } |
michael@0 | 4945 | for (j=0; isxdigit(buf[i]) && j < sizeof(msg); i+=2,j++) { |
michael@0 | 4946 | hex_to_byteval(&buf[i], &msg[j]); |
michael@0 | 4947 | } |
michael@0 | 4948 | shaLength = fips_hashLen(shaAlg); |
michael@0 | 4949 | if (fips_hashBuf(shaAlg,sha,msg,j) != SECSuccess) { |
michael@0 | 4950 | if (shaLength == 0) { |
michael@0 | 4951 | fprintf(rsaresp, "ERROR: SHAAlg not defined."); |
michael@0 | 4952 | } |
michael@0 | 4953 | fprintf(rsaresp, "ERROR: Unable to generate SHA%x", |
michael@0 | 4954 | shaLength == 160 ? 1 : shaLength); |
michael@0 | 4955 | goto loser; |
michael@0 | 4956 | } |
michael@0 | 4957 | shaOid = fips_hashOid(shaAlg); |
michael@0 | 4958 | |
michael@0 | 4959 | /* Perform RSA signature with the RSA private key. */ |
michael@0 | 4960 | rv = RSA_HashSign( shaOid, |
michael@0 | 4961 | rsa_private_key, |
michael@0 | 4962 | rsa_computed_signature, |
michael@0 | 4963 | &rsa_bytes_signed, |
michael@0 | 4964 | nsslowkey_PrivateModulusLen(rsa_private_key), |
michael@0 | 4965 | sha, |
michael@0 | 4966 | shaLength); |
michael@0 | 4967 | |
michael@0 | 4968 | if( rv != SECSuccess ) { |
michael@0 | 4969 | fprintf(rsaresp, "ERROR: RSA_HashSign failed"); |
michael@0 | 4970 | goto loser; |
michael@0 | 4971 | } |
michael@0 | 4972 | |
michael@0 | 4973 | /* Output the signature */ |
michael@0 | 4974 | fputs(buf, rsaresp); |
michael@0 | 4975 | to_hex_str(buf, rsa_computed_signature, rsa_bytes_signed); |
michael@0 | 4976 | fprintf(rsaresp, "S = %s\n", buf); |
michael@0 | 4977 | |
michael@0 | 4978 | /* Perform RSA verification with the RSA public key. */ |
michael@0 | 4979 | rv = RSA_HashCheckSign( shaOid, |
michael@0 | 4980 | rsa_public_key, |
michael@0 | 4981 | rsa_computed_signature, |
michael@0 | 4982 | rsa_bytes_signed, |
michael@0 | 4983 | sha, |
michael@0 | 4984 | shaLength); |
michael@0 | 4985 | if( rv != SECSuccess ) { |
michael@0 | 4986 | fprintf(rsaresp, "ERROR: RSA_HashCheckSign failed"); |
michael@0 | 4987 | goto loser; |
michael@0 | 4988 | } |
michael@0 | 4989 | continue; |
michael@0 | 4990 | } |
michael@0 | 4991 | } |
michael@0 | 4992 | loser: |
michael@0 | 4993 | fclose(rsareq); |
michael@0 | 4994 | |
michael@0 | 4995 | if (rsaBlapiPrivKey != NULL) { |
michael@0 | 4996 | /* frees private and public key */ |
michael@0 | 4997 | PORT_FreeArena(rsaBlapiPrivKey->arena, PR_TRUE); |
michael@0 | 4998 | rsaBlapiPrivKey = NULL; |
michael@0 | 4999 | rsaBlapiPublicKey = NULL; |
michael@0 | 5000 | } |
michael@0 | 5001 | |
michael@0 | 5002 | } |
michael@0 | 5003 | /* |
michael@0 | 5004 | * Perform the RSA Signature Verification Test. |
michael@0 | 5005 | * |
michael@0 | 5006 | * reqfn is the pathname of the REQUEST file. |
michael@0 | 5007 | * |
michael@0 | 5008 | * The output RESPONSE file is written to stdout. |
michael@0 | 5009 | */ |
michael@0 | 5010 | void |
michael@0 | 5011 | rsa_sigver_test(char *reqfn) |
michael@0 | 5012 | { |
michael@0 | 5013 | char buf[2*RSA_MAX_TEST_MODULUS_BYTES+7]; |
michael@0 | 5014 | /* buf holds one line from the input REQUEST file |
michael@0 | 5015 | * or to the output RESPONSE file. |
michael@0 | 5016 | * s = 2x for HEX output + 1 for \n |
michael@0 | 5017 | */ |
michael@0 | 5018 | FILE *rsareq; /* input stream from the REQUEST file */ |
michael@0 | 5019 | FILE *rsaresp; /* output stream to the RESPONSE file */ |
michael@0 | 5020 | int i, j; |
michael@0 | 5021 | unsigned char sha[HASH_LENGTH_MAX]; /* SHA digest */ |
michael@0 | 5022 | unsigned int shaLength = 0; /* actual length of the digest */ |
michael@0 | 5023 | HASH_HashType shaAlg = HASH_AlgNULL; |
michael@0 | 5024 | SECOidTag shaOid = SEC_OID_UNKNOWN; |
michael@0 | 5025 | int modulus = 0; /* the Modulus size */ |
michael@0 | 5026 | unsigned char signature[513]; /* largest signature size + '\n' */ |
michael@0 | 5027 | unsigned int signatureLength = 0; /* actual length of the signature */ |
michael@0 | 5028 | PRBool keyvalid = PR_TRUE; |
michael@0 | 5029 | |
michael@0 | 5030 | RSAPublicKey rsaBlapiPublicKey; /* hold RSA public key */ |
michael@0 | 5031 | |
michael@0 | 5032 | rsareq = fopen(reqfn, "r"); |
michael@0 | 5033 | rsaresp = stdout; |
michael@0 | 5034 | memset(&rsaBlapiPublicKey, 0, sizeof(RSAPublicKey)); |
michael@0 | 5035 | |
michael@0 | 5036 | while (fgets(buf, sizeof buf, rsareq) != NULL) { |
michael@0 | 5037 | /* a comment or blank line */ |
michael@0 | 5038 | if (buf[0] == '#' || buf[0] == '\n') { |
michael@0 | 5039 | fputs(buf, rsaresp); |
michael@0 | 5040 | continue; |
michael@0 | 5041 | } |
michael@0 | 5042 | |
michael@0 | 5043 | /* [Mod = ...] */ |
michael@0 | 5044 | if (buf[0] == '[') { |
michael@0 | 5045 | unsigned int flen; /* length in bytes of the field size */ |
michael@0 | 5046 | |
michael@0 | 5047 | if (rsaBlapiPublicKey.modulus.data) { /* n */ |
michael@0 | 5048 | SECITEM_ZfreeItem(&rsaBlapiPublicKey.modulus, PR_FALSE); |
michael@0 | 5049 | } |
michael@0 | 5050 | if (sscanf(buf, "[mod = %d]", &modulus) != 1) { |
michael@0 | 5051 | goto loser; |
michael@0 | 5052 | } |
michael@0 | 5053 | |
michael@0 | 5054 | if (modulus > RSA_MAX_TEST_MODULUS_BITS) { |
michael@0 | 5055 | fprintf(rsaresp,"ERROR: modulus greater than test maximum\n"); |
michael@0 | 5056 | goto loser; |
michael@0 | 5057 | } |
michael@0 | 5058 | |
michael@0 | 5059 | fputs(buf, rsaresp); |
michael@0 | 5060 | |
michael@0 | 5061 | signatureLength = flen = modulus/8; |
michael@0 | 5062 | |
michael@0 | 5063 | SECITEM_AllocItem(NULL, &rsaBlapiPublicKey.modulus, flen); |
michael@0 | 5064 | if (rsaBlapiPublicKey.modulus.data == NULL) { |
michael@0 | 5065 | goto loser; |
michael@0 | 5066 | } |
michael@0 | 5067 | continue; |
michael@0 | 5068 | } |
michael@0 | 5069 | |
michael@0 | 5070 | /* n = ... modulus */ |
michael@0 | 5071 | if (buf[0] == 'n') { |
michael@0 | 5072 | i = 1; |
michael@0 | 5073 | while (isspace(buf[i]) || buf[i] == '=') { |
michael@0 | 5074 | i++; |
michael@0 | 5075 | } |
michael@0 | 5076 | keyvalid = from_hex_str(&rsaBlapiPublicKey.modulus.data[0], |
michael@0 | 5077 | rsaBlapiPublicKey.modulus.len, |
michael@0 | 5078 | &buf[i]); |
michael@0 | 5079 | |
michael@0 | 5080 | if (!keyvalid) { |
michael@0 | 5081 | fprintf(rsaresp, "ERROR: rsa_sigver n not valid.\n"); |
michael@0 | 5082 | goto loser; |
michael@0 | 5083 | } |
michael@0 | 5084 | fputs(buf, rsaresp); |
michael@0 | 5085 | continue; |
michael@0 | 5086 | } |
michael@0 | 5087 | |
michael@0 | 5088 | /* SHAAlg = ... */ |
michael@0 | 5089 | if (strncmp(buf, "SHAAlg", 6) == 0) { |
michael@0 | 5090 | i = 6; |
michael@0 | 5091 | while (isspace(buf[i]) || buf[i] == '=') { |
michael@0 | 5092 | i++; |
michael@0 | 5093 | } |
michael@0 | 5094 | /* set the SHA Algorithm */ |
michael@0 | 5095 | if (strncmp(&buf[i], "SHA1", 4) == 0) { |
michael@0 | 5096 | shaAlg = HASH_AlgSHA1; |
michael@0 | 5097 | } else if (strncmp(&buf[i], "SHA224", 6) == 0) { |
michael@0 | 5098 | shaAlg = HASH_AlgSHA224; |
michael@0 | 5099 | } else if (strncmp(&buf[i], "SHA256", 6) == 0) { |
michael@0 | 5100 | shaAlg = HASH_AlgSHA256; |
michael@0 | 5101 | } else if (strncmp(&buf[i], "SHA384", 6) == 0) { |
michael@0 | 5102 | shaAlg = HASH_AlgSHA384; |
michael@0 | 5103 | } else if (strncmp(&buf[i], "SHA512", 6) == 0) { |
michael@0 | 5104 | shaAlg = HASH_AlgSHA512; |
michael@0 | 5105 | } else { |
michael@0 | 5106 | fprintf(rsaresp, "ERROR: Unable to find SHAAlg type"); |
michael@0 | 5107 | goto loser; |
michael@0 | 5108 | } |
michael@0 | 5109 | fputs(buf, rsaresp); |
michael@0 | 5110 | continue; |
michael@0 | 5111 | } |
michael@0 | 5112 | |
michael@0 | 5113 | /* e = ... public Key */ |
michael@0 | 5114 | if (buf[0] == 'e') { |
michael@0 | 5115 | unsigned char data[RSA_MAX_TEST_EXPONENT_BYTES]; |
michael@0 | 5116 | unsigned char t; |
michael@0 | 5117 | |
michael@0 | 5118 | memset(data, 0, sizeof data); |
michael@0 | 5119 | |
michael@0 | 5120 | if (rsaBlapiPublicKey.publicExponent.data) { /* e */ |
michael@0 | 5121 | SECITEM_ZfreeItem(&rsaBlapiPublicKey.publicExponent, PR_FALSE); |
michael@0 | 5122 | } |
michael@0 | 5123 | |
michael@0 | 5124 | i = 1; |
michael@0 | 5125 | while (isspace(buf[i]) || buf[i] == '=') { |
michael@0 | 5126 | i++; |
michael@0 | 5127 | } |
michael@0 | 5128 | /* skip leading zero's */ |
michael@0 | 5129 | while (isxdigit(buf[i])) { |
michael@0 | 5130 | hex_to_byteval(&buf[i], &t); |
michael@0 | 5131 | if (t == 0) { |
michael@0 | 5132 | i+=2; |
michael@0 | 5133 | } else break; |
michael@0 | 5134 | } |
michael@0 | 5135 | |
michael@0 | 5136 | /* get the exponent */ |
michael@0 | 5137 | for (j=0; isxdigit(buf[i]) && j < sizeof data; i+=2,j++) { |
michael@0 | 5138 | hex_to_byteval(&buf[i], &data[j]); |
michael@0 | 5139 | } |
michael@0 | 5140 | |
michael@0 | 5141 | if (j == 0) { j = 1; } /* to handle 1 byte length exponents */ |
michael@0 | 5142 | |
michael@0 | 5143 | SECITEM_AllocItem(NULL, &rsaBlapiPublicKey.publicExponent, j); |
michael@0 | 5144 | if (rsaBlapiPublicKey.publicExponent.data == NULL) { |
michael@0 | 5145 | goto loser; |
michael@0 | 5146 | } |
michael@0 | 5147 | |
michael@0 | 5148 | for (i=0; i < j; i++) { |
michael@0 | 5149 | rsaBlapiPublicKey.publicExponent.data[i] = data[i]; |
michael@0 | 5150 | } |
michael@0 | 5151 | |
michael@0 | 5152 | fputs(buf, rsaresp); |
michael@0 | 5153 | continue; |
michael@0 | 5154 | } |
michael@0 | 5155 | |
michael@0 | 5156 | /* Msg = ... */ |
michael@0 | 5157 | if (strncmp(buf, "Msg", 3) == 0) { |
michael@0 | 5158 | unsigned char msg[128]; /* MAX msg 128 */ |
michael@0 | 5159 | |
michael@0 | 5160 | memset(sha, 0, sizeof sha); |
michael@0 | 5161 | memset(msg, 0, sizeof msg); |
michael@0 | 5162 | |
michael@0 | 5163 | i = 3; |
michael@0 | 5164 | while (isspace(buf[i]) || buf[i] == '=') { |
michael@0 | 5165 | i++; |
michael@0 | 5166 | } |
michael@0 | 5167 | |
michael@0 | 5168 | for (j=0; isxdigit(buf[i]) && j < sizeof msg; i+=2,j++) { |
michael@0 | 5169 | hex_to_byteval(&buf[i], &msg[j]); |
michael@0 | 5170 | } |
michael@0 | 5171 | |
michael@0 | 5172 | shaLength = fips_hashLen(shaAlg); |
michael@0 | 5173 | if (fips_hashBuf(shaAlg,sha,msg,j) != SECSuccess) { |
michael@0 | 5174 | if (shaLength == 0) { |
michael@0 | 5175 | fprintf(rsaresp, "ERROR: SHAAlg not defined."); |
michael@0 | 5176 | } |
michael@0 | 5177 | fprintf(rsaresp, "ERROR: Unable to generate SHA%x", |
michael@0 | 5178 | shaLength == 160 ? 1 : shaLength); |
michael@0 | 5179 | goto loser; |
michael@0 | 5180 | } |
michael@0 | 5181 | |
michael@0 | 5182 | fputs(buf, rsaresp); |
michael@0 | 5183 | continue; |
michael@0 | 5184 | |
michael@0 | 5185 | } |
michael@0 | 5186 | |
michael@0 | 5187 | /* S = ... */ |
michael@0 | 5188 | if (buf[0] == 'S') { |
michael@0 | 5189 | SECStatus rv = SECFailure; |
michael@0 | 5190 | NSSLOWKEYPublicKey * rsa_public_key; |
michael@0 | 5191 | NSSLOWKEYPublicKey low_RSA_public_key = { NULL, |
michael@0 | 5192 | NSSLOWKEYRSAKey, }; |
michael@0 | 5193 | |
michael@0 | 5194 | /* convert to a low RSA public key */ |
michael@0 | 5195 | low_RSA_public_key.u.rsa = rsaBlapiPublicKey; |
michael@0 | 5196 | rsa_public_key = &low_RSA_public_key; |
michael@0 | 5197 | |
michael@0 | 5198 | memset(signature, 0, sizeof(signature)); |
michael@0 | 5199 | i = 1; |
michael@0 | 5200 | while (isspace(buf[i]) || buf[i] == '=') { |
michael@0 | 5201 | i++; |
michael@0 | 5202 | } |
michael@0 | 5203 | |
michael@0 | 5204 | for (j=0; isxdigit(buf[i]) && j < sizeof signature; i+=2,j++) { |
michael@0 | 5205 | hex_to_byteval(&buf[i], &signature[j]); |
michael@0 | 5206 | } |
michael@0 | 5207 | |
michael@0 | 5208 | signatureLength = j; |
michael@0 | 5209 | fputs(buf, rsaresp); |
michael@0 | 5210 | |
michael@0 | 5211 | /* Perform RSA verification with the RSA public key. */ |
michael@0 | 5212 | rv = RSA_HashCheckSign( shaOid, |
michael@0 | 5213 | rsa_public_key, |
michael@0 | 5214 | signature, |
michael@0 | 5215 | signatureLength, |
michael@0 | 5216 | sha, |
michael@0 | 5217 | shaLength); |
michael@0 | 5218 | if( rv == SECSuccess ) { |
michael@0 | 5219 | fputs("Result = P\n", rsaresp); |
michael@0 | 5220 | } else { |
michael@0 | 5221 | fputs("Result = F\n", rsaresp); |
michael@0 | 5222 | } |
michael@0 | 5223 | continue; |
michael@0 | 5224 | } |
michael@0 | 5225 | } |
michael@0 | 5226 | loser: |
michael@0 | 5227 | fclose(rsareq); |
michael@0 | 5228 | if (rsaBlapiPublicKey.modulus.data) { /* n */ |
michael@0 | 5229 | SECITEM_ZfreeItem(&rsaBlapiPublicKey.modulus, PR_FALSE); |
michael@0 | 5230 | } |
michael@0 | 5231 | if (rsaBlapiPublicKey.publicExponent.data) { /* e */ |
michael@0 | 5232 | SECITEM_ZfreeItem(&rsaBlapiPublicKey.publicExponent, PR_FALSE); |
michael@0 | 5233 | } |
michael@0 | 5234 | } |
michael@0 | 5235 | |
michael@0 | 5236 | int main(int argc, char **argv) |
michael@0 | 5237 | { |
michael@0 | 5238 | if (argc < 2) exit (-1); |
michael@0 | 5239 | |
michael@0 | 5240 | RNG_RNGInit(); |
michael@0 | 5241 | SECOID_Init(); |
michael@0 | 5242 | |
michael@0 | 5243 | /*************/ |
michael@0 | 5244 | /* TDEA */ |
michael@0 | 5245 | /*************/ |
michael@0 | 5246 | if (strcmp(argv[1], "tdea") == 0) { |
michael@0 | 5247 | /* argv[2]=kat|mmt|mct argv[3]=ecb|cbc argv[4]=<test name>.req */ |
michael@0 | 5248 | if (strcmp(argv[2], "kat") == 0) { |
michael@0 | 5249 | /* Known Answer Test (KAT) */ |
michael@0 | 5250 | tdea_kat_mmt(argv[4]); |
michael@0 | 5251 | } else if (strcmp(argv[2], "mmt") == 0) { |
michael@0 | 5252 | /* Multi-block Message Test (MMT) */ |
michael@0 | 5253 | tdea_kat_mmt(argv[4]); |
michael@0 | 5254 | } else if (strcmp(argv[2], "mct") == 0) { |
michael@0 | 5255 | /* Monte Carlo Test (MCT) */ |
michael@0 | 5256 | if (strcmp(argv[3], "ecb") == 0) { |
michael@0 | 5257 | /* ECB mode */ |
michael@0 | 5258 | tdea_mct(NSS_DES_EDE3, argv[4]); |
michael@0 | 5259 | } else if (strcmp(argv[3], "cbc") == 0) { |
michael@0 | 5260 | /* CBC mode */ |
michael@0 | 5261 | tdea_mct(NSS_DES_EDE3_CBC, argv[4]); |
michael@0 | 5262 | } |
michael@0 | 5263 | } |
michael@0 | 5264 | /*************/ |
michael@0 | 5265 | /* AES */ |
michael@0 | 5266 | /*************/ |
michael@0 | 5267 | } else if (strcmp(argv[1], "aes") == 0) { |
michael@0 | 5268 | /* argv[2]=kat|mmt|mct argv[3]=ecb|cbc argv[4]=<test name>.req */ |
michael@0 | 5269 | if ( strcmp(argv[2], "kat") == 0) { |
michael@0 | 5270 | /* Known Answer Test (KAT) */ |
michael@0 | 5271 | aes_kat_mmt(argv[4]); |
michael@0 | 5272 | } else if (strcmp(argv[2], "mmt") == 0) { |
michael@0 | 5273 | /* Multi-block Message Test (MMT) */ |
michael@0 | 5274 | aes_kat_mmt(argv[4]); |
michael@0 | 5275 | } else if (strcmp(argv[2], "mct") == 0) { |
michael@0 | 5276 | /* Monte Carlo Test (MCT) */ |
michael@0 | 5277 | if ( strcmp(argv[3], "ecb") == 0) { |
michael@0 | 5278 | /* ECB mode */ |
michael@0 | 5279 | aes_ecb_mct(argv[4]); |
michael@0 | 5280 | } else if (strcmp(argv[3], "cbc") == 0) { |
michael@0 | 5281 | /* CBC mode */ |
michael@0 | 5282 | aes_cbc_mct(argv[4]); |
michael@0 | 5283 | } |
michael@0 | 5284 | } |
michael@0 | 5285 | /*************/ |
michael@0 | 5286 | /* SHA */ |
michael@0 | 5287 | /*************/ |
michael@0 | 5288 | } else if (strcmp(argv[1], "sha") == 0) { |
michael@0 | 5289 | sha_test(argv[2]); |
michael@0 | 5290 | /*************/ |
michael@0 | 5291 | /* RSA */ |
michael@0 | 5292 | /*************/ |
michael@0 | 5293 | } else if (strcmp(argv[1], "rsa") == 0) { |
michael@0 | 5294 | /* argv[2]=siggen|sigver */ |
michael@0 | 5295 | /* argv[3]=<test name>.req */ |
michael@0 | 5296 | if (strcmp(argv[2], "siggen") == 0) { |
michael@0 | 5297 | /* Signature Generation Test */ |
michael@0 | 5298 | rsa_siggen_test(argv[3]); |
michael@0 | 5299 | } else if (strcmp(argv[2], "sigver") == 0) { |
michael@0 | 5300 | /* Signature Verification Test */ |
michael@0 | 5301 | rsa_sigver_test(argv[3]); |
michael@0 | 5302 | } |
michael@0 | 5303 | /*************/ |
michael@0 | 5304 | /* HMAC */ |
michael@0 | 5305 | /*************/ |
michael@0 | 5306 | } else if (strcmp(argv[1], "hmac") == 0) { |
michael@0 | 5307 | hmac_test(argv[2]); |
michael@0 | 5308 | /*************/ |
michael@0 | 5309 | /* DSA */ |
michael@0 | 5310 | /*************/ |
michael@0 | 5311 | } else if (strcmp(argv[1], "dsa") == 0) { |
michael@0 | 5312 | /* argv[2]=keypair|pqggen|pqgver|siggen|sigver */ |
michael@0 | 5313 | /* argv[3]=<test name>.req */ |
michael@0 | 5314 | if (strcmp(argv[2], "keypair") == 0) { |
michael@0 | 5315 | /* Key Pair Generation Test */ |
michael@0 | 5316 | dsa_keypair_test(argv[3]); |
michael@0 | 5317 | } else if (strcmp(argv[2], "pqggen") == 0) { |
michael@0 | 5318 | /* Domain Parameter Generation Test */ |
michael@0 | 5319 | dsa_pqggen_test(argv[3]); |
michael@0 | 5320 | } else if (strcmp(argv[2], "pqgver") == 0) { |
michael@0 | 5321 | /* Domain Parameter Validation Test */ |
michael@0 | 5322 | dsa_pqgver_test(argv[3]); |
michael@0 | 5323 | } else if (strcmp(argv[2], "siggen") == 0) { |
michael@0 | 5324 | /* Signature Generation Test */ |
michael@0 | 5325 | dsa_siggen_test(argv[3]); |
michael@0 | 5326 | } else if (strcmp(argv[2], "sigver") == 0) { |
michael@0 | 5327 | /* Signature Verification Test */ |
michael@0 | 5328 | dsa_sigver_test(argv[3]); |
michael@0 | 5329 | } |
michael@0 | 5330 | #ifndef NSS_DISABLE_ECC |
michael@0 | 5331 | /*************/ |
michael@0 | 5332 | /* ECDSA */ |
michael@0 | 5333 | /*************/ |
michael@0 | 5334 | } else if (strcmp(argv[1], "ecdsa") == 0) { |
michael@0 | 5335 | /* argv[2]=keypair|pkv|siggen|sigver argv[3]=<test name>.req */ |
michael@0 | 5336 | if ( strcmp(argv[2], "keypair") == 0) { |
michael@0 | 5337 | /* Key Pair Generation Test */ |
michael@0 | 5338 | ecdsa_keypair_test(argv[3]); |
michael@0 | 5339 | } else if (strcmp(argv[2], "pkv") == 0) { |
michael@0 | 5340 | /* Public Key Validation Test */ |
michael@0 | 5341 | ecdsa_pkv_test(argv[3]); |
michael@0 | 5342 | } else if (strcmp(argv[2], "siggen") == 0) { |
michael@0 | 5343 | /* Signature Generation Test */ |
michael@0 | 5344 | ecdsa_siggen_test(argv[3]); |
michael@0 | 5345 | } else if (strcmp(argv[2], "sigver") == 0) { |
michael@0 | 5346 | /* Signature Verification Test */ |
michael@0 | 5347 | ecdsa_sigver_test(argv[3]); |
michael@0 | 5348 | } |
michael@0 | 5349 | #endif /* NSS_DISABLE_ECC */ |
michael@0 | 5350 | /*************/ |
michael@0 | 5351 | /* RNG */ |
michael@0 | 5352 | /*************/ |
michael@0 | 5353 | } else if (strcmp(argv[1], "rng") == 0) { |
michael@0 | 5354 | /* argv[2]=vst|mct argv[3]=<test name>.req */ |
michael@0 | 5355 | if ( strcmp(argv[2], "vst") == 0) { |
michael@0 | 5356 | /* Variable Seed Test */ |
michael@0 | 5357 | rng_vst(argv[3]); |
michael@0 | 5358 | } else if (strcmp(argv[2], "mct") == 0) { |
michael@0 | 5359 | /* Monte Carlo Test */ |
michael@0 | 5360 | rng_mct(argv[3]); |
michael@0 | 5361 | } |
michael@0 | 5362 | } else if (strcmp(argv[1], "drbg") == 0) { |
michael@0 | 5363 | /* Variable Seed Test */ |
michael@0 | 5364 | drbg(argv[2]); |
michael@0 | 5365 | } else if (strcmp(argv[1], "ddrbg") == 0) { |
michael@0 | 5366 | debug = 1; |
michael@0 | 5367 | drbg(argv[2]); |
michael@0 | 5368 | } |
michael@0 | 5369 | return 0; |
michael@0 | 5370 | } |