diff options
Diffstat (limited to 'security/nss/cmd/bltest/blapitest.c')
-rw-r--r-- | security/nss/cmd/bltest/blapitest.c | 4274 |
1 files changed, 4274 insertions, 0 deletions
diff --git a/security/nss/cmd/bltest/blapitest.c b/security/nss/cmd/bltest/blapitest.c new file mode 100644 index 0000000000..199d5a450a --- /dev/null +++ b/security/nss/cmd/bltest/blapitest.c @@ -0,0 +1,4274 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include <stdio.h> +#include <stdlib.h> + +#include "blapi.h" +#include "secrng.h" +#include "prmem.h" +#include "prprf.h" +#include "prtime.h" +#include "prsystem.h" +#include "plstr.h" +#include "nssb64.h" +#include "basicutil.h" +#include "plgetopt.h" +#include "softoken.h" +#include "nspr.h" +#include "secport.h" +#include "secoid.h" +#include "nssutil.h" +#include "ecl-curve.h" +#include "chacha20poly1305.h" + +#include "pkcs1_vectors.h" + +SECStatus EC_DecodeParams(const SECItem *encodedParams, + ECParams **ecparams); +SECStatus EC_CopyParams(PLArenaPool *arena, ECParams *dstParams, + const ECParams *srcParams); + +char *progName; +char *testdir = NULL; + +#define BLTEST_DEFAULT_CHUNKSIZE 4096 + +#define WORDSIZE sizeof(unsigned long) + +#define CHECKERROR(rv, ln) \ + if (rv) { \ + PRErrorCode prerror = PR_GetError(); \ + PR_fprintf(PR_STDERR, "%s: ERR %d (%s) at line %d.\n", progName, \ + prerror, PORT_ErrorToString(prerror), ln); \ + exit(-1); \ + } + +/* Macros for performance timing. */ +#define TIMESTART() \ + time1 = PR_IntervalNow(); + +#define TIMEFINISH(time, reps) \ + time2 = (PRIntervalTime)(PR_IntervalNow() - time1); \ + time1 = PR_IntervalToMilliseconds(time2); \ + time = ((double)(time1)) / reps; + +#define TIMEMARK(seconds) \ + time1 = PR_SecondsToInterval(seconds); \ + { \ + PRInt64 tmp; \ + if (time2 == 0) { \ + time2 = 1; \ + } \ + LL_DIV(tmp, time1, time2); \ + if (tmp < 10) { \ + if (tmp == 0) { \ + opsBetweenChecks = 1; \ + } else { \ + LL_L2I(opsBetweenChecks, tmp); \ + } \ + } else { \ + opsBetweenChecks = 10; \ + } \ + } \ + time2 = time1; \ + time1 = PR_IntervalNow(); + +#define TIMETOFINISH() \ + PR_IntervalNow() - time1 >= time2 + +static void +Usage() +{ +#define PRINTUSAGE(subject, option, predicate) \ + fprintf(stderr, "%10s %s\t%s\n", subject, option, predicate); + fprintf(stderr, "\n"); + PRINTUSAGE(progName, "[-DEHSVR]", "List available cipher modes"); /* XXX */ + fprintf(stderr, "\n"); + PRINTUSAGE(progName, "-E -m mode ", "Encrypt a buffer"); + PRINTUSAGE("", "", "[-i plaintext] [-o ciphertext] [-k key] [-v iv]"); + PRINTUSAGE("", "", "[-b bufsize] [-g keysize] [-e exp] [-r rounds]"); + PRINTUSAGE("", "", "[-w wordsize] [-p repetitions | -5 time_interval]"); + PRINTUSAGE("", "", "[-4 th_num]"); + PRINTUSAGE("", "-m", "cipher mode to use"); + PRINTUSAGE("", "-i", "file which contains input buffer"); + PRINTUSAGE("", "-o", "file for output buffer"); + PRINTUSAGE("", "-k", "file which contains key"); + PRINTUSAGE("", "-v", "file which contains initialization vector"); + PRINTUSAGE("", "-b", "size of input buffer"); + PRINTUSAGE("", "-g", "key size (in bytes)"); + PRINTUSAGE("", "-p", "do performance test"); + PRINTUSAGE("", "-4", "run test in multithread mode. th_num number of parallel threads"); + PRINTUSAGE("", "-5", "run test for specified time interval(in seconds)"); + PRINTUSAGE("", "--aad", "File with contains additional auth data"); + PRINTUSAGE("(rsa)", "-e", "rsa public exponent"); + PRINTUSAGE("(rc5)", "-r", "number of rounds"); + PRINTUSAGE("(rc5)", "-w", "wordsize (32 or 64)"); + fprintf(stderr, "\n"); + PRINTUSAGE(progName, "-D -m mode", "Decrypt a buffer"); + PRINTUSAGE("", "", "[-i plaintext] [-o ciphertext] [-k key] [-v iv]"); + PRINTUSAGE("", "", "[-p repetitions | -5 time_interval] [-4 th_num]"); + PRINTUSAGE("", "-m", "cipher mode to use"); + PRINTUSAGE("", "-i", "file which contains input buffer"); + PRINTUSAGE("", "-o", "file for output buffer"); + PRINTUSAGE("", "-k", "file which contains key"); + PRINTUSAGE("", "-v", "file which contains initialization vector"); + PRINTUSAGE("", "-p", "do performance test"); + PRINTUSAGE("", "-4", "run test in multithread mode. th_num number of parallel threads"); + PRINTUSAGE("", "-5", "run test for specified time interval(in seconds)"); + PRINTUSAGE("", "--aad", "File with contains additional auth data"); + fprintf(stderr, "\n"); + PRINTUSAGE(progName, "-H -m mode", "Hash a buffer"); + PRINTUSAGE("", "", "[-i plaintext] [-o hash]"); + PRINTUSAGE("", "", "[-b bufsize]"); + PRINTUSAGE("", "", "[-p repetitions | -5 time_interval] [-4 th_num]"); + PRINTUSAGE("", "-m", "cipher mode to use"); + PRINTUSAGE("", "-i", "file which contains input buffer"); + PRINTUSAGE("", "-o", "file for hash"); + PRINTUSAGE("", "-b", "size of input buffer"); + PRINTUSAGE("", "-p", "do performance test"); + PRINTUSAGE("", "-4", "run test in multithread mode. th_num number of parallel threads"); + PRINTUSAGE("", "-5", "run test for specified time interval(in seconds)"); + fprintf(stderr, "\n"); + PRINTUSAGE(progName, "-S -m mode", "Sign a buffer"); + PRINTUSAGE("", "", "[-i plaintext] [-o signature] [-k key]"); + PRINTUSAGE("", "", "[-b bufsize]"); + PRINTUSAGE("", "", "[-n curvename]"); + PRINTUSAGE("", "", "[-p repetitions | -5 time_interval] [-4 th_num]"); + PRINTUSAGE("", "-m", "cipher mode to use"); + PRINTUSAGE("", "-i", "file which contains input buffer"); + PRINTUSAGE("", "-o", "file for signature"); + PRINTUSAGE("", "-k", "file which contains key"); + PRINTUSAGE("", "-n", "name of curve for EC key generation; one of:"); + PRINTUSAGE("", "", " nistp256, nistp384, nistp521"); + PRINTUSAGE("", "-p", "do performance test"); + PRINTUSAGE("", "-4", "run test in multithread mode. th_num number of parallel threads"); + PRINTUSAGE("", "-5", "run test for specified time interval(in seconds)"); + fprintf(stderr, "\n"); + PRINTUSAGE(progName, "-V -m mode", "Verify a signed buffer"); + PRINTUSAGE("", "", "[-i plaintext] [-s signature] [-k key]"); + PRINTUSAGE("", "", "[-p repetitions | -5 time_interval] [-4 th_num]"); + PRINTUSAGE("", "-m", "cipher mode to use"); + PRINTUSAGE("", "-i", "file which contains input buffer"); + PRINTUSAGE("", "-s", "file which contains signature of input buffer"); + PRINTUSAGE("", "-k", "file which contains key"); + PRINTUSAGE("", "-p", "do performance test"); + PRINTUSAGE("", "-4", "run test in multithread mode. th_num number of parallel threads"); + PRINTUSAGE("", "-5", "run test for specified time interval(in seconds)"); + fprintf(stderr, "\n"); + PRINTUSAGE(progName, "-N -m mode -b bufsize", + "Create a nonce plaintext and key"); + PRINTUSAGE("", "", "[-g keysize] [-u cxreps]"); + PRINTUSAGE("", "-g", "key size (in bytes)"); + PRINTUSAGE("", "-u", "number of repetitions of context creation"); + fprintf(stderr, "\n"); + PRINTUSAGE(progName, "-R [-g keysize] [-e exp]", + "Test the RSA populate key function"); + PRINTUSAGE("", "", "[-r repetitions]"); + PRINTUSAGE("", "-g", "key size (in bytes)"); + PRINTUSAGE("", "-e", "rsa public exponent"); + PRINTUSAGE("", "-r", "repetitions of the test"); + fprintf(stderr, "\n"); + PRINTUSAGE(progName, "-F", "Run the FIPS self-test"); + fprintf(stderr, "\n"); + PRINTUSAGE(progName, "-T [-m mode1,mode2...]", "Run the BLAPI self-test"); + fprintf(stderr, "\n"); + exit(1); +} + +/* Helper functions for ascii<-->binary conversion/reading/writing */ + +/* XXX argh */ +struct item_with_arena { + SECItem *item; + PLArenaPool *arena; +}; + +static PRInt32 +get_binary(void *arg, const unsigned char *ibuf, PRInt32 size) +{ + struct item_with_arena *it = arg; + SECItem *binary = it->item; + SECItem *tmp; + int index; + if (binary->data == NULL) { + tmp = SECITEM_AllocItem(it->arena, NULL, size); + binary->data = tmp->data; + binary->len = tmp->len; + index = 0; + } else { + SECITEM_ReallocItem(NULL, binary, binary->len, binary->len + size); + index = binary->len; + } + PORT_Memcpy(&binary->data[index], ibuf, size); + return binary->len; +} + +static SECStatus +atob(SECItem *ascii, SECItem *binary, PLArenaPool *arena) +{ + SECStatus status; + NSSBase64Decoder *cx; + struct item_with_arena it; + int len; + binary->data = NULL; + binary->len = 0; + it.item = binary; + it.arena = arena; + len = (strncmp((const char *)&ascii->data[ascii->len - 2], "\r\n", 2)) ? ascii->len + : ascii->len - 2; + cx = NSSBase64Decoder_Create(get_binary, &it); + status = NSSBase64Decoder_Update(cx, (const char *)ascii->data, len); + status = NSSBase64Decoder_Destroy(cx, PR_FALSE); + return status; +} + +static PRInt32 +output_ascii(void *arg, const char *obuf, PRInt32 size) +{ + PRFileDesc *outfile = arg; + PRInt32 nb = PR_Write(outfile, obuf, size); + if (nb != size) { + PORT_SetError(SEC_ERROR_IO); + return -1; + } + return nb; +} + +static SECStatus +btoa_file(SECItem *binary, PRFileDesc *outfile) +{ + SECStatus status; + NSSBase64Encoder *cx; + if (binary->len == 0) + return SECSuccess; + cx = NSSBase64Encoder_Create(output_ascii, outfile); + status = NSSBase64Encoder_Update(cx, binary->data, binary->len); + status = NSSBase64Encoder_Destroy(cx, PR_FALSE); + status = PR_Write(outfile, "\r\n", 2); + return status; +} + +SECStatus +hex_from_2char(unsigned char *c2, unsigned char *byteval) +{ + int i; + unsigned char offset; + *byteval = 0; + for (i = 0; i < 2; i++) { + if (c2[i] >= '0' && c2[i] <= '9') { + offset = c2[i] - '0'; + *byteval |= offset << 4 * (1 - i); + } else if (c2[i] >= 'a' && c2[i] <= 'f') { + offset = c2[i] - 'a'; + *byteval |= (offset + 10) << 4 * (1 - i); + } else if (c2[i] >= 'A' && c2[i] <= 'F') { + offset = c2[i] - 'A'; + *byteval |= (offset + 10) << 4 * (1 - i); + } else { + return SECFailure; + } + } + return SECSuccess; +} + +SECStatus +char2_from_hex(unsigned char byteval, char *c2) +{ + int i; + unsigned char offset; + for (i = 0; i < 2; i++) { + offset = (byteval >> 4 * (1 - i)) & 0x0f; + if (offset < 10) { + c2[i] = '0' + offset; + } else { + c2[i] = 'A' + offset - 10; + } + } + return SECSuccess; +} + +void +serialize_key(SECItem *it, int ni, PRFileDesc *file) +{ + unsigned char len[4]; + int i; + NSSBase64Encoder *cx; + cx = NSSBase64Encoder_Create(output_ascii, file); + for (i = 0; i < ni; i++, it++) { + len[0] = (it->len >> 24) & 0xff; + len[1] = (it->len >> 16) & 0xff; + len[2] = (it->len >> 8) & 0xff; + len[3] = (it->len & 0xff); + NSSBase64Encoder_Update(cx, len, 4); + NSSBase64Encoder_Update(cx, it->data, it->len); + } + NSSBase64Encoder_Destroy(cx, PR_FALSE); + PR_Write(file, "\r\n", 2); +} + +void +key_from_filedata(PLArenaPool *arena, SECItem *it, int ns, int ni, SECItem *filedata) +{ + int fpos = 0; + int i, len; + unsigned char *buf = filedata->data; + for (i = 0; i < ni; i++) { + len = (buf[fpos++] & 0xff) << 24; + len |= (buf[fpos++] & 0xff) << 16; + len |= (buf[fpos++] & 0xff) << 8; + len |= (buf[fpos++] & 0xff); + if (ns <= i) { + if (len > 0) { + it->len = len; + it->data = PORT_ArenaAlloc(arena, it->len); + PORT_Memcpy(it->data, &buf[fpos], it->len); + } else { + it->len = 0; + it->data = NULL; + } + it++; + } + fpos += len; + } +} + +static RSAPrivateKey * +rsakey_from_filedata(PLArenaPool *arena, SECItem *filedata) +{ + RSAPrivateKey *key; + key = (RSAPrivateKey *)PORT_ArenaZAlloc(arena, sizeof(RSAPrivateKey)); + key->arena = arena; + key_from_filedata(arena, &key->version, 0, 9, filedata); + return key; +} + +static PQGParams * +pqg_from_filedata(PLArenaPool *arena, SECItem *filedata) +{ + PQGParams *pqg; + pqg = (PQGParams *)PORT_ArenaZAlloc(arena, sizeof(PQGParams)); + pqg->arena = arena; + key_from_filedata(arena, &pqg->prime, 0, 3, filedata); + return pqg; +} + +static DSAPrivateKey * +dsakey_from_filedata(PLArenaPool *arena, SECItem *filedata) +{ + DSAPrivateKey *key; + key = (DSAPrivateKey *)PORT_ArenaZAlloc(arena, sizeof(DSAPrivateKey)); + key->params.arena = arena; + key_from_filedata(arena, &key->params.prime, 0, 5, filedata); + return key; +} + +static ECPrivateKey * +eckey_from_filedata(PLArenaPool *arena, SECItem *filedata) +{ + ECPrivateKey *key; + SECStatus rv; + ECParams *tmpECParams = NULL; + key = (ECPrivateKey *)PORT_ArenaZAlloc(arena, sizeof(ECPrivateKey)); + /* read and convert params */ + key->ecParams.arena = arena; + key_from_filedata(arena, &key->ecParams.DEREncoding, 0, 1, filedata); + rv = SECOID_Init(); + CHECKERROR(rv, __LINE__); + rv = EC_DecodeParams(&key->ecParams.DEREncoding, &tmpECParams); + CHECKERROR(rv, __LINE__); + rv = EC_CopyParams(key->ecParams.arena, &key->ecParams, tmpECParams); + CHECKERROR(rv, __LINE__); + rv = SECOID_Shutdown(); + CHECKERROR(rv, __LINE__); + PORT_FreeArena(tmpECParams->arena, PR_TRUE); + /* read key */ + key_from_filedata(arena, &key->publicValue, 1, 3, filedata); + return key; +} + +typedef struct curveNameTagPairStr { + char *curveName; + SECOidTag curveOidTag; +} CurveNameTagPair; + +static CurveNameTagPair nameTagPair[] = { + { "sect163k1", SEC_OID_SECG_EC_SECT163K1 }, + { "nistk163", SEC_OID_SECG_EC_SECT163K1 }, + { "sect163r1", SEC_OID_SECG_EC_SECT163R1 }, + { "sect163r2", SEC_OID_SECG_EC_SECT163R2 }, + { "nistb163", SEC_OID_SECG_EC_SECT163R2 }, + { "sect193r1", SEC_OID_SECG_EC_SECT193R1 }, + { "sect193r2", SEC_OID_SECG_EC_SECT193R2 }, + { "sect233k1", SEC_OID_SECG_EC_SECT233K1 }, + { "nistk233", SEC_OID_SECG_EC_SECT233K1 }, + { "sect233r1", SEC_OID_SECG_EC_SECT233R1 }, + { "nistb233", SEC_OID_SECG_EC_SECT233R1 }, + { "sect239k1", SEC_OID_SECG_EC_SECT239K1 }, + { "sect283k1", SEC_OID_SECG_EC_SECT283K1 }, + { "nistk283", SEC_OID_SECG_EC_SECT283K1 }, + { "sect283r1", SEC_OID_SECG_EC_SECT283R1 }, + { "nistb283", SEC_OID_SECG_EC_SECT283R1 }, + { "sect409k1", SEC_OID_SECG_EC_SECT409K1 }, + { "nistk409", SEC_OID_SECG_EC_SECT409K1 }, + { "sect409r1", SEC_OID_SECG_EC_SECT409R1 }, + { "nistb409", SEC_OID_SECG_EC_SECT409R1 }, + { "sect571k1", SEC_OID_SECG_EC_SECT571K1 }, + { "nistk571", SEC_OID_SECG_EC_SECT571K1 }, + { "sect571r1", SEC_OID_SECG_EC_SECT571R1 }, + { "nistb571", SEC_OID_SECG_EC_SECT571R1 }, + { "secp160k1", SEC_OID_SECG_EC_SECP160K1 }, + { "secp160r1", SEC_OID_SECG_EC_SECP160R1 }, + { "secp160r2", SEC_OID_SECG_EC_SECP160R2 }, + { "secp192k1", SEC_OID_SECG_EC_SECP192K1 }, + { "secp192r1", SEC_OID_SECG_EC_SECP192R1 }, + { "nistp192", SEC_OID_SECG_EC_SECP192R1 }, + { "secp224k1", SEC_OID_SECG_EC_SECP224K1 }, + { "secp224r1", SEC_OID_SECG_EC_SECP224R1 }, + { "nistp224", SEC_OID_SECG_EC_SECP224R1 }, + { "secp256k1", SEC_OID_SECG_EC_SECP256K1 }, + { "secp256r1", SEC_OID_SECG_EC_SECP256R1 }, + { "nistp256", SEC_OID_SECG_EC_SECP256R1 }, + { "secp384r1", SEC_OID_SECG_EC_SECP384R1 }, + { "nistp384", SEC_OID_SECG_EC_SECP384R1 }, + { "secp521r1", SEC_OID_SECG_EC_SECP521R1 }, + { "nistp521", SEC_OID_SECG_EC_SECP521R1 }, + + { "prime192v1", SEC_OID_ANSIX962_EC_PRIME192V1 }, + { "prime192v2", SEC_OID_ANSIX962_EC_PRIME192V2 }, + { "prime192v3", SEC_OID_ANSIX962_EC_PRIME192V3 }, + { "prime239v1", SEC_OID_ANSIX962_EC_PRIME239V1 }, + { "prime239v2", SEC_OID_ANSIX962_EC_PRIME239V2 }, + { "prime239v3", SEC_OID_ANSIX962_EC_PRIME239V3 }, + + { "c2pnb163v1", SEC_OID_ANSIX962_EC_C2PNB163V1 }, + { "c2pnb163v2", SEC_OID_ANSIX962_EC_C2PNB163V2 }, + { "c2pnb163v3", SEC_OID_ANSIX962_EC_C2PNB163V3 }, + { "c2pnb176v1", SEC_OID_ANSIX962_EC_C2PNB176V1 }, + { "c2tnb191v1", SEC_OID_ANSIX962_EC_C2TNB191V1 }, + { "c2tnb191v2", SEC_OID_ANSIX962_EC_C2TNB191V2 }, + { "c2tnb191v3", SEC_OID_ANSIX962_EC_C2TNB191V3 }, + { "c2onb191v4", SEC_OID_ANSIX962_EC_C2ONB191V4 }, + { "c2onb191v5", SEC_OID_ANSIX962_EC_C2ONB191V5 }, + { "c2pnb208w1", SEC_OID_ANSIX962_EC_C2PNB208W1 }, + { "c2tnb239v1", SEC_OID_ANSIX962_EC_C2TNB239V1 }, + { "c2tnb239v2", SEC_OID_ANSIX962_EC_C2TNB239V2 }, + { "c2tnb239v3", SEC_OID_ANSIX962_EC_C2TNB239V3 }, + { "c2onb239v4", SEC_OID_ANSIX962_EC_C2ONB239V4 }, + { "c2onb239v5", SEC_OID_ANSIX962_EC_C2ONB239V5 }, + { "c2pnb272w1", SEC_OID_ANSIX962_EC_C2PNB272W1 }, + { "c2pnb304w1", SEC_OID_ANSIX962_EC_C2PNB304W1 }, + { "c2tnb359v1", SEC_OID_ANSIX962_EC_C2TNB359V1 }, + { "c2pnb368w1", SEC_OID_ANSIX962_EC_C2PNB368W1 }, + { "c2tnb431r1", SEC_OID_ANSIX962_EC_C2TNB431R1 }, + + { "secp112r1", SEC_OID_SECG_EC_SECP112R1 }, + { "secp112r2", SEC_OID_SECG_EC_SECP112R2 }, + { "secp128r1", SEC_OID_SECG_EC_SECP128R1 }, + { "secp128r2", SEC_OID_SECG_EC_SECP128R2 }, + + { "sect113r1", SEC_OID_SECG_EC_SECT113R1 }, + { "sect113r2", SEC_OID_SECG_EC_SECT113R2 }, + { "sect131r1", SEC_OID_SECG_EC_SECT131R1 }, + { "sect131r2", SEC_OID_SECG_EC_SECT131R2 }, + { "curve25519", SEC_OID_CURVE25519 }, +}; + +static SECItem * +getECParams(const char *curve) +{ + SECItem *ecparams; + SECOidData *oidData = NULL; + SECOidTag curveOidTag = SEC_OID_UNKNOWN; /* default */ + int i, numCurves; + + if (curve != NULL) { + numCurves = sizeof(nameTagPair) / sizeof(CurveNameTagPair); + for (i = 0; ((i < numCurves) && (curveOidTag == SEC_OID_UNKNOWN)); + i++) { + if (PL_strcmp(curve, nameTagPair[i].curveName) == 0) + curveOidTag = nameTagPair[i].curveOidTag; + } + } + + /* Return NULL if curve name is not recognized */ + if ((curveOidTag == SEC_OID_UNKNOWN) || + (oidData = SECOID_FindOIDByTag(curveOidTag)) == NULL) { + fprintf(stderr, "Unrecognized elliptic curve %s\n", curve); + return NULL; + } + + ecparams = SECITEM_AllocItem(NULL, NULL, (2 + oidData->oid.len)); + + /* + * ecparams->data needs to contain the ASN encoding of an object ID (OID) + * representing the named curve. The actual OID is in + * oidData->oid.data so we simply prepend 0x06 and OID length + */ + ecparams->data[0] = SEC_ASN1_OBJECT_ID; + ecparams->data[1] = oidData->oid.len; + memcpy(ecparams->data + 2, oidData->oid.data, oidData->oid.len); + + return ecparams; +} + +static void +dump_pqg(PQGParams *pqg) +{ + SECU_PrintInteger(stdout, &pqg->prime, "PRIME:", 0); + SECU_PrintInteger(stdout, &pqg->subPrime, "SUBPRIME:", 0); + SECU_PrintInteger(stdout, &pqg->base, "BASE:", 0); +} + +static void +dump_dsakey(DSAPrivateKey *key) +{ + dump_pqg(&key->params); + SECU_PrintInteger(stdout, &key->publicValue, "PUBLIC VALUE:", 0); + SECU_PrintInteger(stdout, &key->privateValue, "PRIVATE VALUE:", 0); +} + +static void +dump_ecp(ECParams *ecp) +{ + /* TODO other fields */ + SECU_PrintInteger(stdout, &ecp->base, "BASE POINT:", 0); +} + +static void +dump_eckey(ECPrivateKey *key) +{ + dump_ecp(&key->ecParams); + SECU_PrintInteger(stdout, &key->publicValue, "PUBLIC VALUE:", 0); + SECU_PrintInteger(stdout, &key->privateValue, "PRIVATE VALUE:", 0); +} + +static void +dump_rsakey(RSAPrivateKey *key) +{ + SECU_PrintInteger(stdout, &key->version, "VERSION:", 0); + SECU_PrintInteger(stdout, &key->modulus, "MODULUS:", 0); + SECU_PrintInteger(stdout, &key->publicExponent, "PUBLIC EXP:", 0); + SECU_PrintInteger(stdout, &key->privateExponent, "PRIVATE EXP:", 0); + SECU_PrintInteger(stdout, &key->prime1, "CRT PRIME 1:", 0); + SECU_PrintInteger(stdout, &key->prime2, "CRT PRIME 2:", 0); + SECU_PrintInteger(stdout, &key->exponent1, "CRT EXP 1:", 0); + SECU_PrintInteger(stdout, &key->exponent2, "CRT EXP 2:", 0); + SECU_PrintInteger(stdout, &key->coefficient, "CRT COEFFICIENT:", 0); +} + +typedef enum { + bltestBase64Encoded, /* Base64 encoded ASCII */ + bltestBinary, /* straight binary */ + bltestHexSpaceDelim, /* 0x12 0x34 0xab 0xCD ... */ + bltestHexStream /* 1234abCD ... */ +} bltestIOMode; + +typedef struct +{ + SECItem buf; + SECItem pBuf; + bltestIOMode mode; + PRFileDesc *file; +} bltestIO; + +typedef SECStatus (*bltestSymmCipherFn)(void *cx, + unsigned char *output, + unsigned int *outputLen, + unsigned int maxOutputLen, + const unsigned char *input, + unsigned int inputLen); + +typedef SECStatus (*bltestAEADFn)(void *cx, + unsigned char *output, + unsigned int *outputLen, + unsigned int maxOutputLen, + const unsigned char *input, + unsigned int inputLen, + const unsigned char *nonce, + unsigned int nonceLen, + const unsigned char *ad, + unsigned int adLen); + +typedef SECStatus (*bltestPubKeyCipherFn)(void *key, + SECItem *output, + const SECItem *input); + +typedef SECStatus (*bltestHashCipherFn)(unsigned char *dest, + const unsigned char *src, + PRUint32 src_length); + +/* Note: Algorithms are grouped in order to support is_symmkeyCipher / + * is_pubkeyCipher / is_hashCipher / is_sigCipher + */ +typedef enum { + bltestINVALID = -1, + bltestDES_ECB, /* Symmetric Key Ciphers */ + bltestDES_CBC, /* . */ + bltestDES_EDE_ECB, /* . */ + bltestDES_EDE_CBC, /* . */ +#ifndef NSS_DISABLE_DEPRECATED_RC2 + bltestRC2_ECB, /* . */ + bltestRC2_CBC, /* . */ +#endif + bltestRC4, /* . */ +#ifdef NSS_SOFTOKEN_DOES_RC5 + bltestRC5_ECB, /* . */ + bltestRC5_CBC, /* . */ +#endif + bltestAES_ECB, /* . */ + bltestAES_CBC, /* . */ + bltestAES_CTS, /* . */ + bltestAES_CTR, /* . */ + bltestAES_GCM, /* . */ + bltestCAMELLIA_ECB, /* . */ + bltestCAMELLIA_CBC, /* . */ +#ifndef NSS_DISABLE_DEPRECATED_SEED + bltestSEED_ECB, /* SEED algorithm */ + bltestSEED_CBC, /* SEED algorithm */ +#endif + bltestCHACHA20_CTR, /* ChaCha20 block cipher */ + bltestCHACHA20, /* ChaCha20 + Poly1305 */ + bltestRSA, /* Public Key Ciphers */ + bltestRSA_OAEP, /* . (Public Key Enc.) */ + bltestRSA_PSS, /* . (Public Key Sig.) */ + bltestECDSA, /* . (Public Key Sig.) */ + bltestDSA, /* . (Public Key Sig.) */ + bltestMD2, /* Hash algorithms */ + bltestMD5, /* . */ + bltestSHA1, /* . */ + bltestSHA224, /* . */ + bltestSHA256, /* . */ + bltestSHA384, /* . */ + bltestSHA512, /* . */ + NUMMODES +} bltestCipherMode; + +static char *mode_strings[] = { + "des_ecb", + "des_cbc", + "des3_ecb", + "des3_cbc", +#ifndef NSS_DISABLE_DEPRECATED_RC2 + "rc2_ecb", + "rc2_cbc", +#endif + "rc4", +#ifdef NSS_SOFTOKEN_DOES_RC5 + "rc5_ecb", + "rc5_cbc", +#endif + "aes_ecb", + "aes_cbc", + "aes_cts", + "aes_ctr", + "aes_gcm", + "camellia_ecb", + "camellia_cbc", +#ifndef NSS_DISABLE_DEPRECATED_SEED + "seed_ecb", + "seed_cbc", +#endif + "chacha20_ctr", + "chacha20_poly1305", + "rsa", + "rsa_oaep", + "rsa_pss", + "ecdsa", + /*"pqg",*/ + "dsa", + "md2", + "md5", + "sha1", + "sha224", + "sha256", + "sha384", + "sha512", +}; + +typedef struct +{ + bltestIO key; + bltestIO iv; +} bltestSymmKeyParams; + +typedef struct +{ + bltestSymmKeyParams sk; /* must be first */ + bltestIO aad; +} bltestAuthSymmKeyParams; + +typedef struct +{ + bltestIO key; + bltestIO iv; + int rounds; + int wordsize; +} bltestRC5Params; + +typedef struct +{ + bltestIO key; + int keysizeInBits; + + /* OAEP & PSS */ + HASH_HashType hashAlg; + HASH_HashType maskHashAlg; + bltestIO seed; /* salt if PSS */ +} bltestRSAParams; + +typedef struct +{ + bltestIO pqgdata; + unsigned int keysize; + bltestIO keyseed; + bltestIO sigseed; + PQGParams *pqg; +} bltestDSAParams; + +typedef struct +{ + char *curveName; + bltestIO sigseed; +} bltestECDSAParams; + +typedef struct +{ + bltestIO key; + void *privKey; + void *pubKey; + bltestIO sig; /* if doing verify, the signature (which may come + * from sigfile. */ + + union { + bltestRSAParams rsa; + bltestDSAParams dsa; + bltestECDSAParams ecdsa; + } cipherParams; +} bltestAsymKeyParams; + +typedef struct +{ + bltestIO key; /* unused */ + PRBool restart; +} bltestHashParams; + +typedef union { + bltestIO key; + bltestSymmKeyParams sk; + bltestAuthSymmKeyParams ask; + bltestRC5Params rc5; + bltestAsymKeyParams asymk; + bltestHashParams hash; +} bltestParams; + +typedef struct bltestCipherInfoStr bltestCipherInfo; + +struct bltestCipherInfoStr { + PLArenaPool *arena; + /* link to next in multithreaded test */ + bltestCipherInfo *next; + PRThread *cipherThread; + + /* MonteCarlo test flag*/ + PRBool mCarlo; + /* cipher context */ + void *cx; + /* I/O streams */ + bltestIO input; + bltestIO output; + /* Cipher-specific parameters */ + bltestParams params; + /* Cipher mode */ + bltestCipherMode mode; + /* Cipher function (encrypt/decrypt/sign/verify/hash) */ + union { + bltestSymmCipherFn symmkeyCipher; + bltestAEADFn aeadCipher; + bltestPubKeyCipherFn pubkeyCipher; + bltestHashCipherFn hashCipher; + } cipher; + /* performance testing */ + int repetitionsToPerfom; + int seconds; + int repetitions; + int cxreps; + double cxtime; + double optime; +}; + +PRBool +is_symmkeyCipher(bltestCipherMode mode) +{ + /* change as needed! */ + if (mode >= bltestDES_ECB && mode <= bltestCHACHA20_CTR) + return PR_TRUE; + return PR_FALSE; +} + +PRBool +is_aeadCipher(bltestCipherMode mode) +{ + /* change as needed! */ + switch (mode) { + case bltestCHACHA20: + return PR_TRUE; + default: + return PR_FALSE; + } +} + +PRBool +is_authCipher(bltestCipherMode mode) +{ + /* change as needed! */ + switch (mode) { + case bltestAES_GCM: + case bltestCHACHA20: + return PR_TRUE; + default: + return PR_FALSE; + } +} + +PRBool +is_singleShotCipher(bltestCipherMode mode) +{ + /* change as needed! */ + switch (mode) { + case bltestAES_GCM: + case bltestAES_CTS: + case bltestCHACHA20_CTR: + case bltestCHACHA20: + return PR_TRUE; + default: + return PR_FALSE; + } +} + +PRBool +is_pubkeyCipher(bltestCipherMode mode) +{ + /* change as needed! */ + if (mode >= bltestRSA && mode <= bltestDSA) + return PR_TRUE; + return PR_FALSE; +} + +PRBool +is_hashCipher(bltestCipherMode mode) +{ + /* change as needed! */ + if (mode >= bltestMD2 && mode <= bltestSHA512) + return PR_TRUE; + return PR_FALSE; +} + +PRBool +is_sigCipher(bltestCipherMode mode) +{ + /* change as needed! */ + if (mode >= bltestRSA_PSS && mode <= bltestDSA) + return PR_TRUE; + return PR_FALSE; +} + +PRBool +cipher_requires_IV(bltestCipherMode mode) +{ + /* change as needed! */ + switch (mode) { + case bltestDES_CBC: + case bltestDES_EDE_CBC: +#ifndef NSS_DISABLE_DEPRECATED_RC2 + case bltestRC2_CBC: +#endif +#ifdef NSS_SOFTOKEN_DOES_RC5 + case bltestRC5_CBC: +#endif + case bltestAES_CBC: + case bltestAES_CTS: + case bltestAES_CTR: + case bltestAES_GCM: + case bltestCAMELLIA_CBC: +#ifndef NSS_DISABLE_DEPRECATED_SEED + case bltestSEED_CBC: +#endif + case bltestCHACHA20_CTR: + case bltestCHACHA20: + return PR_TRUE; + default: + return PR_FALSE; + } +} + +SECStatus finishIO(bltestIO *output, PRFileDesc *file); + +SECStatus +setupIO(PLArenaPool *arena, bltestIO *input, PRFileDesc *file, + char *str, int numBytes) +{ + SECStatus rv = SECSuccess; + SECItem fileData; + SECItem *in; + unsigned char *tok; + unsigned int i, j; + PRBool needToFreeFile = PR_FALSE; + + if (file && (numBytes == 0 || file == PR_STDIN)) { + /* grabbing data from a file */ + rv = SECU_FileToItem(&fileData, file); + if (rv != SECSuccess) + return SECFailure; + in = &fileData; + needToFreeFile = PR_TRUE; + } else if (str) { + /* grabbing data from command line */ + fileData.data = (unsigned char *)str; + fileData.len = PL_strlen(str); + in = &fileData; + } else if (file) { + /* create nonce */ + SECITEM_AllocItem(arena, &input->buf, numBytes); + RNG_GenerateGlobalRandomBytes(input->buf.data, numBytes); + return finishIO(input, file); + } else { + return SECFailure; + } + + switch (input->mode) { + case bltestBase64Encoded: + if (in->len == 0) { + input->buf.data = NULL; + input->buf.len = 0; + break; + } + rv = atob(in, &input->buf, arena); + break; + case bltestBinary: + if (in->len == 0) { + input->buf.data = NULL; + input->buf.len = 0; + break; + } + if (in->data[in->len - 1] == '\n') + --in->len; + if (in->data[in->len - 1] == '\r') + --in->len; + rv = SECITEM_CopyItem(arena, &input->buf, in); + break; + case bltestHexSpaceDelim: + SECITEM_AllocItem(arena, &input->buf, in->len / 5); + for (i = 0, j = 0; i < in->len; i += 5, j++) { + tok = &in->data[i]; + if (tok[0] != '0' || tok[1] != 'x' || tok[4] != ' ') + /* bad hex token */ + break; + + rv = hex_from_2char(&tok[2], input->buf.data + j); + if (rv) + break; + } + break; + case bltestHexStream: + SECITEM_AllocItem(arena, &input->buf, in->len / 2); + for (i = 0, j = 0; i < in->len; i += 2, j++) { + tok = &in->data[i]; + rv = hex_from_2char(tok, input->buf.data + j); + if (rv) + break; + } + break; + } + + if (needToFreeFile) + SECITEM_FreeItem(&fileData, PR_FALSE); + return rv; +} + +SECStatus +finishIO(bltestIO *output, PRFileDesc *file) +{ + SECStatus rv = SECSuccess; + PRInt32 nb; + unsigned char byteval; + SECItem *it; + char hexstr[5]; + unsigned int i; + if (output->pBuf.len > 0) { + it = &output->pBuf; + } else { + it = &output->buf; + } + switch (output->mode) { + case bltestBase64Encoded: + rv = btoa_file(it, file); + break; + case bltestBinary: + nb = PR_Write(file, it->data, it->len); + rv = (nb == (PRInt32)it->len) ? SECSuccess : SECFailure; + break; + case bltestHexSpaceDelim: + hexstr[0] = '0'; + hexstr[1] = 'x'; + hexstr[4] = ' '; + for (i = 0; i < it->len; i++) { + byteval = it->data[i]; + rv = char2_from_hex(byteval, hexstr + 2); + nb = PR_Write(file, hexstr, 5); + if (rv) + break; + } + PR_Write(file, "\n", 1); + break; + case bltestHexStream: + for (i = 0; i < it->len; i++) { + byteval = it->data[i]; + rv = char2_from_hex(byteval, hexstr); + if (rv) + break; + nb = PR_Write(file, hexstr, 2); + } + PR_Write(file, "\n", 1); + break; + } + return rv; +} + +SECStatus +bltestCopyIO(PLArenaPool *arena, bltestIO *dest, bltestIO *src) +{ + if (SECITEM_CopyItem(arena, &dest->buf, &src->buf) != SECSuccess) { + return SECFailure; + } + if (src->pBuf.len > 0) { + dest->pBuf.len = src->pBuf.len; + dest->pBuf.data = dest->buf.data + (src->pBuf.data - src->buf.data); + } + dest->mode = src->mode; + dest->file = src->file; + + return SECSuccess; +} + +void +misalignBuffer(PLArenaPool *arena, bltestIO *io, int off) +{ + ptrdiff_t offset = (ptrdiff_t)io->buf.data % WORDSIZE; + int length = io->buf.len; + if (offset != off) { + SECITEM_ReallocItemV2(arena, &io->buf, length + 2 * WORDSIZE); + /* offset may have changed? */ + offset = (ptrdiff_t)io->buf.data % WORDSIZE; + if (offset != off) { + memmove(io->buf.data + off, io->buf.data, length); + io->pBuf.data = io->buf.data + off; + io->pBuf.len = length; + } else { + io->pBuf.data = io->buf.data; + io->pBuf.len = length; + } + } else { + io->pBuf.data = io->buf.data; + io->pBuf.len = length; + } +} + +SECStatus +des_Encrypt(void *cx, unsigned char *output, unsigned int *outputLen, + unsigned int maxOutputLen, const unsigned char *input, + unsigned int inputLen) +{ + return DES_Encrypt((DESContext *)cx, output, outputLen, maxOutputLen, + input, inputLen); +} + +SECStatus +des_Decrypt(void *cx, unsigned char *output, unsigned int *outputLen, + unsigned int maxOutputLen, const unsigned char *input, + unsigned int inputLen) +{ + return DES_Decrypt((DESContext *)cx, output, outputLen, maxOutputLen, + input, inputLen); +} + +#ifndef NSS_DISABLE_DEPRECATED_RC2 +SECStatus +rc2_Encrypt(void *cx, unsigned char *output, unsigned int *outputLen, + unsigned int maxOutputLen, const unsigned char *input, + unsigned int inputLen) +{ + return RC2_Encrypt((RC2Context *)cx, output, outputLen, maxOutputLen, + input, inputLen); +} + +SECStatus +rc2_Decrypt(void *cx, unsigned char *output, unsigned int *outputLen, + unsigned int maxOutputLen, const unsigned char *input, + unsigned int inputLen) +{ + return RC2_Decrypt((RC2Context *)cx, output, outputLen, maxOutputLen, + input, inputLen); +} +#endif /* NSS_DISABLE_DEPRECATED_RC2 */ + +SECStatus +rc4_Encrypt(void *cx, unsigned char *output, unsigned int *outputLen, + unsigned int maxOutputLen, const unsigned char *input, + unsigned int inputLen) +{ + return RC4_Encrypt((RC4Context *)cx, output, outputLen, maxOutputLen, + input, inputLen); +} + +SECStatus +rc4_Decrypt(void *cx, unsigned char *output, unsigned int *outputLen, + unsigned int maxOutputLen, const unsigned char *input, + unsigned int inputLen) +{ + return RC4_Decrypt((RC4Context *)cx, output, outputLen, maxOutputLen, + input, inputLen); +} + +SECStatus +aes_Encrypt(void *cx, unsigned char *output, unsigned int *outputLen, + unsigned int maxOutputLen, const unsigned char *input, + unsigned int inputLen) +{ + return AES_Encrypt((AESContext *)cx, output, outputLen, maxOutputLen, + input, inputLen); +} + +SECStatus +aes_Decrypt(void *cx, unsigned char *output, unsigned int *outputLen, + unsigned int maxOutputLen, const unsigned char *input, + unsigned int inputLen) +{ + return AES_Decrypt((AESContext *)cx, output, outputLen, maxOutputLen, + input, inputLen); +} + +SECStatus +chacha20_Encrypt(void *cx, unsigned char *output, unsigned int *outputLen, + unsigned int maxOutputLen, const unsigned char *input, + unsigned int inputLen) +{ + if (maxOutputLen < inputLen) { + PORT_SetError(SEC_ERROR_OUTPUT_LEN); + return SECFailure; + } + ChaCha20Context *ctx = cx; + *outputLen = inputLen; + return ChaCha20_Xor(output, input, inputLen, ctx->key, ctx->nonce, + ctx->counter); +} + +SECStatus +chacha20_poly1305_Encrypt(void *cx, unsigned char *output, + unsigned int *outputLen, unsigned int maxOutputLen, + const unsigned char *input, unsigned int inputLen, + const unsigned char *nonce, unsigned int nonceLen, + const unsigned char *ad, unsigned int adLen) +{ + return ChaCha20Poly1305_Seal((ChaCha20Poly1305Context *)cx, output, + outputLen, maxOutputLen, input, inputLen, + nonce, nonceLen, ad, adLen); +} + +SECStatus +chacha20_poly1305_Decrypt(void *cx, unsigned char *output, + unsigned int *outputLen, unsigned int maxOutputLen, + const unsigned char *input, unsigned int inputLen, + const unsigned char *nonce, unsigned int nonceLen, + const unsigned char *ad, unsigned int adLen) +{ + return ChaCha20Poly1305_Open((ChaCha20Poly1305Context *)cx, output, + outputLen, maxOutputLen, input, inputLen, + nonce, nonceLen, ad, adLen); +} + +SECStatus +camellia_Encrypt(void *cx, unsigned char *output, unsigned int *outputLen, + unsigned int maxOutputLen, const unsigned char *input, + unsigned int inputLen) +{ + return Camellia_Encrypt((CamelliaContext *)cx, output, outputLen, + maxOutputLen, + input, inputLen); +} + +SECStatus +camellia_Decrypt(void *cx, unsigned char *output, unsigned int *outputLen, + unsigned int maxOutputLen, const unsigned char *input, + unsigned int inputLen) +{ + return Camellia_Decrypt((CamelliaContext *)cx, output, outputLen, + maxOutputLen, + input, inputLen); +} + +#ifndef NSS_DISABLE_DEPRECATED_SEED +SECStatus +seed_Encrypt(void *cx, unsigned char *output, unsigned int *outputLen, + unsigned int maxOutputLen, const unsigned char *input, + unsigned int inputLen) +{ + return SEED_Encrypt((SEEDContext *)cx, output, outputLen, maxOutputLen, + input, inputLen); +} + +SECStatus +seed_Decrypt(void *cx, unsigned char *output, unsigned int *outputLen, + unsigned int maxOutputLen, const unsigned char *input, + unsigned int inputLen) +{ + return SEED_Decrypt((SEEDContext *)cx, output, outputLen, maxOutputLen, + input, inputLen); +} +#endif /* NSS_DISABLE_DEPRECATED_SEED */ + +SECStatus +rsa_PublicKeyOp(void *cx, SECItem *output, const SECItem *input) +{ + bltestAsymKeyParams *params = (bltestAsymKeyParams *)cx; + RSAPublicKey *pubKey = (RSAPublicKey *)params->pubKey; + SECStatus rv = RSA_PublicKeyOp(pubKey, output->data, input->data); + if (rv == SECSuccess) { + output->len = pubKey->modulus.data[0] ? pubKey->modulus.len : pubKey->modulus.len - 1; + } + return rv; +} + +SECStatus +rsa_PrivateKeyOp(void *cx, SECItem *output, const SECItem *input) +{ + bltestAsymKeyParams *params = (bltestAsymKeyParams *)cx; + RSAPrivateKey *privKey = (RSAPrivateKey *)params->privKey; + SECStatus rv = RSA_PrivateKeyOp(privKey, output->data, input->data); + if (rv == SECSuccess) { + output->len = privKey->modulus.data[0] ? privKey->modulus.len : privKey->modulus.len - 1; + } + return rv; +} + +SECStatus +rsa_signDigestPSS(void *cx, SECItem *output, const SECItem *input) +{ + bltestAsymKeyParams *params = (bltestAsymKeyParams *)cx; + bltestRSAParams *rsaParams = ¶ms->cipherParams.rsa; + return RSA_SignPSS((RSAPrivateKey *)params->privKey, + rsaParams->hashAlg, + rsaParams->maskHashAlg, + rsaParams->seed.buf.data, + rsaParams->seed.buf.len, + output->data, &output->len, output->len, + input->data, input->len); +} + +SECStatus +rsa_verifyDigestPSS(void *cx, SECItem *output, const SECItem *input) +{ + bltestAsymKeyParams *params = (bltestAsymKeyParams *)cx; + bltestRSAParams *rsaParams = ¶ms->cipherParams.rsa; + return RSA_CheckSignPSS((RSAPublicKey *)params->pubKey, + rsaParams->hashAlg, + rsaParams->maskHashAlg, + rsaParams->seed.buf.len, + output->data, output->len, + input->data, input->len); +} + +SECStatus +rsa_encryptOAEP(void *cx, SECItem *output, const SECItem *input) +{ + bltestAsymKeyParams *params = (bltestAsymKeyParams *)cx; + bltestRSAParams *rsaParams = ¶ms->cipherParams.rsa; + return RSA_EncryptOAEP((RSAPublicKey *)params->pubKey, + rsaParams->hashAlg, + rsaParams->maskHashAlg, + NULL, 0, + rsaParams->seed.buf.data, + rsaParams->seed.buf.len, + output->data, &output->len, output->len, + input->data, input->len); +} + +SECStatus +rsa_decryptOAEP(void *cx, SECItem *output, const SECItem *input) +{ + bltestAsymKeyParams *params = (bltestAsymKeyParams *)cx; + bltestRSAParams *rsaParams = ¶ms->cipherParams.rsa; + return RSA_DecryptOAEP((RSAPrivateKey *)params->privKey, + rsaParams->hashAlg, + rsaParams->maskHashAlg, + NULL, 0, + output->data, &output->len, output->len, + input->data, input->len); +} + +SECStatus +dsa_signDigest(void *cx, SECItem *output, const SECItem *input) +{ + bltestAsymKeyParams *params = (bltestAsymKeyParams *)cx; + if (params->cipherParams.dsa.sigseed.buf.len > 0) { + return DSA_SignDigestWithSeed((DSAPrivateKey *)params->privKey, + output, input, + params->cipherParams.dsa.sigseed.buf.data); + } + return DSA_SignDigest((DSAPrivateKey *)params->privKey, output, input); +} + +SECStatus +dsa_verifyDigest(void *cx, SECItem *output, const SECItem *input) +{ + bltestAsymKeyParams *params = (bltestAsymKeyParams *)cx; + return DSA_VerifyDigest((DSAPublicKey *)params->pubKey, output, input); +} + +SECStatus +ecdsa_signDigest(void *cx, SECItem *output, const SECItem *input) +{ + bltestAsymKeyParams *params = (bltestAsymKeyParams *)cx; + if (params->cipherParams.ecdsa.sigseed.buf.len > 0) { + return ECDSA_SignDigestWithSeed( + (ECPrivateKey *)params->privKey, + output, input, + params->cipherParams.ecdsa.sigseed.buf.data, + params->cipherParams.ecdsa.sigseed.buf.len); + } + return ECDSA_SignDigest((ECPrivateKey *)params->privKey, output, input); +} + +SECStatus +ecdsa_verifyDigest(void *cx, SECItem *output, const SECItem *input) +{ + bltestAsymKeyParams *params = (bltestAsymKeyParams *)cx; + return ECDSA_VerifyDigest((ECPublicKey *)params->pubKey, output, input); +} + +SECStatus +bltest_des_init(bltestCipherInfo *cipherInfo, PRBool encrypt) +{ + PRIntervalTime time1, time2; + bltestSymmKeyParams *desp = &cipherInfo->params.sk; + int minorMode; + int i; + switch (cipherInfo->mode) { + case bltestDES_ECB: + minorMode = NSS_DES; + break; + case bltestDES_CBC: + minorMode = NSS_DES_CBC; + break; + case bltestDES_EDE_ECB: + minorMode = NSS_DES_EDE3; + break; + case bltestDES_EDE_CBC: + minorMode = NSS_DES_EDE3_CBC; + break; + default: + return SECFailure; + } + cipherInfo->cx = (void *)DES_CreateContext(desp->key.buf.data, + desp->iv.buf.data, + minorMode, encrypt); + if (cipherInfo->cxreps > 0) { + DESContext **dummycx; + dummycx = PORT_Alloc(cipherInfo->cxreps * sizeof(DESContext *)); + TIMESTART(); + for (i = 0; i < cipherInfo->cxreps; i++) { + dummycx[i] = (void *)DES_CreateContext(desp->key.buf.data, + desp->iv.buf.data, + minorMode, encrypt); + } + TIMEFINISH(cipherInfo->cxtime, 1.0); + for (i = 0; i < cipherInfo->cxreps; i++) { + DES_DestroyContext(dummycx[i], PR_TRUE); + } + PORT_Free(dummycx); + } + if (encrypt) + cipherInfo->cipher.symmkeyCipher = des_Encrypt; + else + cipherInfo->cipher.symmkeyCipher = des_Decrypt; + return SECSuccess; +} + +#ifndef NSS_DISABLE_DEPRECATED_RC2 +SECStatus +bltest_rc2_init(bltestCipherInfo *cipherInfo, PRBool encrypt) +{ + PRIntervalTime time1, time2; + bltestSymmKeyParams *rc2p = &cipherInfo->params.sk; + int minorMode; + int i; + switch (cipherInfo->mode) { + case bltestRC2_ECB: + minorMode = NSS_RC2; + break; + case bltestRC2_CBC: + minorMode = NSS_RC2_CBC; + break; + default: + return SECFailure; + } + cipherInfo->cx = (void *)RC2_CreateContext(rc2p->key.buf.data, + rc2p->key.buf.len, + rc2p->iv.buf.data, + minorMode, + rc2p->key.buf.len); + if (cipherInfo->cxreps > 0) { + RC2Context **dummycx; + dummycx = PORT_Alloc(cipherInfo->cxreps * sizeof(RC2Context *)); + TIMESTART(); + for (i = 0; i < cipherInfo->cxreps; i++) { + dummycx[i] = (void *)RC2_CreateContext(rc2p->key.buf.data, + rc2p->key.buf.len, + rc2p->iv.buf.data, + minorMode, + rc2p->key.buf.len); + } + TIMEFINISH(cipherInfo->cxtime, 1.0); + for (i = 0; i < cipherInfo->cxreps; i++) { + RC2_DestroyContext(dummycx[i], PR_TRUE); + } + PORT_Free(dummycx); + } + if (encrypt) + cipherInfo->cipher.symmkeyCipher = rc2_Encrypt; + else + cipherInfo->cipher.symmkeyCipher = rc2_Decrypt; + return SECSuccess; +} +#endif /* NSS_DISABLE_DEPRECATED_RC2 */ + +SECStatus +bltest_rc4_init(bltestCipherInfo *cipherInfo, PRBool encrypt) +{ + PRIntervalTime time1, time2; + int i; + bltestSymmKeyParams *rc4p = &cipherInfo->params.sk; + cipherInfo->cx = (void *)RC4_CreateContext(rc4p->key.buf.data, + rc4p->key.buf.len); + if (cipherInfo->cxreps > 0) { + RC4Context **dummycx; + dummycx = PORT_Alloc(cipherInfo->cxreps * sizeof(RC4Context *)); + TIMESTART(); + for (i = 0; i < cipherInfo->cxreps; i++) { + dummycx[i] = (void *)RC4_CreateContext(rc4p->key.buf.data, + rc4p->key.buf.len); + } + TIMEFINISH(cipherInfo->cxtime, 1.0); + for (i = 0; i < cipherInfo->cxreps; i++) { + RC4_DestroyContext(dummycx[i], PR_TRUE); + } + PORT_Free(dummycx); + } + if (encrypt) + cipherInfo->cipher.symmkeyCipher = rc4_Encrypt; + else + cipherInfo->cipher.symmkeyCipher = rc4_Decrypt; + return SECSuccess; +} + +SECStatus +bltest_rc5_init(bltestCipherInfo *cipherInfo, PRBool encrypt) +{ +#ifdef NSS_SOFTOKEN_DOES_RC5 + PRIntervalTime time1, time2; + bltestRC5Params *rc5p = &cipherInfo->params.rc5; + int minorMode; + switch (cipherInfo->mode) { + case bltestRC5_ECB: + minorMode = NSS_RC5; + break; + case bltestRC5_CBC: + minorMode = NSS_RC5_CBC; + break; + default: + return SECFailure; + } + TIMESTART(); + cipherInfo->cx = (void *)RC5_CreateContext(&rc5p->key.buf, + rc5p->rounds, rc5p->wordsize, + rc5p->iv.buf.data, minorMode); + TIMEFINISH(cipherInfo->cxtime, 1.0); + if (encrypt) + cipherInfo->cipher.symmkeyCipher = RC5_Encrypt; + else + cipherInfo->cipher.symmkeyCipher = RC5_Decrypt; + return SECSuccess; +#else + return SECFailure; +#endif +} + +SECStatus +bltest_aes_init(bltestCipherInfo *cipherInfo, PRBool encrypt) +{ + bltestSymmKeyParams *aesp = &cipherInfo->params.sk; + bltestAuthSymmKeyParams *gcmp = &cipherInfo->params.ask; + int minorMode; + int i; + int keylen = aesp->key.buf.len; + unsigned int blocklen = AES_BLOCK_SIZE; + PRIntervalTime time1, time2; + unsigned char *params; + int len; + CK_AES_CTR_PARAMS ctrParams; + CK_NSS_GCM_PARAMS gcmParams; + + params = aesp->iv.buf.data; + switch (cipherInfo->mode) { + case bltestAES_ECB: + minorMode = NSS_AES; + break; + case bltestAES_CBC: + minorMode = NSS_AES_CBC; + break; + case bltestAES_CTS: + minorMode = NSS_AES_CTS; + break; + case bltestAES_CTR: + minorMode = NSS_AES_CTR; + ctrParams.ulCounterBits = 32; + len = PR_MIN(aesp->iv.buf.len, blocklen); + PORT_Memset(ctrParams.cb, 0, blocklen); + PORT_Memcpy(ctrParams.cb, aesp->iv.buf.data, len); + params = (unsigned char *)&ctrParams; + break; + case bltestAES_GCM: + minorMode = NSS_AES_GCM; + gcmParams.pIv = gcmp->sk.iv.buf.data; + gcmParams.ulIvLen = gcmp->sk.iv.buf.len; + gcmParams.pAAD = gcmp->aad.buf.data; + gcmParams.ulAADLen = gcmp->aad.buf.len; + gcmParams.ulTagBits = blocklen * 8; + params = (unsigned char *)&gcmParams; + break; + default: + return SECFailure; + } + cipherInfo->cx = (void *)AES_CreateContext(aesp->key.buf.data, + params, + minorMode, encrypt, + keylen, blocklen); + if (cipherInfo->cxreps > 0) { + AESContext **dummycx; + dummycx = PORT_Alloc(cipherInfo->cxreps * sizeof(AESContext *)); + TIMESTART(); + for (i = 0; i < cipherInfo->cxreps; i++) { + dummycx[i] = (void *)AES_CreateContext(aesp->key.buf.data, + params, + minorMode, encrypt, + keylen, blocklen); + } + TIMEFINISH(cipherInfo->cxtime, 1.0); + for (i = 0; i < cipherInfo->cxreps; i++) { + AES_DestroyContext(dummycx[i], PR_TRUE); + } + PORT_Free(dummycx); + } + if (encrypt) + cipherInfo->cipher.symmkeyCipher = aes_Encrypt; + else + cipherInfo->cipher.symmkeyCipher = aes_Decrypt; + return SECSuccess; +} + +SECStatus +bltest_camellia_init(bltestCipherInfo *cipherInfo, PRBool encrypt) +{ + bltestSymmKeyParams *camelliap = &cipherInfo->params.sk; + int minorMode; + int i; + int keylen = camelliap->key.buf.len; + PRIntervalTime time1, time2; + + switch (cipherInfo->mode) { + case bltestCAMELLIA_ECB: + minorMode = NSS_CAMELLIA; + break; + case bltestCAMELLIA_CBC: + minorMode = NSS_CAMELLIA_CBC; + break; + default: + return SECFailure; + } + cipherInfo->cx = (void *)Camellia_CreateContext(camelliap->key.buf.data, + camelliap->iv.buf.data, + minorMode, encrypt, + keylen); + if (cipherInfo->cxreps > 0) { + CamelliaContext **dummycx; + dummycx = PORT_Alloc(cipherInfo->cxreps * sizeof(CamelliaContext *)); + TIMESTART(); + for (i = 0; i < cipherInfo->cxreps; i++) { + dummycx[i] = (void *)Camellia_CreateContext(camelliap->key.buf.data, + camelliap->iv.buf.data, + minorMode, encrypt, + keylen); + } + TIMEFINISH(cipherInfo->cxtime, 1.0); + for (i = 0; i < cipherInfo->cxreps; i++) { + Camellia_DestroyContext(dummycx[i], PR_TRUE); + } + PORT_Free(dummycx); + } + if (encrypt) + cipherInfo->cipher.symmkeyCipher = camellia_Encrypt; + else + cipherInfo->cipher.symmkeyCipher = camellia_Decrypt; + return SECSuccess; +} + +#ifndef NSS_DISABLE_DEPRECATED_SEED +SECStatus +bltest_seed_init(bltestCipherInfo *cipherInfo, PRBool encrypt) +{ + PRIntervalTime time1, time2; + bltestSymmKeyParams *seedp = &cipherInfo->params.sk; + int minorMode; + int i; + + switch (cipherInfo->mode) { + case bltestSEED_ECB: + minorMode = NSS_SEED; + break; + case bltestSEED_CBC: + minorMode = NSS_SEED_CBC; + break; + default: + return SECFailure; + } + cipherInfo->cx = (void *)SEED_CreateContext(seedp->key.buf.data, + seedp->iv.buf.data, + minorMode, encrypt); + if (cipherInfo->cxreps > 0) { + SEEDContext **dummycx; + dummycx = PORT_Alloc(cipherInfo->cxreps * sizeof(SEEDContext *)); + TIMESTART(); + for (i = 0; i < cipherInfo->cxreps; i++) { + dummycx[i] = (void *)SEED_CreateContext(seedp->key.buf.data, + seedp->iv.buf.data, + minorMode, encrypt); + } + TIMEFINISH(cipherInfo->cxtime, 1.0); + for (i = 0; i < cipherInfo->cxreps; i++) { + SEED_DestroyContext(dummycx[i], PR_TRUE); + } + PORT_Free(dummycx); + } + if (encrypt) + cipherInfo->cipher.symmkeyCipher = seed_Encrypt; + else + cipherInfo->cipher.symmkeyCipher = seed_Decrypt; + + return SECSuccess; +} +#endif /* NSS_DISABLE_DEPRECATED_SEED */ + +SECStatus +bltest_chacha20_ctr_init(bltestCipherInfo *cipherInfo, PRBool encrypt) +{ + const PRUint32 counter = 1; + bltestSymmKeyParams *sk = &cipherInfo->params.sk; + cipherInfo->cx = ChaCha20_CreateContext(sk->key.buf.data, sk->key.buf.len, + sk->iv.buf.data, sk->iv.buf.len, + counter); + + if (cipherInfo->cx == NULL) { + PR_fprintf(PR_STDERR, "ChaCha20_CreateContext() returned NULL\n" + "key must be 32 bytes, iv must be 12 bytes\n"); + return SECFailure; + } + cipherInfo->cipher.symmkeyCipher = chacha20_Encrypt; + return SECSuccess; +} + +SECStatus +bltest_chacha20_init(bltestCipherInfo *cipherInfo, PRBool encrypt) +{ + const unsigned int tagLen = 16; + const bltestSymmKeyParams *sk = &cipherInfo->params.sk; + cipherInfo->cx = ChaCha20Poly1305_CreateContext(sk->key.buf.data, + sk->key.buf.len, tagLen); + + if (encrypt) + cipherInfo->cipher.aeadCipher = chacha20_poly1305_Encrypt; + else + cipherInfo->cipher.aeadCipher = chacha20_poly1305_Decrypt; + return SECSuccess; +} + +SECStatus +bltest_rsa_init(bltestCipherInfo *cipherInfo, PRBool encrypt) +{ + int i; + RSAPrivateKey **dummyKey; + RSAPrivateKey *privKey; + RSAPublicKey *pubKey; + PRIntervalTime time1, time2; + + bltestAsymKeyParams *asymk = &cipherInfo->params.asymk; + bltestRSAParams *rsap = &asymk->cipherParams.rsa; + + /* RSA key gen was done during parameter setup */ + cipherInfo->cx = asymk; + privKey = (RSAPrivateKey *)asymk->privKey; + + /* For performance testing */ + if (cipherInfo->cxreps > 0) { + /* Create space for n private key objects */ + dummyKey = (RSAPrivateKey **)PORT_Alloc(cipherInfo->cxreps * + sizeof(RSAPrivateKey *)); + /* Time n keygens, storing in the array */ + TIMESTART(); + for (i = 0; i < cipherInfo->cxreps; i++) + dummyKey[i] = RSA_NewKey(rsap->keysizeInBits, + &privKey->publicExponent); + TIMEFINISH(cipherInfo->cxtime, cipherInfo->cxreps); + /* Free the n key objects */ + for (i = 0; i < cipherInfo->cxreps; i++) + PORT_FreeArena(dummyKey[i]->arena, PR_TRUE); + PORT_Free(dummyKey); + } + + if ((encrypt && !is_sigCipher(cipherInfo->mode)) || + (!encrypt && is_sigCipher(cipherInfo->mode))) { + /* Have to convert private key to public key. Memory + * is freed with private key's arena */ + pubKey = (RSAPublicKey *)PORT_ArenaAlloc(privKey->arena, + sizeof(RSAPublicKey)); + pubKey->modulus.len = privKey->modulus.len; + pubKey->modulus.data = privKey->modulus.data; + pubKey->publicExponent.len = privKey->publicExponent.len; + pubKey->publicExponent.data = privKey->publicExponent.data; + asymk->pubKey = (void *)pubKey; + } + switch (cipherInfo->mode) { + case bltestRSA: + cipherInfo->cipher.pubkeyCipher = encrypt ? rsa_PublicKeyOp + : rsa_PrivateKeyOp; + break; + case bltestRSA_PSS: + cipherInfo->cipher.pubkeyCipher = encrypt ? rsa_signDigestPSS + : rsa_verifyDigestPSS; + break; + case bltestRSA_OAEP: + cipherInfo->cipher.pubkeyCipher = encrypt ? rsa_encryptOAEP + : rsa_decryptOAEP; + break; + default: + break; + } + return SECSuccess; +} + +SECStatus +blapi_pqg_param_gen(unsigned int keysize, PQGParams **pqg, PQGVerify **vfy) +{ + if (keysize < 1024) { + int j = PQG_PBITS_TO_INDEX(keysize); + return PQG_ParamGen(j, pqg, vfy); + } + return PQG_ParamGenV2(keysize, 0, 0, pqg, vfy); +} + +SECStatus +bltest_pqg_init(bltestDSAParams *dsap) +{ + SECStatus rv, res; + PQGVerify *vfy = NULL; + rv = blapi_pqg_param_gen(dsap->keysize, &dsap->pqg, &vfy); + CHECKERROR(rv, __LINE__); + rv = PQG_VerifyParams(dsap->pqg, vfy, &res); + CHECKERROR(res, __LINE__); + CHECKERROR(rv, __LINE__); + return rv; +} + +SECStatus +bltest_dsa_init(bltestCipherInfo *cipherInfo, PRBool encrypt) +{ + int i; + DSAPrivateKey **dummyKey; + PQGParams *dummypqg; + PRIntervalTime time1, time2; + bltestAsymKeyParams *asymk = &cipherInfo->params.asymk; + bltestDSAParams *dsap = &asymk->cipherParams.dsa; + PQGVerify *ignore = NULL; + cipherInfo->cx = asymk; + /* For performance testing */ + if (cipherInfo->cxreps > 0) { + /* Create space for n private key objects */ + dummyKey = (DSAPrivateKey **)PORT_ZAlloc(cipherInfo->cxreps * + sizeof(DSAPrivateKey *)); + /* Time n keygens, storing in the array */ + TIMESTART(); + for (i = 0; i < cipherInfo->cxreps; i++) { + dummypqg = NULL; + blapi_pqg_param_gen(dsap->keysize, &dummypqg, &ignore); + DSA_NewKey(dummypqg, &dummyKey[i]); + } + TIMEFINISH(cipherInfo->cxtime, cipherInfo->cxreps); + /* Free the n key objects */ + for (i = 0; i < cipherInfo->cxreps; i++) + PORT_FreeArena(dummyKey[i]->params.arena, PR_TRUE); + PORT_Free(dummyKey); + } + if (!dsap->pqg && dsap->pqgdata.buf.len > 0) { + dsap->pqg = pqg_from_filedata(cipherInfo->arena, &dsap->pqgdata.buf); + } + if (!asymk->privKey && asymk->key.buf.len > 0) { + asymk->privKey = dsakey_from_filedata(cipherInfo->arena, &asymk->key.buf); + } + if (encrypt) { + cipherInfo->cipher.pubkeyCipher = dsa_signDigest; + } else { + /* Have to convert private key to public key. Memory + * is freed with private key's arena */ + DSAPublicKey *pubkey; + DSAPrivateKey *key = (DSAPrivateKey *)asymk->privKey; + pubkey = (DSAPublicKey *)PORT_ArenaZAlloc(key->params.arena, + sizeof(DSAPublicKey)); + pubkey->params.prime.len = key->params.prime.len; + pubkey->params.prime.data = key->params.prime.data; + pubkey->params.subPrime.len = key->params.subPrime.len; + pubkey->params.subPrime.data = key->params.subPrime.data; + pubkey->params.base.len = key->params.base.len; + pubkey->params.base.data = key->params.base.data; + pubkey->publicValue.len = key->publicValue.len; + pubkey->publicValue.data = key->publicValue.data; + asymk->pubKey = pubkey; + cipherInfo->cipher.pubkeyCipher = dsa_verifyDigest; + } + return SECSuccess; +} + +SECStatus +bltest_ecdsa_init(bltestCipherInfo *cipherInfo, PRBool encrypt) +{ + int i; + ECPrivateKey **dummyKey; + PRIntervalTime time1, time2; + bltestAsymKeyParams *asymk = &cipherInfo->params.asymk; + cipherInfo->cx = asymk; + /* For performance testing */ + if (cipherInfo->cxreps > 0) { + /* Create space for n private key objects */ + dummyKey = (ECPrivateKey **)PORT_ZAlloc(cipherInfo->cxreps * + sizeof(ECPrivateKey *)); + /* Time n keygens, storing in the array */ + TIMESTART(); + for (i = 0; i < cipherInfo->cxreps; i++) { + EC_NewKey(&((ECPrivateKey *)asymk->privKey)->ecParams, &dummyKey[i]); + } + TIMEFINISH(cipherInfo->cxtime, cipherInfo->cxreps); + /* Free the n key objects */ + for (i = 0; i < cipherInfo->cxreps; i++) + PORT_FreeArena(dummyKey[i]->ecParams.arena, PR_TRUE); + PORT_Free(dummyKey); + } + if (!asymk->privKey && asymk->key.buf.len > 0) { + asymk->privKey = eckey_from_filedata(cipherInfo->arena, &asymk->key.buf); + } + if (encrypt) { + cipherInfo->cipher.pubkeyCipher = ecdsa_signDigest; + } else { + /* Have to convert private key to public key. Memory + * is freed with private key's arena */ + ECPublicKey *pubkey; + ECPrivateKey *key = (ECPrivateKey *)asymk->privKey; + pubkey = (ECPublicKey *)PORT_ArenaZAlloc(key->ecParams.arena, + sizeof(ECPublicKey)); + pubkey->ecParams.type = key->ecParams.type; + pubkey->ecParams.fieldID.size = key->ecParams.fieldID.size; + pubkey->ecParams.fieldID.type = key->ecParams.fieldID.type; + pubkey->ecParams.fieldID.u.prime.len = key->ecParams.fieldID.u.prime.len; + pubkey->ecParams.fieldID.u.prime.data = key->ecParams.fieldID.u.prime.data; + pubkey->ecParams.fieldID.k1 = key->ecParams.fieldID.k1; + pubkey->ecParams.fieldID.k2 = key->ecParams.fieldID.k2; + pubkey->ecParams.fieldID.k3 = key->ecParams.fieldID.k3; + pubkey->ecParams.curve.a.len = key->ecParams.curve.a.len; + pubkey->ecParams.curve.a.data = key->ecParams.curve.a.data; + pubkey->ecParams.curve.b.len = key->ecParams.curve.b.len; + pubkey->ecParams.curve.b.data = key->ecParams.curve.b.data; + pubkey->ecParams.curve.seed.len = key->ecParams.curve.seed.len; + pubkey->ecParams.curve.seed.data = key->ecParams.curve.seed.data; + pubkey->ecParams.base.len = key->ecParams.base.len; + pubkey->ecParams.base.data = key->ecParams.base.data; + pubkey->ecParams.order.len = key->ecParams.order.len; + pubkey->ecParams.order.data = key->ecParams.order.data; + pubkey->ecParams.cofactor = key->ecParams.cofactor; + pubkey->ecParams.DEREncoding.len = key->ecParams.DEREncoding.len; + pubkey->ecParams.DEREncoding.data = key->ecParams.DEREncoding.data; + pubkey->ecParams.name = key->ecParams.name; + pubkey->publicValue.len = key->publicValue.len; + pubkey->publicValue.data = key->publicValue.data; + asymk->pubKey = pubkey; + cipherInfo->cipher.pubkeyCipher = ecdsa_verifyDigest; + } + return SECSuccess; +} + +/* XXX unfortunately, this is not defined in blapi.h */ +SECStatus +md2_HashBuf(unsigned char *dest, const unsigned char *src, PRUint32 src_length) +{ + unsigned int len; + MD2Context *cx = MD2_NewContext(); + if (cx == NULL) + return SECFailure; + MD2_Begin(cx); + MD2_Update(cx, src, src_length); + MD2_End(cx, dest, &len, MD2_LENGTH); + MD2_DestroyContext(cx, PR_TRUE); + return SECSuccess; +} + +SECStatus +md2_restart(unsigned char *dest, const unsigned char *src, PRUint32 src_length) +{ + MD2Context *cx, *cx_cpy; + unsigned char *cxbytes; + unsigned int len; + unsigned int i, quarter; + SECStatus rv = SECSuccess; + cx = MD2_NewContext(); + MD2_Begin(cx); + /* divide message by 4, restarting 3 times */ + quarter = (src_length + 3) / 4; + for (i = 0; i < 4 && src_length > 0; i++) { + MD2_Update(cx, src + i * quarter, PR_MIN(quarter, src_length)); + len = MD2_FlattenSize(cx); + cxbytes = PORT_Alloc(len); + MD2_Flatten(cx, cxbytes); + cx_cpy = MD2_Resurrect(cxbytes, NULL); + if (!cx_cpy) { + PR_fprintf(PR_STDERR, "%s: MD2_Resurrect failed!\n", progName); + goto finish; + } + rv = PORT_Memcmp(cx, cx_cpy, len); + if (rv) { + MD2_DestroyContext(cx_cpy, PR_TRUE); + PR_fprintf(PR_STDERR, "%s: MD2_restart failed!\n", progName); + goto finish; + } + MD2_DestroyContext(cx_cpy, PR_TRUE); + PORT_Free(cxbytes); + src_length -= quarter; + } + MD2_End(cx, dest, &len, MD2_LENGTH); +finish: + MD2_DestroyContext(cx, PR_TRUE); + return rv; +} + +SECStatus +md5_restart(unsigned char *dest, const unsigned char *src, PRUint32 src_length) +{ + SECStatus rv = SECSuccess; + MD5Context *cx, *cx_cpy; + unsigned char *cxbytes; + unsigned int len; + unsigned int i, quarter; + cx = MD5_NewContext(); + MD5_Begin(cx); + /* divide message by 4, restarting 3 times */ + quarter = (src_length + 3) / 4; + for (i = 0; i < 4 && src_length > 0; i++) { + MD5_Update(cx, src + i * quarter, PR_MIN(quarter, src_length)); + len = MD5_FlattenSize(cx); + cxbytes = PORT_Alloc(len); + MD5_Flatten(cx, cxbytes); + cx_cpy = MD5_Resurrect(cxbytes, NULL); + if (!cx_cpy) { + PR_fprintf(PR_STDERR, "%s: MD5_Resurrect failed!\n", progName); + rv = SECFailure; + goto finish; + } + rv = PORT_Memcmp(cx, cx_cpy, len); + if (rv) { + MD5_DestroyContext(cx_cpy, PR_TRUE); + PR_fprintf(PR_STDERR, "%s: MD5_restart failed!\n", progName); + goto finish; + } + MD5_DestroyContext(cx_cpy, PR_TRUE); + PORT_Free(cxbytes); + src_length -= quarter; + } + MD5_End(cx, dest, &len, MD5_LENGTH); +finish: + MD5_DestroyContext(cx, PR_TRUE); + return rv; +} + +SECStatus +sha1_restart(unsigned char *dest, const unsigned char *src, PRUint32 src_length) +{ + SECStatus rv = SECSuccess; + SHA1Context *cx, *cx_cpy; + unsigned char *cxbytes; + unsigned int len; + unsigned int i, quarter; + cx = SHA1_NewContext(); + SHA1_Begin(cx); + /* divide message by 4, restarting 3 times */ + quarter = (src_length + 3) / 4; + for (i = 0; i < 4 && src_length > 0; i++) { + SHA1_Update(cx, src + i * quarter, PR_MIN(quarter, src_length)); + len = SHA1_FlattenSize(cx); + cxbytes = PORT_Alloc(len); + SHA1_Flatten(cx, cxbytes); + cx_cpy = SHA1_Resurrect(cxbytes, NULL); + if (!cx_cpy) { + PR_fprintf(PR_STDERR, "%s: SHA1_Resurrect failed!\n", progName); + rv = SECFailure; + goto finish; + } + rv = PORT_Memcmp(cx, cx_cpy, len); + if (rv) { + SHA1_DestroyContext(cx_cpy, PR_TRUE); + PR_fprintf(PR_STDERR, "%s: SHA1_restart failed!\n", progName); + goto finish; + } + SHA1_DestroyContext(cx_cpy, PR_TRUE); + PORT_Free(cxbytes); + src_length -= quarter; + } + SHA1_End(cx, dest, &len, MD5_LENGTH); +finish: + SHA1_DestroyContext(cx, PR_TRUE); + return rv; +} + +SECStatus +SHA224_restart(unsigned char *dest, const unsigned char *src, PRUint32 src_length) +{ + SECStatus rv = SECSuccess; + SHA224Context *cx, *cx_cpy; + unsigned char *cxbytes; + unsigned int len; + unsigned int i, quarter; + cx = SHA224_NewContext(); + SHA224_Begin(cx); + /* divide message by 4, restarting 3 times */ + quarter = (src_length + 3) / 4; + for (i = 0; i < 4 && src_length > 0; i++) { + SHA224_Update(cx, src + i * quarter, PR_MIN(quarter, src_length)); + len = SHA224_FlattenSize(cx); + cxbytes = PORT_Alloc(len); + SHA224_Flatten(cx, cxbytes); + cx_cpy = SHA224_Resurrect(cxbytes, NULL); + if (!cx_cpy) { + PR_fprintf(PR_STDERR, "%s: SHA224_Resurrect failed!\n", progName); + rv = SECFailure; + goto finish; + } + rv = PORT_Memcmp(cx, cx_cpy, len); + if (rv) { + SHA224_DestroyContext(cx_cpy, PR_TRUE); + PR_fprintf(PR_STDERR, "%s: SHA224_restart failed!\n", progName); + goto finish; + } + + SHA224_DestroyContext(cx_cpy, PR_TRUE); + PORT_Free(cxbytes); + src_length -= quarter; + } + SHA224_End(cx, dest, &len, MD5_LENGTH); +finish: + SHA224_DestroyContext(cx, PR_TRUE); + return rv; +} + +SECStatus +SHA256_restart(unsigned char *dest, const unsigned char *src, PRUint32 src_length) +{ + SECStatus rv = SECSuccess; + SHA256Context *cx, *cx_cpy; + unsigned char *cxbytes; + unsigned int len; + unsigned int i, quarter; + cx = SHA256_NewContext(); + SHA256_Begin(cx); + /* divide message by 4, restarting 3 times */ + quarter = (src_length + 3) / 4; + for (i = 0; i < 4 && src_length > 0; i++) { + SHA256_Update(cx, src + i * quarter, PR_MIN(quarter, src_length)); + len = SHA256_FlattenSize(cx); + cxbytes = PORT_Alloc(len); + SHA256_Flatten(cx, cxbytes); + cx_cpy = SHA256_Resurrect(cxbytes, NULL); + if (!cx_cpy) { + PR_fprintf(PR_STDERR, "%s: SHA256_Resurrect failed!\n", progName); + rv = SECFailure; + goto finish; + } + rv = PORT_Memcmp(cx, cx_cpy, len); + if (rv) { + SHA256_DestroyContext(cx_cpy, PR_TRUE); + PR_fprintf(PR_STDERR, "%s: SHA256_restart failed!\n", progName); + goto finish; + } + SHA256_DestroyContext(cx_cpy, PR_TRUE); + PORT_Free(cxbytes); + src_length -= quarter; + } + SHA256_End(cx, dest, &len, MD5_LENGTH); +finish: + SHA256_DestroyContext(cx, PR_TRUE); + return rv; +} + +SECStatus +SHA384_restart(unsigned char *dest, const unsigned char *src, PRUint32 src_length) +{ + SECStatus rv = SECSuccess; + SHA384Context *cx, *cx_cpy; + unsigned char *cxbytes; + unsigned int len; + unsigned int i, quarter; + cx = SHA384_NewContext(); + SHA384_Begin(cx); + /* divide message by 4, restarting 3 times */ + quarter = (src_length + 3) / 4; + for (i = 0; i < 4 && src_length > 0; i++) { + SHA384_Update(cx, src + i * quarter, PR_MIN(quarter, src_length)); + len = SHA384_FlattenSize(cx); + cxbytes = PORT_Alloc(len); + SHA384_Flatten(cx, cxbytes); + cx_cpy = SHA384_Resurrect(cxbytes, NULL); + if (!cx_cpy) { + PR_fprintf(PR_STDERR, "%s: SHA384_Resurrect failed!\n", progName); + rv = SECFailure; + goto finish; + } + rv = PORT_Memcmp(cx, cx_cpy, len); + if (rv) { + SHA384_DestroyContext(cx_cpy, PR_TRUE); + PR_fprintf(PR_STDERR, "%s: SHA384_restart failed!\n", progName); + goto finish; + } + SHA384_DestroyContext(cx_cpy, PR_TRUE); + PORT_Free(cxbytes); + src_length -= quarter; + } + SHA384_End(cx, dest, &len, MD5_LENGTH); +finish: + SHA384_DestroyContext(cx, PR_TRUE); + return rv; +} + +SECStatus +SHA512_restart(unsigned char *dest, const unsigned char *src, PRUint32 src_length) +{ + SECStatus rv = SECSuccess; + SHA512Context *cx, *cx_cpy; + unsigned char *cxbytes; + unsigned int len; + unsigned int i, quarter; + cx = SHA512_NewContext(); + SHA512_Begin(cx); + /* divide message by 4, restarting 3 times */ + quarter = (src_length + 3) / 4; + for (i = 0; i < 4 && src_length > 0; i++) { + SHA512_Update(cx, src + i * quarter, PR_MIN(quarter, src_length)); + len = SHA512_FlattenSize(cx); + cxbytes = PORT_Alloc(len); + SHA512_Flatten(cx, cxbytes); + cx_cpy = SHA512_Resurrect(cxbytes, NULL); + if (!cx_cpy) { + PR_fprintf(PR_STDERR, "%s: SHA512_Resurrect failed!\n", progName); + rv = SECFailure; + goto finish; + } + rv = PORT_Memcmp(cx, cx_cpy, len); + if (rv) { + SHA512_DestroyContext(cx_cpy, PR_TRUE); + PR_fprintf(PR_STDERR, "%s: SHA512_restart failed!\n", progName); + goto finish; + } + SHA512_DestroyContext(cx_cpy, PR_TRUE); + PORT_Free(cxbytes); + src_length -= quarter; + } + SHA512_End(cx, dest, &len, MD5_LENGTH); +finish: + SHA512_DestroyContext(cx, PR_TRUE); + return rv; +} + +SECStatus +pubkeyInitKey(bltestCipherInfo *cipherInfo, PRFileDesc *file, + int keysize, int exponent, char *curveName) +{ + int i; + SECStatus rv = SECSuccess; + bltestAsymKeyParams *asymk = &cipherInfo->params.asymk; + bltestRSAParams *rsap; + RSAPrivateKey **rsaKey = NULL; + bltestDSAParams *dsap; + DSAPrivateKey **dsaKey = NULL; + SECItem *tmpECParamsDER; + ECParams *tmpECParams = NULL; + SECItem ecSerialize[3]; + ECPrivateKey **ecKey = NULL; + switch (cipherInfo->mode) { + case bltestRSA: + case bltestRSA_PSS: + case bltestRSA_OAEP: + rsap = &asymk->cipherParams.rsa; + rsaKey = (RSAPrivateKey **)&asymk->privKey; + if (keysize > 0) { + SECItem expitem = { 0, 0, 0 }; + SECITEM_AllocItem(cipherInfo->arena, &expitem, sizeof(int)); + for (i = 1; i <= sizeof(int); i++) + expitem.data[i - 1] = exponent >> (8 * (sizeof(int) - i)); + *rsaKey = RSA_NewKey(keysize * 8, &expitem); + serialize_key(&(*rsaKey)->version, 9, file); + rsap->keysizeInBits = keysize * 8; + } else { + setupIO(cipherInfo->arena, &asymk->key, file, NULL, 0); + *rsaKey = rsakey_from_filedata(cipherInfo->arena, &asymk->key.buf); + rsap->keysizeInBits = (*rsaKey)->modulus.len * 8; + } + break; + case bltestDSA: + dsap = &asymk->cipherParams.dsa; + dsaKey = (DSAPrivateKey **)&asymk->privKey; + if (keysize > 0) { + dsap->keysize = keysize * 8; + if (!dsap->pqg) + bltest_pqg_init(dsap); + rv = DSA_NewKey(dsap->pqg, dsaKey); + CHECKERROR(rv, __LINE__); + serialize_key(&(*dsaKey)->params.prime, 5, file); + } else { + setupIO(cipherInfo->arena, &asymk->key, file, NULL, 0); + *dsaKey = dsakey_from_filedata(cipherInfo->arena, &asymk->key.buf); + dsap->keysize = (*dsaKey)->params.prime.len * 8; + } + break; + case bltestECDSA: + ecKey = (ECPrivateKey **)&asymk->privKey; + if (curveName != NULL) { + tmpECParamsDER = getECParams(curveName); + rv = SECOID_Init(); + CHECKERROR(rv, __LINE__); + rv = EC_DecodeParams(tmpECParamsDER, &tmpECParams) == SECFailure; + CHECKERROR(rv, __LINE__); + rv = EC_NewKey(tmpECParams, ecKey); + CHECKERROR(rv, __LINE__); + ecSerialize[0].type = tmpECParamsDER->type; + ecSerialize[0].data = tmpECParamsDER->data; + ecSerialize[0].len = tmpECParamsDER->len; + ecSerialize[1].type = (*ecKey)->publicValue.type; + ecSerialize[1].data = (*ecKey)->publicValue.data; + ecSerialize[1].len = (*ecKey)->publicValue.len; + ecSerialize[2].type = (*ecKey)->privateValue.type; + ecSerialize[2].data = (*ecKey)->privateValue.data; + ecSerialize[2].len = (*ecKey)->privateValue.len; + serialize_key(&(ecSerialize[0]), 3, file); + SECITEM_FreeItem(tmpECParamsDER, PR_TRUE); + PORT_FreeArena(tmpECParams->arena, PR_TRUE); + rv = SECOID_Shutdown(); + CHECKERROR(rv, __LINE__); + } else { + setupIO(cipherInfo->arena, &asymk->key, file, NULL, 0); + *ecKey = eckey_from_filedata(cipherInfo->arena, &asymk->key.buf); + } + break; + default: + return SECFailure; + } + return SECSuccess; +} + +SECStatus +cipherInit(bltestCipherInfo *cipherInfo, PRBool encrypt) +{ + PRBool restart; + int outlen; + switch (cipherInfo->mode) { + case bltestDES_ECB: + case bltestDES_CBC: + case bltestDES_EDE_ECB: + case bltestDES_EDE_CBC: + SECITEM_AllocItem(cipherInfo->arena, &cipherInfo->output.buf, + cipherInfo->input.pBuf.len); + return bltest_des_init(cipherInfo, encrypt); + break; +#ifndef NSS_DISABLE_DEPRECATED_RC2 + case bltestRC2_ECB: + case bltestRC2_CBC: + SECITEM_AllocItem(cipherInfo->arena, &cipherInfo->output.buf, + cipherInfo->input.pBuf.len); + return bltest_rc2_init(cipherInfo, encrypt); + break; +#endif /* NSS_DISABLE_DEPRECATED_RC2 */ + case bltestRC4: + SECITEM_AllocItem(cipherInfo->arena, &cipherInfo->output.buf, + cipherInfo->input.pBuf.len); + return bltest_rc4_init(cipherInfo, encrypt); + break; +#ifdef NSS_SOFTOKEN_DOES_RC5 + case bltestRC5_ECB: + case bltestRC5_CBC: + SECITEM_AllocItem(cipherInfo->arena, &cipherInfo->output.buf, + cipherInfo->input.pBuf.len); + return bltest_rc5_init(cipherInfo, encrypt); + break; +#endif + case bltestAES_ECB: + case bltestAES_CBC: + case bltestAES_CTS: + case bltestAES_CTR: + case bltestAES_GCM: + outlen = cipherInfo->input.pBuf.len; + if (cipherInfo->mode == bltestAES_GCM && encrypt) { + outlen += 16; + } + SECITEM_AllocItem(cipherInfo->arena, &cipherInfo->output.buf, outlen); + return bltest_aes_init(cipherInfo, encrypt); + break; + case bltestCAMELLIA_ECB: + case bltestCAMELLIA_CBC: + SECITEM_AllocItem(cipherInfo->arena, &cipherInfo->output.buf, + cipherInfo->input.pBuf.len); + return bltest_camellia_init(cipherInfo, encrypt); + break; +#ifndef NSS_DISABLE_DEPRECATED_SEED + case bltestSEED_ECB: + case bltestSEED_CBC: + SECITEM_AllocItem(cipherInfo->arena, &cipherInfo->output.buf, + cipherInfo->input.pBuf.len); + return bltest_seed_init(cipherInfo, encrypt); + break; +#endif /* NSS_DISABLE_DEPRECATED_SEED */ + case bltestCHACHA20_CTR: + outlen = cipherInfo->input.pBuf.len; + SECITEM_AllocItem(cipherInfo->arena, &cipherInfo->output.buf, outlen); + return bltest_chacha20_ctr_init(cipherInfo, encrypt); + break; + case bltestCHACHA20: + outlen = cipherInfo->input.pBuf.len + (encrypt ? 16 : 0); + SECITEM_AllocItem(cipherInfo->arena, &cipherInfo->output.buf, outlen); + return bltest_chacha20_init(cipherInfo, encrypt); + break; + case bltestRSA: + case bltestRSA_OAEP: + case bltestRSA_PSS: + if (encrypt || cipherInfo->mode != bltestRSA_PSS) { + /* Don't allocate a buffer for PSS in verify mode, as no actual + * output is produced. */ + SECITEM_AllocItem(cipherInfo->arena, &cipherInfo->output.buf, + RSA_MAX_MODULUS_BITS / 8); + } + return bltest_rsa_init(cipherInfo, encrypt); + break; + case bltestDSA: + if (encrypt) { + SECITEM_AllocItem(cipherInfo->arena, &cipherInfo->output.buf, + DSA_MAX_SIGNATURE_LEN); + } + return bltest_dsa_init(cipherInfo, encrypt); + break; + case bltestECDSA: + if (encrypt) { + SECITEM_AllocItem(cipherInfo->arena, &cipherInfo->output.buf, + 2 * MAX_ECKEY_LEN); + } + return bltest_ecdsa_init(cipherInfo, encrypt); + break; + case bltestMD2: + restart = cipherInfo->params.hash.restart; + SECITEM_AllocItem(cipherInfo->arena, &cipherInfo->output.buf, + MD2_LENGTH); + cipherInfo->cipher.hashCipher = (restart) ? md2_restart : md2_HashBuf; + return SECSuccess; + break; + case bltestMD5: + restart = cipherInfo->params.hash.restart; + SECITEM_AllocItem(cipherInfo->arena, &cipherInfo->output.buf, + MD5_LENGTH); + cipherInfo->cipher.hashCipher = (restart) ? md5_restart : MD5_HashBuf; + return SECSuccess; + break; + case bltestSHA1: + restart = cipherInfo->params.hash.restart; + SECITEM_AllocItem(cipherInfo->arena, &cipherInfo->output.buf, + SHA1_LENGTH); + cipherInfo->cipher.hashCipher = (restart) ? sha1_restart : SHA1_HashBuf; + return SECSuccess; + break; + case bltestSHA224: + restart = cipherInfo->params.hash.restart; + SECITEM_AllocItem(cipherInfo->arena, &cipherInfo->output.buf, + SHA224_LENGTH); + cipherInfo->cipher.hashCipher = (restart) ? SHA224_restart + : SHA224_HashBuf; + return SECSuccess; + break; + case bltestSHA256: + restart = cipherInfo->params.hash.restart; + SECITEM_AllocItem(cipherInfo->arena, &cipherInfo->output.buf, + SHA256_LENGTH); + cipherInfo->cipher.hashCipher = (restart) ? SHA256_restart + : SHA256_HashBuf; + return SECSuccess; + break; + case bltestSHA384: + restart = cipherInfo->params.hash.restart; + SECITEM_AllocItem(cipherInfo->arena, &cipherInfo->output.buf, + SHA384_LENGTH); + cipherInfo->cipher.hashCipher = (restart) ? SHA384_restart + : SHA384_HashBuf; + return SECSuccess; + break; + case bltestSHA512: + restart = cipherInfo->params.hash.restart; + SECITEM_AllocItem(cipherInfo->arena, &cipherInfo->output.buf, + SHA512_LENGTH); + cipherInfo->cipher.hashCipher = (restart) ? SHA512_restart + : SHA512_HashBuf; + return SECSuccess; + break; + default: + return SECFailure; + } + return SECSuccess; +} + +SECStatus +cipherDoOp(bltestCipherInfo *cipherInfo) +{ + PRIntervalTime time1, time2; + SECStatus rv = SECSuccess; + int i; + unsigned int len; + unsigned int maxLen = cipherInfo->output.pBuf.len; + unsigned char *dummyOut; + dummyOut = PORT_Alloc(maxLen); + if (is_symmkeyCipher(cipherInfo->mode)) { + const unsigned char *input = cipherInfo->input.pBuf.data; + unsigned int inputLen = is_singleShotCipher(cipherInfo->mode) ? cipherInfo->input.pBuf.len + : PR_MIN(cipherInfo->input.pBuf.len, 16); + unsigned char *output = cipherInfo->output.pBuf.data; + unsigned int outputLen = maxLen; + unsigned int totalOutputLen = 0; + TIMESTART(); + rv = (*cipherInfo->cipher.symmkeyCipher)(cipherInfo->cx, + output, &len, outputLen, + input, inputLen); + CHECKERROR(rv, __LINE__); + totalOutputLen += len; + if (cipherInfo->input.pBuf.len > inputLen) { + input += inputLen; + inputLen = cipherInfo->input.pBuf.len - inputLen; + output += len; + outputLen -= len; + rv = (*cipherInfo->cipher.symmkeyCipher)(cipherInfo->cx, + output, &len, outputLen, + input, inputLen); + CHECKERROR(rv, __LINE__); + totalOutputLen += len; + } + cipherInfo->output.pBuf.len = totalOutputLen; + TIMEFINISH(cipherInfo->optime, 1.0); + cipherInfo->repetitions = 0; + if (cipherInfo->repetitionsToPerfom != 0) { + TIMESTART(); + for (i = 0; i < cipherInfo->repetitionsToPerfom; i++, + cipherInfo->repetitions++) { + (*cipherInfo->cipher.symmkeyCipher)(cipherInfo->cx, dummyOut, + &len, maxLen, + cipherInfo->input.pBuf.data, + cipherInfo->input.pBuf.len); + + CHECKERROR(rv, __LINE__); + } + } else { + int opsBetweenChecks = 0; + TIMEMARK(cipherInfo->seconds); + while (!(TIMETOFINISH())) { + int j = 0; + for (; j < opsBetweenChecks; j++) { + (*cipherInfo->cipher.symmkeyCipher)( + cipherInfo->cx, dummyOut, &len, maxLen, + cipherInfo->input.pBuf.data, + cipherInfo->input.pBuf.len); + } + cipherInfo->repetitions += j; + } + } + TIMEFINISH(cipherInfo->optime, 1.0); + } else if (is_aeadCipher(cipherInfo->mode)) { + const unsigned char *input = cipherInfo->input.pBuf.data; + unsigned int inputLen = cipherInfo->input.pBuf.len; + unsigned char *output = cipherInfo->output.pBuf.data; + unsigned int outputLen; + bltestSymmKeyParams *sk = &cipherInfo->params.sk; + bltestAuthSymmKeyParams *ask = &cipherInfo->params.ask; + + TIMESTART(); + rv = (*cipherInfo->cipher.aeadCipher)( + cipherInfo->cx, + output, &outputLen, maxLen, + input, inputLen, + sk->iv.buf.data, sk->iv.buf.len, + ask->aad.buf.data, ask->aad.buf.len); + CHECKERROR(rv, __LINE__); + cipherInfo->output.pBuf.len = outputLen; + TIMEFINISH(cipherInfo->optime, 1.0); + + cipherInfo->repetitions = 0; + if (cipherInfo->repetitionsToPerfom != 0) { + TIMESTART(); + for (i = 0; i < cipherInfo->repetitionsToPerfom; i++, + cipherInfo->repetitions++) { + rv = (*cipherInfo->cipher.aeadCipher)( + cipherInfo->cx, + output, &outputLen, maxLen, + input, inputLen, + sk->iv.buf.data, sk->iv.buf.len, + ask->aad.buf.data, ask->aad.buf.len); + CHECKERROR(rv, __LINE__); + } + } else { + int opsBetweenChecks = 0; + TIMEMARK(cipherInfo->seconds); + while (!(TIMETOFINISH())) { + int j = 0; + for (; j < opsBetweenChecks; j++) { + (*cipherInfo->cipher.aeadCipher)( + cipherInfo->cx, + output, &outputLen, maxLen, + input, inputLen, + sk->iv.buf.data, sk->iv.buf.len, + ask->aad.buf.data, ask->aad.buf.len); + } + cipherInfo->repetitions += j; + } + } + TIMEFINISH(cipherInfo->optime, 1.0); + } else if (is_pubkeyCipher(cipherInfo->mode)) { + TIMESTART(); + rv = (*cipherInfo->cipher.pubkeyCipher)(cipherInfo->cx, + &cipherInfo->output.pBuf, + &cipherInfo->input.pBuf); + TIMEFINISH(cipherInfo->optime, 1.0); + CHECKERROR(rv, __LINE__); + cipherInfo->repetitions = 0; + if (cipherInfo->repetitionsToPerfom != 0) { + TIMESTART(); + for (i = 0; i < cipherInfo->repetitionsToPerfom; + i++, cipherInfo->repetitions++) { + SECItem dummy; + dummy.data = dummyOut; + dummy.len = maxLen; + (*cipherInfo->cipher.pubkeyCipher)(cipherInfo->cx, &dummy, + &cipherInfo->input.pBuf); + CHECKERROR(rv, __LINE__); + } + } else { + int opsBetweenChecks = 0; + TIMEMARK(cipherInfo->seconds); + while (!(TIMETOFINISH())) { + int j = 0; + for (; j < opsBetweenChecks; j++) { + SECItem dummy; + dummy.data = dummyOut; + dummy.len = maxLen; + (*cipherInfo->cipher.pubkeyCipher)(cipherInfo->cx, &dummy, + &cipherInfo->input.pBuf); + CHECKERROR(rv, __LINE__); + } + cipherInfo->repetitions += j; + } + } + TIMEFINISH(cipherInfo->optime, 1.0); + } else if (is_hashCipher(cipherInfo->mode)) { + TIMESTART(); + rv = (*cipherInfo->cipher.hashCipher)(cipherInfo->output.pBuf.data, + cipherInfo->input.pBuf.data, + cipherInfo->input.pBuf.len); + TIMEFINISH(cipherInfo->optime, 1.0); + CHECKERROR(rv, __LINE__); + cipherInfo->repetitions = 0; + if (cipherInfo->repetitionsToPerfom != 0) { + TIMESTART(); + for (i = 0; i < cipherInfo->repetitionsToPerfom; + i++, cipherInfo->repetitions++) { + (*cipherInfo->cipher.hashCipher)(dummyOut, + cipherInfo->input.pBuf.data, + cipherInfo->input.pBuf.len); + CHECKERROR(rv, __LINE__); + } + } else { + int opsBetweenChecks = 0; + TIMEMARK(cipherInfo->seconds); + while (!(TIMETOFINISH())) { + int j = 0; + for (; j < opsBetweenChecks; j++) { + bltestIO *input = &cipherInfo->input; + (*cipherInfo->cipher.hashCipher)(dummyOut, + input->pBuf.data, + input->pBuf.len); + CHECKERROR(rv, __LINE__); + } + cipherInfo->repetitions += j; + } + } + TIMEFINISH(cipherInfo->optime, 1.0); + } + PORT_Free(dummyOut); + return rv; +} + +SECStatus +cipherFinish(bltestCipherInfo *cipherInfo) +{ + SECStatus rv = SECSuccess; + + switch (cipherInfo->mode) { + case bltestDES_ECB: + case bltestDES_CBC: + case bltestDES_EDE_ECB: + case bltestDES_EDE_CBC: + DES_DestroyContext((DESContext *)cipherInfo->cx, PR_TRUE); + break; + case bltestAES_GCM: + case bltestAES_ECB: + case bltestAES_CBC: + case bltestAES_CTS: + case bltestAES_CTR: + AES_DestroyContext((AESContext *)cipherInfo->cx, PR_TRUE); + break; + case bltestCAMELLIA_ECB: + case bltestCAMELLIA_CBC: + Camellia_DestroyContext((CamelliaContext *)cipherInfo->cx, PR_TRUE); + break; +#ifndef NSS_DISABLE_DEPRECATED_SEED + case bltestSEED_ECB: + case bltestSEED_CBC: + SEED_DestroyContext((SEEDContext *)cipherInfo->cx, PR_TRUE); + break; +#endif /* NSS_DISABLE_DEPRECATED_SEED */ + case bltestCHACHA20_CTR: + ChaCha20_DestroyContext((ChaCha20Context *)cipherInfo->cx, PR_TRUE); + break; + case bltestCHACHA20: + ChaCha20Poly1305_DestroyContext((ChaCha20Poly1305Context *) + cipherInfo->cx, + PR_TRUE); + break; +#ifndef NSS_DISABLE_DEPRECATED_RC2 + case bltestRC2_ECB: + case bltestRC2_CBC: + RC2_DestroyContext((RC2Context *)cipherInfo->cx, PR_TRUE); + break; +#endif /* NSS_DISABLE_DEPRECATED_RC2 */ + case bltestRC4: + RC4_DestroyContext((RC4Context *)cipherInfo->cx, PR_TRUE); + break; +#ifdef NSS_SOFTOKEN_DOES_RC5 + case bltestRC5_ECB: + case bltestRC5_CBC: + RC5_DestroyContext((RC5Context *)cipherInfo->cx, PR_TRUE); + break; +#endif + case bltestRSA: /* keys are alloc'ed within cipherInfo's arena, */ + case bltestRSA_PSS: /* will be freed with it. */ + case bltestRSA_OAEP: + case bltestDSA: + case bltestECDSA: + case bltestMD2: /* hash contexts are ephemeral */ + case bltestMD5: + case bltestSHA1: + case bltestSHA224: + case bltestSHA256: + case bltestSHA384: + case bltestSHA512: + return SECSuccess; + break; + default: + return SECFailure; + } + return rv; +} + +void +print_exponent(SECItem *exp) +{ + int i; + int e = 0; + if (exp->len <= 4) { + for (i = exp->len; i >= 0; --i) + e |= exp->data[exp->len - i] << 8 * (i - 1); + fprintf(stdout, "%12d", e); + } else { + e = 8 * exp->len; + fprintf(stdout, "~2**%-8d", e); + } +} + +static void +splitToReportUnit(PRInt64 res, int *resArr, int *del, int size) +{ + PRInt64 remaining = res, tmp = 0; + PRInt64 Ldel; + int i = -1; + + while (remaining > 0 && ++i < size) { + LL_I2L(Ldel, del[i]); + LL_MOD(tmp, remaining, Ldel); + LL_L2I(resArr[i], tmp); + LL_DIV(remaining, remaining, Ldel); + } +} + +static char * +getHighUnitBytes(PRInt64 res) +{ + int spl[] = { 0, 0, 0, 0 }; + int del[] = { 1024, 1024, 1024, 1024 }; + char *marks[] = { "b", "Kb", "Mb", "Gb" }; + int i = 3; + + splitToReportUnit(res, spl, del, 4); + + for (; i > 0; i--) { + if (spl[i] != 0) { + break; + } + } + + if (i == 0) + return PR_smprintf("%d%s", spl[i], marks[i]); + else + return PR_smprintf("%d%s %d%s", spl[i], marks[i], spl[i - 1], marks[i - 1]); +} + +static void +printPR_smpString(const char *sformat, char *reportStr, + const char *nformat, PRInt64 rNum) +{ + if (reportStr) { + fprintf(stdout, sformat, reportStr); + PR_smprintf_free(reportStr); + } else { + fprintf(stdout, nformat, rNum); + } +} + +static char * +getHighUnitOps(PRInt64 res) +{ + int spl[] = { 0, 0, 0, 0 }; + int del[] = { 1000, 1000, 1000, 1000 }; + char *marks[] = { "", "T", "M", "B" }; + int i = 3; + + splitToReportUnit(res, spl, del, 4); + + for (; i > 0; i--) { + if (spl[i] != 0) { + break; + } + } + + return PR_smprintf("%d%s", spl[i], marks[i]); +} + +void +dump_performance_info(bltestCipherInfo *infoList, double totalTimeInt, + PRBool encrypt, PRBool cxonly) +{ + bltestCipherInfo *info = infoList; + + PRInt64 totalIn = 0; + PRBool td = PR_TRUE; + + int repetitions = 0; + int cxreps = 0; + double cxtime = 0; + double optime = 0; + while (info != NULL) { + repetitions += info->repetitions; + cxreps += info->cxreps; + cxtime += info->cxtime; + optime += info->optime; + totalIn += (PRInt64)info->input.buf.len * (PRInt64)info->repetitions; + + info = info->next; + } + info = infoList; + + fprintf(stdout, "#%9s", "mode"); + fprintf(stdout, "%12s", "in"); +print_td: + switch (info->mode) { + case bltestDES_ECB: + case bltestDES_CBC: + case bltestDES_EDE_ECB: + case bltestDES_EDE_CBC: + case bltestAES_ECB: + case bltestAES_CBC: + case bltestAES_CTS: + case bltestAES_CTR: + case bltestAES_GCM: + case bltestCAMELLIA_ECB: + case bltestCAMELLIA_CBC: +#ifndef NSS_DISABLE_DEPRECATED_SEED + case bltestSEED_ECB: + case bltestSEED_CBC: +#endif +#ifndef NSS_DISABLE_DEPRECATED_RC2 + case bltestRC2_ECB: + case bltestRC2_CBC: +#endif + case bltestRC4: + if (td) + fprintf(stdout, "%8s", "symmkey"); + else + fprintf(stdout, "%8d", 8 * info->params.sk.key.buf.len); + break; +#ifdef NSS_SOFTOKEN_DOES_RC5 + case bltestRC5_ECB: + case bltestRC5_CBC: + if (info->params.sk.key.buf.len > 0) + printf("symmetric key(bytes)=%d,", info->params.sk.key.buf.len); + if (info->rounds > 0) + printf("rounds=%d,", info->params.rc5.rounds); + if (info->wordsize > 0) + printf("wordsize(bytes)=%d,", info->params.rc5.wordsize); + break; +#endif + case bltestRSA: + case bltestRSA_PSS: + case bltestRSA_OAEP: + if (td) { + fprintf(stdout, "%8s", "rsa_mod"); + fprintf(stdout, "%12s", "rsa_pe"); + } else { + bltestAsymKeyParams *asymk = &info->params.asymk; + fprintf(stdout, "%8d", asymk->cipherParams.rsa.keysizeInBits); + print_exponent( + &((RSAPrivateKey *)asymk->privKey)->publicExponent); + } + break; + case bltestDSA: + if (td) { + fprintf(stdout, "%8s", "pqg_mod"); + } else { + fprintf(stdout, "%8d", info->params.asymk.cipherParams.dsa.keysize); + } + break; + case bltestECDSA: + if (td) { + fprintf(stdout, "%12s", "ec_curve"); + } else { + ECPrivateKey *key = (ECPrivateKey *)info->params.asymk.privKey; + ECCurveName curveName = key->ecParams.name; + fprintf(stdout, "%12s", + ecCurve_map[curveName] ? ecCurve_map[curveName]->text : "Unsupported curve"); + } + break; + case bltestMD2: + case bltestMD5: + case bltestSHA1: + case bltestSHA256: + case bltestSHA384: + case bltestSHA512: + default: + break; + } + if (!td) { + PRInt64 totalThroughPut; + + printPR_smpString("%8s", getHighUnitOps(repetitions), + "%8d", repetitions); + + printPR_smpString("%8s", getHighUnitOps(cxreps), "%8d", cxreps); + + fprintf(stdout, "%12.3f", cxtime); + fprintf(stdout, "%12.3f", optime); + fprintf(stdout, "%12.03f", totalTimeInt / 1000); + + totalThroughPut = (PRInt64)(totalIn / totalTimeInt * 1000); + printPR_smpString("%12s", getHighUnitBytes(totalThroughPut), + "%12d", totalThroughPut); + + fprintf(stdout, "\n"); + return; + } + + fprintf(stdout, "%8s", "opreps"); + fprintf(stdout, "%8s", "cxreps"); + fprintf(stdout, "%12s", "context"); + fprintf(stdout, "%12s", "op"); + fprintf(stdout, "%12s", "time(sec)"); + fprintf(stdout, "%12s", "thrgput"); + fprintf(stdout, "\n"); + fprintf(stdout, "%8s", mode_strings[info->mode]); + fprintf(stdout, "_%c", (cxonly) ? 'c' : (encrypt) ? 'e' : 'd'); + printPR_smpString("%12s", getHighUnitBytes(totalIn), "%12d", totalIn); + + td = !td; + goto print_td; +} + +void +printmodes() +{ + bltestCipherMode mode; + int nummodes = sizeof(mode_strings) / sizeof(char *); + fprintf(stderr, "%s: Available modes (specify with -m):\n", progName); + for (mode = 0; mode < nummodes; mode++) + fprintf(stderr, "%s\n", mode_strings[mode]); +} + +bltestCipherMode +get_mode(const char *modestring) +{ + bltestCipherMode mode; + int nummodes = sizeof(mode_strings) / sizeof(char *); + for (mode = 0; mode < nummodes; mode++) + if (PL_strcmp(modestring, mode_strings[mode]) == 0) + return mode; + fprintf(stderr, "%s: invalid mode: %s\n", progName, modestring); + return bltestINVALID; +} + +void +load_file_data(PLArenaPool *arena, bltestIO *data, + char *fn, bltestIOMode ioMode) +{ + PRFileDesc *file; + data->mode = ioMode; + data->file = NULL; /* don't use -- not saving anything */ + data->pBuf.data = NULL; + data->pBuf.len = 0; + file = PR_Open(fn, PR_RDONLY, 00660); + if (file) { + setupIO(arena, data, file, NULL, 0); + PR_Close(file); + } +} + +HASH_HashType +mode_str_to_hash_alg(const SECItem *modeStr) +{ + bltestCipherMode mode; + char *tempModeStr = NULL; + if (!modeStr || modeStr->len == 0) + return HASH_AlgNULL; + tempModeStr = PORT_Alloc(modeStr->len + 1); + if (!tempModeStr) + return HASH_AlgNULL; + memcpy(tempModeStr, modeStr->data, modeStr->len); + tempModeStr[modeStr->len] = '\0'; + mode = get_mode(tempModeStr); + PORT_Free(tempModeStr); + switch (mode) { + case bltestMD2: + return HASH_AlgMD2; + case bltestMD5: + return HASH_AlgMD5; + case bltestSHA1: + return HASH_AlgSHA1; + case bltestSHA224: + return HASH_AlgSHA224; + case bltestSHA256: + return HASH_AlgSHA256; + case bltestSHA384: + return HASH_AlgSHA384; + case bltestSHA512: + return HASH_AlgSHA512; + default: + return HASH_AlgNULL; + } +} + +void +get_params(PLArenaPool *arena, bltestParams *params, + bltestCipherMode mode, int j) +{ + char filename[256]; + char *modestr = mode_strings[mode]; + bltestIO tempIO; + +#ifdef NSS_SOFTOKEN_DOES_RC5 + FILE *file; + char *mark, *param, *val; + int index = 0; +#endif + switch (mode) { + case bltestAES_GCM: + case bltestCHACHA20: + snprintf(filename, sizeof(filename), "%s/tests/%s/%s%d", testdir, modestr, "aad", j); + load_file_data(arena, ¶ms->ask.aad, filename, bltestBinary); + case bltestDES_CBC: + case bltestDES_EDE_CBC: +#ifndef NSS_DISABLE_DEPRECATED_RC2 + case bltestRC2_CBC: +#endif + case bltestAES_CBC: + case bltestAES_CTS: + case bltestAES_CTR: + case bltestCAMELLIA_CBC: +#ifndef NSS_DISABLE_DEPRECATED_SEED + case bltestSEED_CBC: +#endif + snprintf(filename, sizeof(filename), "%s/tests/%s/%s%d", testdir, modestr, "iv", j); + load_file_data(arena, ¶ms->sk.iv, filename, bltestBinary); + case bltestDES_ECB: + case bltestDES_EDE_ECB: +#ifndef NSS_DISABLE_DEPRECATED_RC2 + case bltestRC2_ECB: +#endif + case bltestRC4: + case bltestAES_ECB: + case bltestCAMELLIA_ECB: +#ifndef NSS_DISABLE_DEPRECATED_SEED + case bltestSEED_ECB: +#endif + snprintf(filename, sizeof(filename), "%s/tests/%s/%s%d", testdir, modestr, "key", j); + load_file_data(arena, ¶ms->sk.key, filename, bltestBinary); + break; +#ifdef NSS_SOFTOKEN_DOES_RC5 + case bltestRC5_ECB: + case bltestRC5_CBC: + snprintf(filename, sizeof(filename), "%s/tests/%s/%s%d", testdir, modestr, "iv", j); + load_file_data(arena, ¶ms->sk.iv, filename, bltestBinary); + snprintf(filename, sizeof(filename), "%s/tests/%s/%s%d", testdir, modestr, "key", j); + load_file_data(arena, ¶ms->sk.key, filename, bltestBinary); + snprintf(filename, sizeof(filename), "%s/tests/%s/%s%d", testdir, modestr, + "params", j); + file = fopen(filename, "r"); + if (!file) + return; + param = malloc(100); + len = fread(param, 1, 100, file); + while (index < len) { + mark = PL_strchr(param, '='); + *mark = '\0'; + val = mark + 1; + mark = PL_strchr(val, '\n'); + *mark = '\0'; + if (PL_strcmp(param, "rounds") == 0) { + params->rc5.rounds = atoi(val); + } else if (PL_strcmp(param, "wordsize") == 0) { + params->rc5.wordsize = atoi(val); + } + index += PL_strlen(param) + PL_strlen(val) + 2; + param = mark + 1; + } + break; +#endif + case bltestRSA_PSS: + snprintf(filename, sizeof(filename), "%s/tests/%s/%s%d", testdir, modestr, "ciphertext", j); + load_file_data(arena, ¶ms->asymk.sig, filename, bltestBase64Encoded); + /* fall through */ + case bltestRSA_OAEP: + snprintf(filename, sizeof(filename), "%s/tests/%s/%s%d", testdir, modestr, "seed", j); + load_file_data(arena, ¶ms->asymk.cipherParams.rsa.seed, + filename, bltestBase64Encoded); + + snprintf(filename, sizeof(filename), "%s/tests/%s/%s%d", testdir, modestr, "hash", j); + load_file_data(arena, &tempIO, filename, bltestBinary); + params->asymk.cipherParams.rsa.hashAlg = + mode_str_to_hash_alg(&tempIO.buf); + + snprintf(filename, sizeof(filename), "%s/tests/%s/%s%d", testdir, modestr, "maskhash", j); + load_file_data(arena, &tempIO, filename, bltestBinary); + params->asymk.cipherParams.rsa.maskHashAlg = + mode_str_to_hash_alg(&tempIO.buf); + /* fall through */ + case bltestRSA: + snprintf(filename, sizeof(filename), "%s/tests/%s/%s%d", testdir, modestr, "key", j); + load_file_data(arena, ¶ms->asymk.key, filename, + bltestBase64Encoded); + params->asymk.privKey = + (void *)rsakey_from_filedata(arena, ¶ms->asymk.key.buf); + break; + case bltestDSA: + snprintf(filename, sizeof(filename), "%s/tests/%s/%s%d", testdir, modestr, "key", j); + load_file_data(arena, ¶ms->asymk.key, filename, bltestBase64Encoded); + params->asymk.privKey = + (void *)dsakey_from_filedata(arena, ¶ms->asymk.key.buf); + snprintf(filename, sizeof(filename), "%s/tests/%s/%s%d", testdir, modestr, "pqg", j); + load_file_data(arena, ¶ms->asymk.cipherParams.dsa.pqgdata, filename, + bltestBase64Encoded); + params->asymk.cipherParams.dsa.pqg = + pqg_from_filedata(arena, ¶ms->asymk.cipherParams.dsa.pqgdata.buf); + snprintf(filename, sizeof(filename), "%s/tests/%s/%s%d", testdir, modestr, "keyseed", j); + load_file_data(arena, ¶ms->asymk.cipherParams.dsa.keyseed, filename, + bltestBase64Encoded); + snprintf(filename, sizeof(filename), "%s/tests/%s/%s%d", testdir, modestr, "sigseed", j); + load_file_data(arena, ¶ms->asymk.cipherParams.dsa.sigseed, filename, + bltestBase64Encoded); + snprintf(filename, sizeof(filename), "%s/tests/%s/%s%d", testdir, modestr, "ciphertext", j); + load_file_data(arena, ¶ms->asymk.sig, filename, bltestBase64Encoded); + break; + case bltestECDSA: + snprintf(filename, sizeof(filename), "%s/tests/%s/%s%d", testdir, modestr, "key", j); + load_file_data(arena, ¶ms->asymk.key, filename, bltestBase64Encoded); + params->asymk.privKey = + (void *)eckey_from_filedata(arena, ¶ms->asymk.key.buf); + snprintf(filename, sizeof(filename), "%s/tests/%s/%s%d", testdir, modestr, "sigseed", j); + load_file_data(arena, ¶ms->asymk.cipherParams.ecdsa.sigseed, + filename, bltestBase64Encoded); + snprintf(filename, sizeof(filename), "%s/tests/%s/%s%d", testdir, modestr, "ciphertext", j); + load_file_data(arena, ¶ms->asymk.sig, filename, bltestBase64Encoded); + break; + case bltestMD2: + case bltestMD5: + case bltestSHA1: + case bltestSHA224: + case bltestSHA256: + case bltestSHA384: + case bltestSHA512: + /*params->hash.restart = PR_TRUE;*/ + params->hash.restart = PR_FALSE; + break; + default: + break; + } +} + +SECStatus +verify_self_test(bltestIO *result, bltestIO *cmp, bltestCipherMode mode, + PRBool forward, SECStatus sigstatus) +{ + PRBool equal; + char *modestr = mode_strings[mode]; + equal = SECITEM_ItemsAreEqual(&result->pBuf, &cmp->buf); + if (is_sigCipher(mode)) { + if (forward) { + if (equal) { + printf("Signature self-test for %s passed.\n", modestr); + } else { + printf("Signature self-test for %s failed!\n", modestr); + } + return equal ? SECSuccess : SECFailure; + } else { + if (sigstatus == SECSuccess) { + printf("Verification self-test for %s passed.\n", modestr); + } else { + printf("Verification self-test for %s failed!\n", modestr); + } + return sigstatus; + } + } else if (is_hashCipher(mode)) { + if (equal) { + printf("Hash self-test for %s passed.\n", modestr); + } else { + printf("Hash self-test for %s failed!\n", modestr); + } + } else { + if (forward) { + if (equal) { + printf("Encryption self-test for %s passed.\n", modestr); + } else { + printf("Encryption self-test for %s failed!\n", modestr); + } + } else { + if (equal) { + printf("Decryption self-test for %s passed.\n", modestr); + } else { + printf("Decryption self-test for %s failed!\n", modestr); + } + } + } + return equal ? SECSuccess : SECFailure; +} + +static SECStatus +ReadFileToItem(PLArenaPool *arena, SECItem *dst, const char *filename) +{ + SECItem tmp = { siBuffer, NULL, 0 }; + PRFileDesc *file; + SECStatus rv; + + file = PR_Open(filename, PR_RDONLY, 00660); + if (!file) { + return SECFailure; + } + rv = SECU_FileToItem(&tmp, file); + rv |= SECITEM_CopyItem(arena, dst, &tmp); + SECITEM_FreeItem(&tmp, PR_FALSE); + PR_Close(file); + return rv; +} + +static SECStatus +blapi_selftest(bltestCipherMode *modes, int numModes, int inoff, int outoff, + PRBool encrypt, PRBool decrypt) +{ + bltestCipherInfo cipherInfo; + bltestIO pt, ct; + bltestCipherMode mode; + bltestParams *params; + unsigned int i, j, nummodes, numtests; + char *modestr; + char filename[256]; + PLArenaPool *arena; + SECItem item; + SECStatus rv = SECSuccess, srv; + + PORT_Memset(&cipherInfo, 0, sizeof(cipherInfo)); + arena = PORT_NewArena(BLTEST_DEFAULT_CHUNKSIZE); + cipherInfo.arena = arena; + + nummodes = (numModes == 0) ? NUMMODES : numModes; + for (i = 0; i < nummodes; i++) { + if (numModes > 0) + mode = modes[i]; + else + mode = i; + if (mode == bltestINVALID) { + fprintf(stderr, "%s: Skipping invalid mode.\n", progName); + continue; + } + modestr = mode_strings[mode]; + cipherInfo.mode = mode; + params = &cipherInfo.params; + /* get the number of tests in the directory */ + snprintf(filename, sizeof(filename), "%s/tests/%s/%s", testdir, modestr, "numtests"); + if (ReadFileToItem(arena, &item, filename) != SECSuccess) { + fprintf(stderr, "%s: Cannot read file %s.\n", progName, filename); + rv = SECFailure; + continue; + } + /* loop over the tests in the directory */ + numtests = 0; + for (j = 0; j < item.len; j++) { + if (!isdigit(item.data[j])) { + break; + } + numtests *= 10; + numtests += (int)(item.data[j] - '0'); + } + for (j = 0; j < numtests; j++) { + snprintf(filename, sizeof(filename), "%s/tests/%s/%s%d", testdir, modestr, + "plaintext", j); + load_file_data(arena, &pt, filename, + is_sigCipher(mode) ? bltestBase64Encoded + : bltestBinary); + snprintf(filename, sizeof(filename), "%s/tests/%s/%s%d", testdir, modestr, + "ciphertext", j); + load_file_data(arena, &ct, filename, bltestBase64Encoded); + + get_params(arena, params, mode, j); + /* Forward Operation (Encrypt/Sign/Hash) + ** Align the input buffer (plaintext) according to request + ** then perform operation and compare to ciphertext + */ + if (encrypt) { + rv |= bltestCopyIO(arena, &cipherInfo.input, &pt); + misalignBuffer(arena, &cipherInfo.input, inoff); + memset(&cipherInfo.output.buf, 0, sizeof cipherInfo.output.buf); + rv |= cipherInit(&cipherInfo, PR_TRUE); + misalignBuffer(arena, &cipherInfo.output, outoff); + rv |= cipherDoOp(&cipherInfo); + rv |= cipherFinish(&cipherInfo); + rv |= verify_self_test(&cipherInfo.output, + &ct, mode, PR_TRUE, SECSuccess); + /* If testing hash, only one op to test */ + if (is_hashCipher(mode)) + continue; + if (is_sigCipher(mode)) { + /* Verify operations support detached signature files. For + ** consistency between tests that run Sign/Verify back to + ** back (eg: self-tests) and tests that are only running + ** verify operations, copy the output into the sig buf, + ** and then copy the sig buf back out when verifying. For + ** self-tests, this is unnecessary copying, but for + ** verify-only operations, this ensures that the output + ** buffer is properly configured + */ + rv |= bltestCopyIO(arena, ¶ms->asymk.sig, &cipherInfo.output); + } + } + if (!decrypt) + continue; + /* Reverse Operation (Decrypt/Verify) + ** Align the input buffer (ciphertext) according to request + ** then perform operation and compare to plaintext + */ + if (is_sigCipher(mode)) { + rv |= bltestCopyIO(arena, &cipherInfo.input, &pt); + rv |= bltestCopyIO(arena, &cipherInfo.output, ¶ms->asymk.sig); + } else { + rv |= bltestCopyIO(arena, &cipherInfo.input, &ct); + memset(&cipherInfo.output.buf, 0, sizeof cipherInfo.output.buf); + } + misalignBuffer(arena, &cipherInfo.input, inoff); + rv |= cipherInit(&cipherInfo, PR_FALSE); + misalignBuffer(arena, &cipherInfo.output, outoff); + srv = SECSuccess; + srv |= cipherDoOp(&cipherInfo); + rv |= cipherFinish(&cipherInfo); + rv |= verify_self_test(&cipherInfo.output, + &pt, mode, PR_FALSE, srv); + } + } + PORT_FreeArena(arena, PR_FALSE); + return rv; +} + +SECStatus +dump_file(bltestCipherMode mode, char *filename) +{ + bltestIO keydata; + PLArenaPool *arena = NULL; + arena = PORT_NewArena(BLTEST_DEFAULT_CHUNKSIZE); + if (!arena) { + return SECFailure; + } + if (mode == bltestRSA || mode == bltestRSA_PSS || mode == bltestRSA_OAEP) { + RSAPrivateKey *key; + load_file_data(arena, &keydata, filename, bltestBase64Encoded); + key = rsakey_from_filedata(arena, &keydata.buf); + dump_rsakey(key); + } else if (mode == bltestDSA) { +#if 0 + PQGParams *pqg; + get_file_data(filename, &item, PR_TRUE); + pqg = pqg_from_filedata(&item); + dump_pqg(pqg); +#endif + DSAPrivateKey *key; + load_file_data(arena, &keydata, filename, bltestBase64Encoded); + key = dsakey_from_filedata(arena, &keydata.buf); + dump_dsakey(key); + } else if (mode == bltestECDSA) { + ECPrivateKey *key; + load_file_data(arena, &keydata, filename, bltestBase64Encoded); + key = eckey_from_filedata(arena, &keydata.buf); + dump_eckey(key); + } + PORT_FreeArena(arena, PR_FALSE); + return SECFailure; +} + +void +ThreadExecTest(void *data) +{ + bltestCipherInfo *cipherInfo = (bltestCipherInfo *)data; + + if (cipherInfo->mCarlo == PR_TRUE) { + int mciter; + for (mciter = 0; mciter < 10000; mciter++) { + cipherDoOp(cipherInfo); + memcpy(cipherInfo->input.buf.data, + cipherInfo->output.buf.data, + cipherInfo->input.buf.len); + } + } else { + cipherDoOp(cipherInfo); + } + cipherFinish(cipherInfo); +} + +static void +rsaPrivKeyReset(RSAPrivateKey *tstKey) +{ + PLArenaPool *arena; + + tstKey->version.data = NULL; + tstKey->version.len = 0; + tstKey->modulus.data = NULL; + tstKey->modulus.len = 0; + tstKey->publicExponent.data = NULL; + tstKey->publicExponent.len = 0; + tstKey->privateExponent.data = NULL; + tstKey->privateExponent.len = 0; + tstKey->prime1.data = NULL; + tstKey->prime1.len = 0; + tstKey->prime2.data = NULL; + tstKey->prime2.len = 0; + tstKey->exponent1.data = NULL; + tstKey->exponent1.len = 0; + tstKey->exponent2.data = NULL; + tstKey->exponent2.len = 0; + tstKey->coefficient.data = NULL; + tstKey->coefficient.len = 0; + + arena = tstKey->arena; + tstKey->arena = NULL; + if (arena) { + PORT_FreeArena(arena, PR_TRUE); + } +} + +#define RSA_TEST_EQUAL(comp) \ + if (!SECITEM_ItemsAreEqual(&(src->comp), &(dest->comp))) { \ + fprintf(stderr, "key->" #comp " not equal"); \ + if (src->comp.len != dest->comp.len) { \ + fprintf(stderr, "src_len = %d, dest_len = %d", \ + src->comp.len, dest->comp.len); \ + } \ + fprintf(stderr, "\n"); \ + areEqual = PR_FALSE; \ + } + +static PRBool +rsaPrivKeysAreEqual(RSAPrivateKey *src, RSAPrivateKey *dest) +{ + PRBool areEqual = PR_TRUE; + RSA_TEST_EQUAL(modulus) + RSA_TEST_EQUAL(publicExponent) + RSA_TEST_EQUAL(privateExponent) + RSA_TEST_EQUAL(prime1) + RSA_TEST_EQUAL(prime2) + RSA_TEST_EQUAL(exponent1) + RSA_TEST_EQUAL(exponent2) + RSA_TEST_EQUAL(coefficient) + if (!areEqual) { + fprintf(stderr, "original key:\n"); + dump_rsakey(src); + fprintf(stderr, "recreated key:\n"); + dump_rsakey(dest); + } + return areEqual; +} + +static int +doRSAPopulateTestKV() +{ + RSAPrivateKey tstKey = { 0 }; + SECStatus rv; + int failed = 0; + int i; + + tstKey.arena = NULL; + + /* Test public exponent, private exponent, modulus cases from + * pkcs1v15sign-vectors.txt. Some are valid PKCS#1 keys but not valid RSA + * ones (de = 1 mod lcm(p − 1, q − 1)) + */ + for (i = 0; i < PR_ARRAY_SIZE(PKCS1_VECTORS); ++i) { + struct pkcs1_test_vector *v = &PKCS1_VECTORS[i]; + + rsaPrivKeyReset(&tstKey); + tstKey.privateExponent.data = v->d; + tstKey.privateExponent.len = v->d_len; + tstKey.publicExponent.data = v->e; + tstKey.publicExponent.len = v->e_len; + tstKey.modulus.data = v->n; + tstKey.modulus.len = v->n_len; + + rv = RSA_PopulatePrivateKey(&tstKey); + if (rv != SECSuccess) { + fprintf(stderr, "RSA Populate failed: pkcs1v15sign-vector %d\n", i); + failed = 1; + } else if (memcmp(v->q, tstKey.prime1.data, v->q_len) || + tstKey.prime1.len != v->q_len) { + fprintf(stderr, "RSA Populate key mismatch: pkcs1v15sign-vector %d q\n", i); + failed = 1; + } else if (memcmp(v->p, tstKey.prime2.data, v->p_len) || + tstKey.prime1.len != v->p_len) { + fprintf(stderr, "RSA Populate key mismatch: pkcs1v15sign-vector %d p\n", i); + failed = 1; + } else { + fprintf(stderr, "RSA Populate success: pkcs1v15sign-vector %d p\n", i); + } + } + + PORT_FreeArena(tstKey.arena, PR_TRUE); + return failed; +} + +/* + * Test the RSA populate command to see that it can really build + * keys from its components. + */ +static int +doRSAPopulateTest(unsigned int keySize, unsigned long exponent) +{ + RSAPrivateKey *srcKey; + RSAPrivateKey tstKey = { 0 }; + SECItem expitem = { 0, 0, 0 }; + SECStatus rv; + unsigned char pubExp[32]; + int expLen = 0; + int failed = 0; + int i; + + for (i = 0; i < sizeof(unsigned long); i++) { + int shift = (sizeof(unsigned long) - i - 1) * 8; + if (expLen || (exponent && ((unsigned long)0xffL << shift))) { + pubExp[expLen] = (unsigned char)((exponent >> shift) & 0xff); + expLen++; + } + } + + expitem.data = pubExp; + expitem.len = expLen; + + srcKey = RSA_NewKey(keySize, &expitem); + if (srcKey == NULL) { + fprintf(stderr, "RSA Key Gen failed"); + return -1; + } + + /* test the basic case - most common, public exponent, modulus, prime */ + tstKey.arena = NULL; + rsaPrivKeyReset(&tstKey); + + tstKey.publicExponent = srcKey->publicExponent; + tstKey.modulus = srcKey->modulus; + tstKey.prime1 = srcKey->prime1; + + rv = RSA_PopulatePrivateKey(&tstKey); + if (rv != SECSuccess) { + fprintf(stderr, "RSA Populate failed: pubExp mod p\n"); + failed = 1; + } else if (!rsaPrivKeysAreEqual(&tstKey, srcKey)) { + fprintf(stderr, "RSA Populate key mismatch: pubExp mod p\n"); + failed = 1; + } + + /* test the basic2 case, public exponent, modulus, prime2 */ + rsaPrivKeyReset(&tstKey); + + tstKey.publicExponent = srcKey->publicExponent; + tstKey.modulus = srcKey->modulus; + tstKey.prime1 = srcKey->prime2; /* test with q in the prime1 position */ + + rv = RSA_PopulatePrivateKey(&tstKey); + if (rv != SECSuccess) { + fprintf(stderr, "RSA Populate failed: pubExp mod q\n"); + failed = 1; + } else if (!rsaPrivKeysAreEqual(&tstKey, srcKey)) { + fprintf(stderr, "RSA Populate key mismatch: pubExp mod q\n"); + failed = 1; + } + + /* test the medium case, private exponent, prime1, prime2 */ + rsaPrivKeyReset(&tstKey); + + tstKey.privateExponent = srcKey->privateExponent; + tstKey.prime1 = srcKey->prime2; /* purposefully swap them to make */ + tstKey.prime2 = srcKey->prime1; /* sure populated swaps them back */ + + rv = RSA_PopulatePrivateKey(&tstKey); + if (rv != SECSuccess) { + fprintf(stderr, "RSA Populate failed: privExp p q\n"); + failed = 1; + } else if (!rsaPrivKeysAreEqual(&tstKey, srcKey)) { + fprintf(stderr, "RSA Populate key mismatch: privExp p q\n"); + failed = 1; + } + + /* test the advanced case, public exponent, private exponent, prime2 */ + rsaPrivKeyReset(&tstKey); + + tstKey.privateExponent = srcKey->privateExponent; + tstKey.publicExponent = srcKey->publicExponent; + tstKey.prime2 = srcKey->prime2; /* use q in the prime2 position */ + + rv = RSA_PopulatePrivateKey(&tstKey); + if (rv != SECSuccess) { + fprintf(stderr, "RSA Populate failed: pubExp privExp q\n"); + fprintf(stderr, " - not fatal\n"); + /* it's possible that we can't uniquely determine the original key + * from just the exponents and prime. Populate returns an error rather + * than return the wrong key. */ + } else if (!rsaPrivKeysAreEqual(&tstKey, srcKey)) { + /* if we returned a key, it *must* be correct */ + fprintf(stderr, "RSA Populate key mismatch: pubExp privExp q\n"); + rv = RSA_PrivateKeyCheck(&tstKey); + failed = 1; + } + + /* test the advanced case2, public exponent, private exponent, modulus */ + rsaPrivKeyReset(&tstKey); + + tstKey.privateExponent = srcKey->privateExponent; + tstKey.publicExponent = srcKey->publicExponent; + tstKey.modulus = srcKey->modulus; + + rv = RSA_PopulatePrivateKey(&tstKey); + if (rv != SECSuccess) { + fprintf(stderr, "RSA Populate failed: pubExp privExp mod\n"); + failed = 1; + } else if (!rsaPrivKeysAreEqual(&tstKey, srcKey)) { + fprintf(stderr, "RSA Populate key mismatch: pubExp privExp mod\n"); + failed = 1; + } + + PORT_FreeArena(srcKey->arena, PR_TRUE); + return failed ? -1 : 0; +} + +/* bltest commands */ +enum { + cmd_Decrypt = 0, + cmd_Encrypt, + cmd_FIPS, + cmd_Hash, + cmd_Nonce, + cmd_Dump, + cmd_RSAPopulate, + cmd_RSAPopulateKV, + cmd_Sign, + cmd_SelfTest, + cmd_Verify +}; + +/* bltest options */ +enum { + opt_B64 = 0, + opt_BufSize, + opt_Restart, + opt_SelfTestDir, + opt_Exponent, + opt_SigFile, + opt_KeySize, + opt_Hex, + opt_Input, + opt_PQGFile, + opt_Key, + opt_HexWSpc, + opt_Mode, + opt_CurveName, + opt_Output, + opt_Repetitions, + opt_ZeroBuf, + opt_Rounds, + opt_Seed, + opt_SigSeedFile, + opt_CXReps, + opt_IV, + opt_WordSize, + opt_UseSeed, + opt_UseSigSeed, + opt_SeedFile, + opt_AAD, + opt_InputOffset, + opt_OutputOffset, + opt_MonteCarlo, + opt_ThreadNum, + opt_SecondsToRun, + opt_CmdLine +}; + +static secuCommandFlag bltest_commands[] = { + { /* cmd_Decrypt */ 'D', PR_FALSE, 0, PR_FALSE }, + { /* cmd_Encrypt */ 'E', PR_FALSE, 0, PR_FALSE }, + { /* cmd_FIPS */ 'F', PR_FALSE, 0, PR_FALSE }, + { /* cmd_Hash */ 'H', PR_FALSE, 0, PR_FALSE }, + { /* cmd_Nonce */ 'N', PR_FALSE, 0, PR_FALSE }, + { /* cmd_Dump */ 'P', PR_FALSE, 0, PR_FALSE }, + { /* cmd_RSAPopulate */ 'R', PR_FALSE, 0, PR_FALSE }, + { /* cmd_RSAPopulateKV */ 'K', PR_FALSE, 0, PR_FALSE }, + { /* cmd_Sign */ 'S', PR_FALSE, 0, PR_FALSE }, + { /* cmd_SelfTest */ 'T', PR_FALSE, 0, PR_FALSE }, + { /* cmd_Verify */ 'V', PR_FALSE, 0, PR_FALSE } +}; + +static secuCommandFlag bltest_options[] = { + { /* opt_B64 */ 'a', PR_FALSE, 0, PR_FALSE }, + { /* opt_BufSize */ 'b', PR_TRUE, 0, PR_FALSE }, + { /* opt_Restart */ 'c', PR_FALSE, 0, PR_FALSE }, + { /* opt_SelfTestDir */ 'd', PR_TRUE, 0, PR_FALSE }, + { /* opt_Exponent */ 'e', PR_TRUE, 0, PR_FALSE }, + { /* opt_SigFile */ 'f', PR_TRUE, 0, PR_FALSE }, + { /* opt_KeySize */ 'g', PR_TRUE, 0, PR_FALSE }, + { /* opt_Hex */ 'h', PR_FALSE, 0, PR_FALSE }, + { /* opt_Input */ 'i', PR_TRUE, 0, PR_FALSE }, + { /* opt_PQGFile */ 'j', PR_TRUE, 0, PR_FALSE }, + { /* opt_Key */ 'k', PR_TRUE, 0, PR_FALSE }, + { /* opt_HexWSpc */ 'l', PR_FALSE, 0, PR_FALSE }, + { /* opt_Mode */ 'm', PR_TRUE, 0, PR_FALSE }, + { /* opt_CurveName */ 'n', PR_TRUE, 0, PR_FALSE }, + { /* opt_Output */ 'o', PR_TRUE, 0, PR_FALSE }, + { /* opt_Repetitions */ 'p', PR_TRUE, 0, PR_FALSE }, + { /* opt_ZeroBuf */ 'q', PR_FALSE, 0, PR_FALSE }, + { /* opt_Rounds */ 'r', PR_TRUE, 0, PR_FALSE }, + { /* opt_Seed */ 's', PR_TRUE, 0, PR_FALSE }, + { /* opt_SigSeedFile */ 't', PR_TRUE, 0, PR_FALSE }, + { /* opt_CXReps */ 'u', PR_TRUE, 0, PR_FALSE }, + { /* opt_IV */ 'v', PR_TRUE, 0, PR_FALSE }, + { /* opt_WordSize */ 'w', PR_TRUE, 0, PR_FALSE }, + { /* opt_UseSeed */ 'x', PR_FALSE, 0, PR_FALSE }, + { /* opt_UseSigSeed */ 'y', PR_FALSE, 0, PR_FALSE }, + { /* opt_SeedFile */ 'z', PR_FALSE, 0, PR_FALSE }, + { /* opt_AAD */ 0, PR_TRUE, 0, PR_FALSE, "aad" }, + { /* opt_InputOffset */ '1', PR_TRUE, 0, PR_FALSE }, + { /* opt_OutputOffset */ '2', PR_TRUE, 0, PR_FALSE }, + { /* opt_MonteCarlo */ '3', PR_FALSE, 0, PR_FALSE }, + { /* opt_ThreadNum */ '4', PR_TRUE, 0, PR_FALSE }, + { /* opt_SecondsToRun */ '5', PR_TRUE, 0, PR_FALSE }, + { /* opt_CmdLine */ '-', PR_FALSE, 0, PR_FALSE } +}; + +int +main(int argc, char **argv) +{ + SECStatus rv = SECFailure; + + double totalTime = 0.0; + PRIntervalTime time1, time2; + PRFileDesc *outfile = NULL; + bltestCipherInfo *cipherInfoListHead, *cipherInfo = NULL; + bltestIOMode ioMode; + int bufsize, exponent, curThrdNum; + char *curveName = NULL; + int i, commandsEntered; + int inoff, outoff; + int threads = 1; + + secuCommand bltest; + bltest.numCommands = sizeof(bltest_commands) / sizeof(secuCommandFlag); + bltest.numOptions = sizeof(bltest_options) / sizeof(secuCommandFlag); + bltest.commands = bltest_commands; + bltest.options = bltest_options; + + progName = strrchr(argv[0], '/'); + if (!progName) + progName = strrchr(argv[0], '\\'); + progName = progName ? progName + 1 : argv[0]; + + rv = NSS_InitializePRErrorTable(); + if (rv != SECSuccess) { + SECU_PrintPRandOSError(progName); + return -1; + } + rv = RNG_RNGInit(); + if (rv != SECSuccess) { + SECU_PrintPRandOSError(progName); + return -1; + } + rv = BL_Init(); + if (rv != SECSuccess) { + SECU_PrintPRandOSError(progName); + return -1; + } + RNG_SystemInfoForRNG(); + + rv = SECU_ParseCommandLine(argc, argv, progName, &bltest); + if (rv == SECFailure) { + fprintf(stderr, "%s: command line parsing error!\n", progName); + goto print_usage; + } + rv = SECFailure; + + cipherInfo = PORT_ZNew(bltestCipherInfo); + cipherInfoListHead = cipherInfo; + + /* Check the number of commands entered on the command line. */ + commandsEntered = 0; + for (i = 0; i < bltest.numCommands; i++) + if (bltest.commands[i].activated) + commandsEntered++; + + if (commandsEntered > 1 && + !(commandsEntered == 2 && bltest.commands[cmd_SelfTest].activated)) { + fprintf(stderr, "%s: one command at a time!\n", progName); + goto print_usage; + } + + if (commandsEntered == 0) { + fprintf(stderr, "%s: you must enter a command!\n", progName); + goto print_usage; + } + + if (bltest.commands[cmd_Sign].activated) + bltest.commands[cmd_Encrypt].activated = PR_TRUE; + if (bltest.commands[cmd_Verify].activated) + bltest.commands[cmd_Decrypt].activated = PR_TRUE; + if (bltest.commands[cmd_Hash].activated) + bltest.commands[cmd_Encrypt].activated = PR_TRUE; + + inoff = outoff = 0; + if (bltest.options[opt_InputOffset].activated) + inoff = PORT_Atoi(bltest.options[opt_InputOffset].arg); + if (bltest.options[opt_OutputOffset].activated) + outoff = PORT_Atoi(bltest.options[opt_OutputOffset].arg); + + testdir = (bltest.options[opt_SelfTestDir].activated) ? strdup(bltest.options[opt_SelfTestDir].arg) + : "."; + + /* + * Handle three simple cases first + */ + + /* test the RSA_PopulatePrivateKey function with known vectors */ + if (bltest.commands[cmd_RSAPopulateKV].activated) { + PORT_Free(cipherInfo); + return doRSAPopulateTestKV(); + } + + /* test the RSA_PopulatePrivateKey function */ + if (bltest.commands[cmd_RSAPopulate].activated) { + unsigned int keySize = 1024; + unsigned long keyExponent = 65537; + int rounds = 1; + int ret = -1; + + if (bltest.options[opt_KeySize].activated) { + keySize = PORT_Atoi(bltest.options[opt_KeySize].arg); + } + if (bltest.options[opt_Rounds].activated) { + rounds = PORT_Atoi(bltest.options[opt_Rounds].arg); + } + if (bltest.options[opt_Exponent].activated) { + keyExponent = PORT_Atoi(bltest.options[opt_Exponent].arg); + } + + for (i = 0; i < rounds; i++) { + printf("Running RSA Populate test round %d\n", i); + ret = doRSAPopulateTest(keySize, keyExponent); + if (ret != 0) { + break; + } + } + if (ret != 0) { + fprintf(stderr, "RSA Populate test round %d: FAILED\n", i); + } + PORT_Free(cipherInfo); + return ret; + } + + /* Do BLAPI self-test */ + if (bltest.commands[cmd_SelfTest].activated) { + PRBool encrypt = PR_TRUE, decrypt = PR_TRUE; + /* user may specified a set of ciphers to test. parse them. */ + bltestCipherMode modesToTest[NUMMODES]; + int numModesToTest = 0; + char *tok, *str; + str = bltest.options[opt_Mode].arg; + while (str) { + tok = strchr(str, ','); + if (tok) + *tok = '\0'; + modesToTest[numModesToTest++] = get_mode(str); + if (tok) { + *tok = ','; + str = tok + 1; + } else { + break; + } + } + if (bltest.commands[cmd_Decrypt].activated && + !bltest.commands[cmd_Encrypt].activated) + encrypt = PR_FALSE; + if (bltest.commands[cmd_Encrypt].activated && + !bltest.commands[cmd_Decrypt].activated) + decrypt = PR_FALSE; + rv = blapi_selftest(modesToTest, numModesToTest, inoff, outoff, + encrypt, decrypt); + PORT_Free(cipherInfo); + return rv == SECSuccess ? 0 : 1; + } + + /* Do FIPS self-test */ + if (bltest.commands[cmd_FIPS].activated) { + PORT_Free(cipherInfo); +#ifdef NSS_FIPS_DISABLED + fprintf(stdout, "FIPS self-test failed with: NSS_FIPS_DISABLED\n"); + return SECFailure; +#else + CK_RV ckrv = sftk_FIPSEntryOK(PR_FALSE); + if (ckrv == CKR_OK) { + fprintf(stdout, "FIPS self-test was successful.\n"); + return SECSuccess; + } + fprintf(stdout, "FIPS self-test failed with the CK_RV: %ld.\n", ckrv); + return SECFailure; +#endif + } + + /* + * Check command line arguments for Encrypt/Decrypt/Hash/Sign/Verify + */ + + if ((bltest.commands[cmd_Decrypt].activated || + bltest.commands[cmd_Verify].activated) && + bltest.options[opt_BufSize].activated) { + fprintf(stderr, "%s: Cannot use a nonce as input to decrypt/verify.\n", + progName); + goto print_usage; + } + + if (bltest.options[opt_Mode].activated) { + cipherInfo->mode = get_mode(bltest.options[opt_Mode].arg); + if (cipherInfo->mode == bltestINVALID) { + goto print_usage; + } + } else { + fprintf(stderr, "%s: You must specify a cipher mode with -m.\n", + progName); + goto print_usage; + } + + if (bltest.options[opt_Repetitions].activated && + bltest.options[opt_SecondsToRun].activated) { + fprintf(stderr, "%s: Operation time should be defined in either " + "repetitions(-p) or seconds(-5) not both", + progName); + goto print_usage; + } + + if (bltest.options[opt_Repetitions].activated) { + cipherInfo->repetitionsToPerfom = + PORT_Atoi(bltest.options[opt_Repetitions].arg); + } else { + cipherInfo->repetitionsToPerfom = 0; + } + + if (bltest.options[opt_SecondsToRun].activated) { + cipherInfo->seconds = PORT_Atoi(bltest.options[opt_SecondsToRun].arg); + } else { + cipherInfo->seconds = 0; + } + + if (bltest.options[opt_CXReps].activated) { + cipherInfo->cxreps = PORT_Atoi(bltest.options[opt_CXReps].arg); + } else { + cipherInfo->cxreps = 0; + } + + if (bltest.options[opt_ThreadNum].activated) { + threads = PORT_Atoi(bltest.options[opt_ThreadNum].arg); + if (threads <= 0) { + threads = 1; + } + } + + /* Dump a file (rsakey, dsakey, etc.) */ + if (bltest.commands[cmd_Dump].activated) { + rv = dump_file(cipherInfo->mode, bltest.options[opt_Input].arg); + PORT_Free(cipherInfo); + return rv; + } + + /* default input mode is binary */ + ioMode = (bltest.options[opt_B64].activated) + ? bltestBase64Encoded + : (bltest.options[opt_Hex].activated) + ? bltestHexStream + : (bltest.options[opt_HexWSpc].activated) ? bltestHexSpaceDelim + : bltestBinary; + + if (bltest.options[opt_Exponent].activated) + exponent = PORT_Atoi(bltest.options[opt_Exponent].arg); + else + exponent = 65537; + + if (bltest.options[opt_CurveName].activated) + curveName = PORT_Strdup(bltest.options[opt_CurveName].arg); + else + curveName = NULL; + + if (bltest.commands[cmd_Verify].activated && + !bltest.options[opt_SigFile].activated) { + fprintf(stderr, "%s: You must specify a signature file with -f.\n", + progName); + + print_usage: + if (cipherInfo) { + PORT_Free(cipherInfo); + } + Usage(); + } + + if (bltest.options[opt_MonteCarlo].activated) { + cipherInfo->mCarlo = PR_TRUE; + } else { + cipherInfo->mCarlo = PR_FALSE; + } + + for (curThrdNum = 0; curThrdNum < threads; curThrdNum++) { + int keysize = 0; + PRFileDesc *file = NULL, *infile; + bltestParams *params; + char *instr = NULL; + PLArenaPool *arena; + + if (curThrdNum > 0) { + bltestCipherInfo *newCInfo = PORT_ZNew(bltestCipherInfo); + if (!newCInfo) { + fprintf(stderr, "%s: Can not allocate memory.\n", progName); + goto exit_point; + } + newCInfo->mode = cipherInfo->mode; + newCInfo->mCarlo = cipherInfo->mCarlo; + newCInfo->repetitionsToPerfom = + cipherInfo->repetitionsToPerfom; + newCInfo->seconds = cipherInfo->seconds; + newCInfo->cxreps = cipherInfo->cxreps; + cipherInfo->next = newCInfo; + cipherInfo = newCInfo; + } + arena = PORT_NewArena(BLTEST_DEFAULT_CHUNKSIZE); + if (!arena) { + fprintf(stderr, "%s: Can not allocate memory.\n", progName); + goto exit_point; + } + cipherInfo->arena = arena; + params = &cipherInfo->params; + + /* Set up an encryption key. */ + keysize = 0; + file = NULL; + if (is_symmkeyCipher(cipherInfo->mode) || + is_aeadCipher(cipherInfo->mode)) { + char *keystr = NULL; /* if key is on command line */ + if (bltest.options[opt_Key].activated) { + if (bltest.options[opt_CmdLine].activated) { + keystr = bltest.options[opt_Key].arg; + } else { + file = PR_Open(bltest.options[opt_Key].arg, + PR_RDONLY, 00660); + } + } else { + if (bltest.options[opt_KeySize].activated) + keysize = PORT_Atoi(bltest.options[opt_KeySize].arg); + else + keysize = 8; /* use 64-bit default (DES) */ + /* save the random key for reference */ + file = PR_Open("tmp.key", PR_WRONLY | PR_CREATE_FILE, 00660); + } + params->key.mode = ioMode; + setupIO(cipherInfo->arena, ¶ms->key, file, keystr, keysize); + if (file) + PR_Close(file); + } else if (is_pubkeyCipher(cipherInfo->mode)) { + if (bltest.options[opt_Key].activated) { + file = PR_Open(bltest.options[opt_Key].arg, PR_RDONLY, 00660); + } else { + if (bltest.options[opt_KeySize].activated) + keysize = PORT_Atoi(bltest.options[opt_KeySize].arg); + else + keysize = 64; /* use 512-bit default */ + file = PR_Open("tmp.key", PR_WRONLY | PR_CREATE_FILE, 00660); + } + params->key.mode = bltestBase64Encoded; + pubkeyInitKey(cipherInfo, file, keysize, exponent, curveName); + PR_Close(file); + } + + /* set up an initialization vector. */ + if (cipher_requires_IV(cipherInfo->mode)) { + char *ivstr = NULL; + bltestSymmKeyParams *skp; + file = NULL; +#ifdef NSS_SOFTOKEN_DOES_RC5 + if (cipherInfo->mode == bltestRC5_CBC) + skp = (bltestSymmKeyParams *)¶ms->rc5; + else +#endif + skp = ¶ms->sk; + if (bltest.options[opt_IV].activated) { + if (bltest.options[opt_CmdLine].activated) { + ivstr = bltest.options[opt_IV].arg; + } else { + file = PR_Open(bltest.options[opt_IV].arg, + PR_RDONLY, 00660); + } + } else { + /* save the random iv for reference */ + file = PR_Open("tmp.iv", PR_WRONLY | PR_CREATE_FILE, 00660); + } + memset(&skp->iv, 0, sizeof skp->iv); + skp->iv.mode = ioMode; + setupIO(cipherInfo->arena, &skp->iv, file, ivstr, keysize); + if (file) { + PR_Close(file); + } + } + + /* set up an initialization vector. */ + if (is_authCipher(cipherInfo->mode)) { + char *aadstr = NULL; + bltestAuthSymmKeyParams *askp; + file = NULL; + askp = ¶ms->ask; + if (bltest.options[opt_AAD].activated) { + if (bltest.options[opt_CmdLine].activated) { + aadstr = bltest.options[opt_AAD].arg; + } else { + file = PR_Open(bltest.options[opt_AAD].arg, + PR_RDONLY, 00660); + } + } else { + file = NULL; + } + memset(&askp->aad, 0, sizeof askp->aad); + askp->aad.mode = ioMode; + setupIO(cipherInfo->arena, &askp->aad, file, aadstr, 0); + if (file) { + PR_Close(file); + } + } + + if (bltest.commands[cmd_Verify].activated) { + file = PR_Open(bltest.options[opt_SigFile].arg, PR_RDONLY, 00660); + if (is_sigCipher(cipherInfo->mode)) { + memset(¶ms->asymk.sig, 0, sizeof(bltestIO)); + params->asymk.sig.mode = ioMode; + setupIO(cipherInfo->arena, ¶ms->asymk.sig, file, NULL, 0); + } + if (file) { + PR_Close(file); + } + } + + if (bltest.options[opt_PQGFile].activated) { + file = PR_Open(bltest.options[opt_PQGFile].arg, PR_RDONLY, 00660); + params->asymk.cipherParams.dsa.pqgdata.mode = bltestBase64Encoded; + setupIO(cipherInfo->arena, ¶ms->asymk.cipherParams.dsa.pqgdata, + file, NULL, 0); + if (file) { + PR_Close(file); + } + } + + /* Set up the input buffer */ + if (bltest.options[opt_Input].activated) { + if (bltest.options[opt_CmdLine].activated) { + instr = bltest.options[opt_Input].arg; + infile = NULL; + } else { + /* form file name from testdir and input arg. */ + char *filename = bltest.options[opt_Input].arg; + if (bltest.options[opt_SelfTestDir].activated && + testdir && filename && filename[0] != '/') { + filename = PR_smprintf("%s/tests/%s/%s", testdir, + mode_strings[cipherInfo->mode], + filename); + if (!filename) { + fprintf(stderr, "%s: Can not allocate memory.\n", + progName); + goto exit_point; + } + infile = PR_Open(filename, PR_RDONLY, 00660); + PR_smprintf_free(filename); + } else { + infile = PR_Open(filename, PR_RDONLY, 00660); + } + } + } else if (bltest.options[opt_BufSize].activated) { + /* save the random plaintext for reference */ + char *tmpFName = PR_smprintf("tmp.in.%d", curThrdNum); + if (!tmpFName) { + fprintf(stderr, "%s: Can not allocate memory.\n", progName); + goto exit_point; + } + infile = PR_Open(tmpFName, PR_WRONLY | PR_CREATE_FILE, 00660); + PR_smprintf_free(tmpFName); + } else { + infile = PR_STDIN; + } + if (!infile) { + fprintf(stderr, "%s: Failed to open input file.\n", progName); + goto exit_point; + } + cipherInfo->input.mode = ioMode; + + /* Set up the output stream */ + if (bltest.options[opt_Output].activated) { + /* form file name from testdir and input arg. */ + char *filename = bltest.options[opt_Output].arg; + if (bltest.options[opt_SelfTestDir].activated && + testdir && filename && filename[0] != '/') { + filename = PR_smprintf("%s/tests/%s/%s", testdir, + mode_strings[cipherInfo->mode], + filename); + if (!filename) { + fprintf(stderr, "%s: Can not allocate memory.\n", progName); + goto exit_point; + } + outfile = PR_Open(filename, PR_WRONLY | PR_CREATE_FILE, 00660); + PR_smprintf_free(filename); + } else { + outfile = PR_Open(filename, PR_WRONLY | PR_CREATE_FILE, 00660); + } + } else { + outfile = PR_STDOUT; + } + if (!outfile) { + fprintf(stderr, "%s: Failed to open output file.\n", progName); + rv = SECFailure; + goto exit_point; + } + cipherInfo->output.mode = ioMode; + if (bltest.options[opt_SelfTestDir].activated && ioMode == bltestBinary) + cipherInfo->output.mode = bltestBase64Encoded; + + if (is_hashCipher(cipherInfo->mode)) + cipherInfo->params.hash.restart = + bltest.options[opt_Restart].activated; + + bufsize = 0; + if (bltest.options[opt_BufSize].activated) + bufsize = PORT_Atoi(bltest.options[opt_BufSize].arg); + + /*infile = NULL;*/ + setupIO(cipherInfo->arena, &cipherInfo->input, infile, instr, bufsize); + if (infile && infile != PR_STDIN) + PR_Close(infile); + misalignBuffer(cipherInfo->arena, &cipherInfo->input, inoff); + + cipherInit(cipherInfo, bltest.commands[cmd_Encrypt].activated); + misalignBuffer(cipherInfo->arena, &cipherInfo->output, outoff); + } + + if (!bltest.commands[cmd_Nonce].activated) { + TIMESTART(); + cipherInfo = cipherInfoListHead; + while (cipherInfo != NULL) { + cipherInfo->cipherThread = + PR_CreateThread(PR_USER_THREAD, + ThreadExecTest, + cipherInfo, + PR_PRIORITY_NORMAL, + PR_GLOBAL_THREAD, + PR_JOINABLE_THREAD, + 0); + cipherInfo = cipherInfo->next; + } + + cipherInfo = cipherInfoListHead; + while (cipherInfo != NULL) { + PR_JoinThread(cipherInfo->cipherThread); + finishIO(&cipherInfo->output, outfile); + cipherInfo = cipherInfo->next; + } + TIMEFINISH(totalTime, 1); + } + + cipherInfo = cipherInfoListHead; + if (cipherInfo->repetitions > 0 || cipherInfo->cxreps > 0 || + threads > 1) + dump_performance_info(cipherInfoListHead, totalTime, + bltest.commands[cmd_Encrypt].activated, + (cipherInfo->repetitions == 0)); + + rv = SECSuccess; + +exit_point: + if (outfile && outfile != PR_STDOUT) + PR_Close(outfile); + cipherInfo = cipherInfoListHead; + while (cipherInfo != NULL) { + bltestCipherInfo *tmpInfo = cipherInfo; + + if (cipherInfo->arena) + PORT_FreeArena(cipherInfo->arena, PR_TRUE); + cipherInfo = cipherInfo->next; + PORT_Free(tmpInfo); + } + + /*NSS_Shutdown();*/ + + return SECSuccess; +} |