/* 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 #include #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 "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, /* . */ bltestRC2_ECB, /* . */ bltestRC2_CBC, /* . */ 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, /* . */ bltestSEED_ECB, /* SEED algorithm */ bltestSEED_CBC, /* SEED algorithm */ 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", "rc2_ecb", "rc2_cbc", "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", "seed_ecb", "seed_cbc", "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 <= bltestSEED_CBC) 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: 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: case bltestRC2_CBC: #ifdef NSS_SOFTOKEN_DOES_RC5 case bltestRC5_CBC: #endif case bltestAES_CBC: case bltestAES_CTS: case bltestAES_CTR: case bltestAES_GCM: case bltestCAMELLIA_CBC: case bltestSEED_CBC: 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); } 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); } 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_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); } 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); } 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; } 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; } 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_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; } 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; } 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; case bltestRC2_ECB: case bltestRC2_CBC: SECITEM_AllocItem(cipherInfo->arena, &cipherInfo->output.buf, cipherInfo->input.pBuf.len); return bltest_rc2_init(cipherInfo, encrypt); break; 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); #endif return bltest_rc5_init(cipherInfo, encrypt); break; 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; case bltestSEED_ECB: case bltestSEED_CBC: SECITEM_AllocItem(cipherInfo->arena, &cipherInfo->output.buf, cipherInfo->input.pBuf.len); return bltest_seed_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; case bltestSEED_ECB: case bltestSEED_CBC: SEED_DestroyContext((SEEDContext *)cipherInfo->cx, PR_TRUE); break; case bltestCHACHA20: ChaCha20Poly1305_DestroyContext((ChaCha20Poly1305Context *) cipherInfo->cx, PR_TRUE); break; case bltestRC2_ECB: case bltestRC2_CBC: RC2_DestroyContext((RC2Context *)cipherInfo->cx, PR_TRUE); break; 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; } } return PR_smprintf("%d%s", spl[i], marks[i]); } 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: case bltestSEED_ECB: case bltestSEED_CBC: case bltestRC2_ECB: case bltestRC2_CBC: 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: sprintf(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: case bltestRC2_CBC: case bltestAES_CBC: case bltestAES_CTS: case bltestAES_CTR: case bltestCAMELLIA_CBC: case bltestSEED_CBC: sprintf(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: case bltestRC2_ECB: case bltestRC4: case bltestAES_ECB: case bltestCAMELLIA_ECB: case bltestSEED_ECB: sprintf(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: sprintf(filename, "%s/tests/%s/%s%d", testdir, modestr, "iv", j); load_file_data(arena, ¶ms->sk.iv, filename, bltestBinary); sprintf(filename, "%s/tests/%s/%s%d", testdir, modestr, "key", j); load_file_data(arena, ¶ms->sk.key, filename, bltestBinary); sprintf(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: sprintf(filename, "%s/tests/%s/%s%d", testdir, modestr, "ciphertext", j); load_file_data(arena, ¶ms->asymk.sig, filename, bltestBase64Encoded); /* fall through */ case bltestRSA_OAEP: sprintf(filename, "%s/tests/%s/%s%d", testdir, modestr, "seed", j); load_file_data(arena, ¶ms->asymk.cipherParams.rsa.seed, filename, bltestBase64Encoded); sprintf(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); sprintf(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: sprintf(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: sprintf(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); sprintf(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); sprintf(filename, "%s/tests/%s/%s%d", testdir, modestr, "keyseed", j); load_file_data(arena, ¶ms->asymk.cipherParams.dsa.keyseed, filename, bltestBase64Encoded); sprintf(filename, "%s/tests/%s/%s%d", testdir, modestr, "sigseed", j); load_file_data(arena, ¶ms->asymk.cipherParams.dsa.sigseed, filename, bltestBase64Encoded); sprintf(filename, "%s/tests/%s/%s%d", testdir, modestr, "ciphertext", j); load_file_data(arena, ¶ms->asymk.sig, filename, bltestBase64Encoded); break; case bltestECDSA: sprintf(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); sprintf(filename, "%s/tests/%s/%s%d", testdir, modestr, "sigseed", j); load_file_data(arena, ¶ms->asymk.cipherParams.ecdsa.sigseed, filename, bltestBase64Encoded); sprintf(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 */ sprintf(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++) { sprintf(filename, "%s/tests/%s/%s%d", testdir, modestr, "plaintext", j); load_file_data(arena, &pt, filename, is_sigCipher(mode) ? bltestBase64Encoded : bltestBinary); sprintf(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) { CK_RV ckrv = sftk_FIPSEntryOK(); fprintf(stdout, "CK_RV: %ld.\n", ckrv); PORT_Free(cipherInfo); if (ckrv == CKR_OK) return SECSuccess; return SECFailure; } /* * 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; }