/* Caller determines depth from other sources (e.g. AlgId.Params) */ feeReturn feePubKeyInitFromECDSAPubBlob(feePubKey pubKey, const unsigned char *keyBlob, unsigned keyBlobLen, feeDepth depth) { pubKeyInst *pkinst = (pubKeyInst *)pubKey; if(pkinst == NULL) { return FR_BadPubKey; } curveParams *cp = curveParamsForDepth(depth); if(cp == NULL) { return FR_IllegalDepth; } unsigned giantBytes = (cp->q + 7) / 8; unsigned blobSize = 1 + (2 * giantBytes); if(keyBlobLen != blobSize) { dbgLog(("feePubKeyInitFromECDSAPubBlob: bad blobLen\n")); return FR_BadKeyBlob; } if(*keyBlob != 0x04) { dbgLog(("feePubKeyInitFromECDSAPubBlob: bad blob leader\n")); return FR_BadKeyBlob; } pkinst->cp = cp; pkinst->plus = new_public(cp, CURVE_PLUS); deserializeGiant(keyBlob+1, pkinst->plus->x, giantBytes); deserializeGiant(keyBlob+1+giantBytes, pkinst->plus->y, giantBytes); return FR_Success; }
/* * Create a giant, initialized with specified char[] data. */ giant giant_with_data(const unsigned char *d, int len) { int numDigits = BYTES_TO_GIANT_DIGITS(len); giant result; result = newGiant(numDigits); deserializeGiant(d, result, len); return result; }
/* * fill a pre-allocd giant with specified number of bytes of random * data. *Buf is mallocd and uninitialized and will change here. */ static void genGiant(giant g, unsigned numBytes, unsigned char *buf) { int i; fillData(numBytes, buf); deserializeGiant(buf, g, numBytes); /* set random sign; deserializeGiant() is always positive */ i = RAND(); if(i & 1) { g->sign = -g->sign; } /* avoid zero data - too many pitfalls with mod and div */ while(isZero(g)) { g->sign = 1; g->n[0] = RAND(); } }
feeReturn feePubKeyInitFromECDSAPrivBlob(feePubKey pubKey, const unsigned char *keyBlob, unsigned keyBlobLen, feeDepth depth) { pubKeyInst *pkinst = (pubKeyInst *)pubKey; if(pkinst == NULL) { return FR_BadPubKey; } curveParams *cp = curveParamsForDepth(depth); if(cp == NULL) { return FR_IllegalDepth; } unsigned giantDigits = cp->basePrime->sign; unsigned giantBytes = (cp->q + 7) / 8; /* * The specified private key can be one byte smaller than the modulus */ if((keyBlobLen > giantBytes) || (keyBlobLen < (giantBytes - 1))) { dbgLog(("feePubKeyInitFromECDSAPrivBlob: bad blobLen\n")); return FR_BadKeyBlob; } pkinst->cp = cp; /* cook up a new private giant */ pkinst->privGiant = newGiant(giantDigits); if(pkinst->privGiant == NULL) { return FR_Memory; } deserializeGiant(keyBlob, pkinst->privGiant, keyBlobLen); /* since this blob only had the private data, infer the remaining fields */ pkinst->plus = new_public(pkinst->cp, CURVE_PLUS); set_priv_key_giant(pkinst->plus, pkinst->privGiant); return FR_Success; }
/* * Decrypt (exactly) a block of data. Caller malloc's plainText. Always * generates feeFEEDExpPlainBlockSize of plaintext, unless finalBlock is * non-zero (in which case feeFEEDExpPlainBlockSize or less bytes of * plainText are generated). */ feeReturn feeFEEDExpDecryptBlock(feeFEEDExp feed, const unsigned char *cipherText, unsigned cipherTextLen, unsigned char *plainText, unsigned *plainTextLen, // RETURNED int finalBlock) { feedInst *finst = (feedInst *) feed; char g; int s; feeReturn frtn = FR_Success; curveParams *cp = finst->cp; if(finst->gPriv == NULL) { /* * Can't decrypt without private data */ return FR_BadPubKey; } /* * grab xm, xc, and g from cipherText */ deserializeGiant(cipherText, finst->xm, finst->cp->minBytes); cipherText += finst->cp->minBytes; deserializeGiant(cipherText, finst->xc, finst->cp->minBytes); cipherText += finst->cp->minBytes; g = *cipherText; #if FEED_DEBUG printf("decrypt g=%d\n", g); printf(" privKey : "); PRINT_GIANT(finst->gPriv); printf(" xm : "); PRINT_GIANT(finst->xm); printf(" xc : "); PRINT_GIANT(finst->xc); #endif // FEED_DEBUG if((g & CLUE_ELL_ADD_SIGN) == CLUE_ELL_ADD_SIGN_PLUS) { s = SIGN_PLUS; } else { s = SIGN_MINUS; } /* * xc = r(P1?) * xc := r(P1?)(pri) = xq * xp = data + r(priB+) +/- pri(rB?) */ elliptic_simple(finst->xc, finst->gPriv, cp); #if FEED_DEBUG printf(" xc1 : "); PRINT_GIANT(finst->xc); #endif elliptic_add(finst->xm, finst->xc, finst->xp, cp, s); /* * plaintext in xp */ #if FEED_DEBUG printf(" xp : "); PRINT_GIANT(finst->xp); #endif // FEED_DEBUG if(finalBlock) { /* * Snag data from xp in order to find out how much to move to * *plainText */ unsigned char *ptext = (unsigned char*) fmalloc(finst->plainBlockSize); serializeGiant(finst->xp, ptext, finst->plainBlockSize); *plainTextLen = ptext[finst->plainBlockSize - 1]; #if FEED_DEBUG printf("decrypt: resid 0x%x\n", *plainTextLen); #endif if(*plainTextLen == RESID_ZERO) { *plainTextLen = 0; } else if(*plainTextLen > (finst->plainBlockSize - 1)) { dbgLog(("feeFEEDExpDecryptBlock: ptext overflow!\n")); frtn = FR_BadCipherText; } else { bcopy(ptext, plainText, *plainTextLen); } ffree(ptext); } else { *plainTextLen = finst->plainBlockSize; serializeGiant(finst->xp, plainText, *plainTextLen); } return frtn; }
/* * Encrypt a block or less of data. Caller malloc's cipherText. */ feeReturn feeFEEDExpEncryptBlock(feeFEEDExp feed, const unsigned char *plainText, unsigned plainTextLen, unsigned char *cipherText, unsigned *cipherTextLen, // RETURNED int finalBlock) { feedInst *finst = (feedInst *) feed; int index; /* which curve (+/- 1) */ char g = 0; /* parity, which_curve bits in ciphertext */ key B; unsigned char *ptext; /* for final block */ unsigned ctextLen; feeReturn frtn = FR_Success; giant x1; unsigned randLen; curveParams *cp = finst->cp; randLen = cp->minBytes+8; // +8bytes (64bits) to reduce the biais when with reduction mod prime. Per FIPS186-4 - "Using Extra Random Bits" if(plainTextLen > finst->plainBlockSize) { return FR_IllegalArg; } else if ((plainTextLen < finst->plainBlockSize) && !finalBlock) { return FR_IllegalArg; } /* * Init only on first encrypt */ if((finst->randFcn == NULL) && (finst->rand == NULL)) { finst->rand = feeRandAlloc(); } if(finst->randData == NULL) { finst->randData = (unsigned char*) fmalloc(randLen); } /* * plaintext as giant xp */ if(finalBlock) { ptext = (unsigned char*) fmalloc(finst->plainBlockSize); bzero(ptext, finst->plainBlockSize); if(plainTextLen) { /* * 0 for empty block with resid length 0 */ bcopy(plainText, ptext, plainTextLen); } if(plainTextLen < finst->plainBlockSize) { if(plainTextLen == 0) { /* * Special case - can't actually write zero here; * it screws up deserializing the giant during * decrypt */ ptext[finst->plainBlockSize - 1] = RESID_ZERO; } else { ptext[finst->plainBlockSize - 1] = plainTextLen; } #if FEED_DEBUG printf("encrypt: resid 0x%x\n", ptext[finst->plainBlockSize - 1]); #endif } /* * else handle evenly aligned case below... */ deserializeGiant(ptext, finst->xp, finst->plainBlockSize); ffree(ptext); } else { deserializeGiant(plainText, finst->xp, plainTextLen); } #if FEED_DEBUG printf("encrypt:\n"); printf(" xp : "); PRINT_GIANT(finst->xp); #endif // FEED_DEBUG /* * pick curve B? that data lies upon */ index = which_curve(finst->xp, finst->cp); if(index == CURVE_PLUS) { B = finst->plus; x1 = finst->cp->x1Plus; } else { B = finst->minus; x1 = finst->cp->x1Minus; } #if FEED_DEBUG printf(" which_curve: %s\n", (index == CURVE_PLUS) ? "CURVE_PLUS" : "CURVE_MINUS"); #endif /* * random number as giant xaux */ if(finst->randFcn != NULL) { finst->randFcn(finst->randRef, finst->randData, randLen); } else { feeRandBytes(finst->rand, finst->randData, randLen); } deserializeGiant(finst->randData, finst->xaux, randLen); #if FEE_DEBUG if(isZero(finst->xaux)) { printf("feeFEEDExpEncryptBlock: random xaux = 0!\n"); } #endif // FEE_DEBUG /* * Justify random # to be in [2, minimumX1Order]. */ lesserX1OrderJustify(finst->xaux, cp); #if FEED_DEBUG printf(" xaux: "); PRINT_GIANT(finst->xaux); #endif // FEED_DEBUG gtog(B->x, finst->xq); // xq = pubB? elliptic_simple(finst->xq, finst->xaux, cp); // xq = r(pubB?) #if FEED_DEBUG printf(" r(pubB?): "); PRINT_GIANT(finst->xq); #endif elliptic_add(finst->xp, finst->xq, finst->xm, cp, SIGN_PLUS); // xm = data + r(pubB?) gtog(x1, finst->xc); elliptic_simple(finst->xc, finst->xaux, cp); // xc = r(P1?) elliptic_add(finst->xm, finst->xq, finst->xaux, cp, SIGN_PLUS); // xaux = xm + xq (for curve +1) // = (data + r(pubB?)) + r(pubB?) if(gcompg(finst->xaux, finst->xp) == 0) { g |= CLUE_ELL_ADD_SIGN_PLUS; } else { g |= CLUE_ELL_ADD_SIGN_MINUS; #if FEED_DEBUG /* this better be true.... */ elliptic_add(finst->xm, finst->xq, finst->xaux, cp, SIGN_MINUS); if(gcompg(finst->xaux, finst->xp)) { printf("*******elliptic_add(xm, xq, -1) != xp! *************\n"); printf(" xq : "); PRINT_GIANT(finst->xq); printf(" ell_add(xm, xq, -1) : "); PRINT_GIANT(finst->xaux); } #endif } // g = (xaux == data) ? add : subtract /* * Ciphertext = (xm, xc, g) */ serializeGiant(finst->xm, cipherText, cp->minBytes); cipherText += cp->minBytes; serializeGiant(finst->xc, cipherText, cp->minBytes); cipherText += cp->minBytes; *cipherText++ = g; ctextLen = finst->cipherBlockSize; #if FEED_DEBUG printf(" xm : "); PRINT_GIANT(finst->xm); printf(" xc : "); PRINT_GIANT(finst->xc); printf(" g : %d\n", g); #endif // FEED_DEBUG if(finalBlock && (plainTextLen == finst->plainBlockSize)) { /* * Special case: finalBlock true, plainTextLen == blockSize. * In this case we generate one more block of ciphertext, * with a resid length of zero. */ unsigned moreCipher; // additional cipherLen #if FEED_DEBUG printf("encrypt: one more empty block\n"); #endif frtn = feeFEEDExpEncryptBlock(feed, NULL, // plainText not used 0, // resid cipherText, // append... &moreCipher, 1); if(frtn == FR_Success) { ctextLen += moreCipher; } } *cipherTextLen = ctextLen; return frtn; }
/* * Decrypt (exactly) a block of data. Caller malloc's plainText. Always * generates feeFEEDPlainBlockSize of plaintext, unless finalBlock is * non-zero (in which case feeFEEDPlainBlockSize or less bytes of plainText are * generated). */ feeReturn feeFEEDDecryptBlock(feeFEED feed, const unsigned char *cipherText, unsigned cipherTextLen, unsigned char *plainText, unsigned *plainTextLen, // RETURNED int finalBlock) { feedInst *finst = (feedInst *) feed; feeReturn frtn = FR_Success; unsigned char clueByte; giant thisClue; // not alloc'd giant thisS; // ditto int parity; if(finst->rsCtext == NULL) { /* * Init'd for encrypt? */ return FR_IllegalArg; } if(cipherTextLen != finst->cipherBlockSize) { dbgLog(("feeFEEDDecryptBlock: bad cipherTextLen\n")); return FR_IllegalArg; } if(finst->rsBlockCount < finst->rsSizeCipherBlocks) { /* * Processing initialRS, FEEDExp-encrypted */ unsigned char *rsPtr = finst->rsCtext + (finst->rsBlockCount * finst->cipherBlockSize); unsigned feedExpCipherSize; if(finalBlock) { dbgLog(("feeFEEDDecryptBlock: incomplete initialRS\n")); return FR_BadCipherText; } bcopy(cipherText, rsPtr, finst->cipherBlockSize); finst->rsBlockCount++; if(finst->rsBlockCount < finst->rsSizeCipherBlocks) { /* * Not done with this yet... */ bprintf(("=== FEED Decrypt: gobbled 0x%x bytes ctext, no ptext (1)\n", cipherTextLen)); *plainTextLen = 0; return FR_Success; } #if FEED_DEBUG if((finst->rsBlockCount * finst->cipherBlockSize) < finst->rsCtextSize) { dbgLog(("feeFEEDDecryptBlock: rsCtextSize underflow!\n")); return FR_Internal; } #endif // FEED_DEBUG /* * OK, we should have the FEEDExp ciphertext for initialRS * in rsCtext. Note the last few bytes are extra; we don't * pass them to FEEDExp. */ feedExpCipherSize = feeFEEDCipherBlockSize(finst->feedExp); frtn = feeFEEDExpDecrypt(finst->feedExp, finst->rsCtext, finst->rsCtextSize, &finst->initialRS, &finst->initialRSSize); if(frtn) { dbgLog(("feeFEEDDecryptBlock: error decrypting " "initialRS (%s)\n", feeReturnString(frtn))); return FR_BadCipherText; } /* * we already know how long this should be... */ if(finst->initialRSSize != finst->initialRSSize) { dbgLog(("feeFEEDDecryptBlock: initialRS sync error\n")); return FR_BadCipherText; } /* * Set up clues */ if(initFromRS(finst)) { dbgLog(("feeFEEDDecryptBlock: bad initialRS\n")); return FR_BadCipherText; } else { /* * Normal completion of last cipherblock containing * initialRS. */ bprintf(("=== FEED Decrypt: gobbled 0x%x bytes ctext, no ptext (2)\n", cipherTextLen)); *plainTextLen = 0; return FR_Success; } } /* * grab xm and clueByte from cipherText */ deserializeGiant(cipherText, finst->xm, finst->cp->minBytes); cipherText += finst->cp->minBytes; clueByte = *cipherText; if((clueByte & CLUE_BIT) == CLUE_PLUS) { thisClue = finst->cluePlus; thisS = finst->sPlus; } else { thisClue = finst->clueMinus; thisS = finst->sMinus; } if((clueByte & PARITY_BIT) == PARITY_PLUS) { parity = SIGN_PLUS; } else { parity = SIGN_MINUS; } /* * recover xp * xp = xm + clue(+/-) w/parity * adjust clue * clue[n+1] = r * clue[n] + (s * P1) */ elliptic_add(thisClue, finst->xm, finst->xp, finst->cp, parity); elliptic_simple(thisClue, finst->r, finst->cp); gtog(thisClue, finst->tmp1); elliptic_add(finst->tmp1, thisS, thisClue, finst->cp, SIGN_PLUS); /* * plaintext in xp */ #if FEED_DEBUG printf("decrypt clue %d\n", clueByte); printf(" xp : "); printGiant(finst->xp); printf(" xm : "); printGiant(finst->xm); printf(" cluePlus :"); printGiant(finst->cluePlus); printf(" clueMinus :"); printGiant(finst->clueMinus); #endif // FEED_DEBUG if(finalBlock) { /* * Snag data from xp in order to find out how much to move to * *plainText */ unsigned char *ptext = (unsigned char*) fmalloc(finst->plainBlockSize); serializeGiant(finst->xp, ptext, finst->plainBlockSize); *plainTextLen = ptext[finst->plainBlockSize - 1]; if(*plainTextLen == RESID_ZERO) { bprintf(("=== FEED Decrypt: RESID_ZERO\n")); *plainTextLen = 0; } else if(*plainTextLen > (finst->plainBlockSize - 1)) { dbgLog(("feeFEEDDecryptBlock: ptext overflow!\n")); bprintf(("feeFEEDDecryptBlock: ptext overflow!\n")); frtn = FR_BadCipherText; } else { bprintf(("=== FEED Decrypt: resid len 0x%x\n", *plainTextLen)); bcopy(ptext, plainText, *plainTextLen); } ffree(ptext); } else { *plainTextLen = finst->plainBlockSize; serializeGiant(finst->xp, plainText, *plainTextLen); } bprintf(("=== FEED decryptBlock ptextLen 0x%x ctextLen 0x%x\n", *plainTextLen, cipherTextLen)); return frtn; }
/* * Encrypt a block or less of data. Caller malloc's cipherText. * Generates up to feeFEEDCipherBufSize() bytes of ciphertext. */ feeReturn feeFEEDEncryptBlock(feeFEED feed, const unsigned char *plainText, unsigned plainTextLen, unsigned char *cipherText, unsigned *cipherTextLen, // RETURNED int finalBlock) { feedInst *finst = (feedInst *) feed; unsigned ctextLen = 0; feeReturn frtn = FR_Success; int whichCurve; giant thisClue; // not alloc'd or freed giant thisS; // ditto unsigned char clueByte; if(plainTextLen > finst->plainBlockSize) { return FR_IllegalArg; } if((plainTextLen < finst->plainBlockSize) && !finalBlock) { return FR_IllegalArg; } if(finst->initialRS == NULL) { /* * Init'd for decrypt? */ return FR_IllegalArg; } /* * First block - encrypt initialRS via FEEDExp */ if(finst->rsBlockCount == 0) { unsigned char *thisCtext; // malloc's by FEEDExp unsigned padLen; if(finst->initialRS == NULL) { /* * init'd for decrypt or reused */ dbgLog(("feeFEEDEncryptBlock: NULL initialRS!\n")); return FR_IllegalArg; } frtn = feeFEEDExpEncrypt(finst->feedExp, finst->initialRS, finst->initialRSSize, &thisCtext, &ctextLen); if(frtn) { /* * Should never happen... */ dbgLog(("feeFEEDEncryptBlock: error writing encrypted" " initialRS (%s)\n", feeReturnString(frtn))); return FR_Internal; } bcopy(thisCtext, cipherText, ctextLen); cipherText += ctextLen; ffree(thisCtext); finst->rsBlockCount = finst->rsSizeCipherBlocks; padLen = finst->cipherBlockSize - (ctextLen % finst->cipherBlockSize); // zeros to write #if 0 /* FEED_DEBUG */ /* * Hard-coded assumptions and tests about initRSSize... * Currently we assume that initRSSize % expBlockSize = 0 */ if((ctextLen / finst->cipherBlockSize) != 5) { dbgLog(("feeFEEDEncryptBlock: cipherblock size screwup (1)\n")); return FR_Internal; } if(padLen != 3) { dbgLog(("feeFEEDEncryptBlock: cipherblock size screwup (2)\n")); return FR_Internal; } #endif // FEED_DEBUG /* * pad to multiple of (our) cipherblock size. */ while(padLen) { *cipherText++ = 0; ctextLen++; padLen--; } } /* * plaintext to giant xp */ if(finalBlock) { unsigned char *ptext = (unsigned char*) fmalloc(finst->plainBlockSize); bzero(ptext, finst->plainBlockSize); if(plainTextLen) { /* * skip for empty block with resid length 0 */ bcopy(plainText, ptext, plainTextLen); } if(plainTextLen < finst->plainBlockSize) { if(plainTextLen == 0) { /* * Special case - resid block with no actual plaintext. * Can't actually write zero here; it screws up * deserializing the giant during decrypt */ ptext[finst->plainBlockSize - 1] = RESID_ZERO; bprintf(("=== FEED encrypt: RESID_ZERO\n")); } else { ptext[finst->plainBlockSize - 1] = plainTextLen; bprintf(("=== FEED encrypt: resid len 0x%x\n", plainTextLen)); } } /* * else handle evenly aligned case (i.e., finalBlock true * and (plainTextLen == plainBlockSize)) below... */ deserializeGiant(ptext, finst->xp, finst->plainBlockSize); ffree(ptext); } else { deserializeGiant(plainText, finst->xp, plainTextLen); } /* * encrypt xp * xm = xp + clue(+/-) * determine parity needed to restore xp * parity = ((xm + clue(+/-) == xp) ? 1 : -1 * and adjust clue * clue[n+1] = r * clue[n] + (s * P1) */ whichCurve = which_curve(finst->xp, finst->cp); if(whichCurve == CURVE_PLUS) { thisClue = finst->cluePlus; thisS = finst->sPlus; clueByte = CLUE_PLUS; } else { thisClue = finst->clueMinus; thisS = finst->sMinus; clueByte = CLUE_MINUS; } // calculate xm elliptic_add(thisClue, finst->xp, finst->xm, finst->cp, SIGN_PLUS); // save xm + clue in tmp1 elliptic_add(finst->xm, thisClue, finst->tmp1, finst->cp, SIGN_PLUS); // Adjust clue elliptic_simple(thisClue, finst->r, finst->cp); gtog(thisClue, finst->tmp2); elliptic_add(finst->tmp2, thisS, thisClue, finst->cp, SIGN_PLUS); /* * Calculate parity */ if(gcompg(finst->tmp1, finst->xp) == 0) { clueByte |= PARITY_PLUS; } /* * Ciphertext = (xm, clueByte) */ serializeGiant(finst->xm, cipherText, finst->cp->minBytes); cipherText += finst->cp->minBytes; ctextLen += finst->cp->minBytes; *cipherText++ = clueByte; ctextLen++; #if FEED_DEBUG printf("encrypt clue %d\n", clueByte); printf(" xp : "); printGiant(finst->xp); printf(" xm : "); printGiant(finst->xm); printf(" cluePlus :"); printGiant(finst->cluePlus); printf(" clueMinus :"); printGiant(finst->clueMinus); #endif // FEED_DEBUG if(finalBlock && (plainTextLen == finst->plainBlockSize)) { /* * Special case: finalBlock true, plainTextLen == blockSize. * In this case we generate one more block of ciphertext, * with a resid length of zero. */ unsigned moreCipher; // additional cipherLen frtn = feeFEEDEncryptBlock(feed, NULL, // plainText not used 0, // resid cipherText, // append... &moreCipher, 1); if(frtn == FR_Success) { ctextLen += moreCipher; } } bprintf(("=== FEED encryptBlock ptextLen 0x%x ctextLen 0x%x\n", plainTextLen, ctextLen)); *cipherTextLen = ctextLen; return frtn; }
feeReturn feeECDSAVerify(const unsigned char *sigData, size_t sigDataLen, const unsigned char *data, unsigned dataLen, feePubKey pubKey, feeSigFormat format) { /* giant integers per IEEE P1363 notation */ giant h; // s^(-1) giant h1; // f h giant h2; // c times h giant littleC; // newGiant from ECDSA_decode giant littleD; // ditto giant c; // borrowed, full size giant d; // ditto giant cPrime = NULL; // i mod r pointProj h1G = NULL; // h1 'o' G pointProj h2W = NULL; // h2 'o' W key W; // i.e., their public key unsigned version; feeReturn frtn; curveParams *cp = feePubKeyCurveParams(pubKey); unsigned groupBytesLen = ((feePubKeyBitsize(pubKey)+7) / 8); int result; if(cp == NULL) { return FR_BadPubKey; } /* * First decode the byteRep string. */ frtn = ECDSA_decode( format, groupBytesLen, sigData, sigDataLen, &littleC, &littleD, &version); if(frtn) { return frtn; } /* * littleC and littleD have capacity = abs(sign), probably * not big enough.... */ c = borrowGiant(cp->maxDigits); d = borrowGiant(cp->maxDigits); gtog(littleC, c); gtog(littleD, d); freeGiant(littleC); freeGiant(littleD); sigDbg(("ECDSA verify:\n")); /* * Verify that c and d are within [1,group_order-1] */ if((gcompg(cp->cOrderPlus, c) != 1) || (gcompg(cp->cOrderPlus, d) != 1) || isZero(c) || isZero(d)) { returnGiant(c); returnGiant(d); return FR_InvalidSignature; } /* * W = signer's public key */ W = feePubKeyPlusCurve(pubKey); /* * 1) Compute h = d^(-1) (mod x1OrderPlus); */ SIGPROF_START; h = borrowGiant(cp->maxDigits); gtog(d, h); binvg_x1OrderPlus(cp, h); SIGPROF_END(vfyStep1); /* * 2) h1 = digest as giant (skips assigning to 'f' in P1363) */ if(dataLen > (cp->maxDigits * GIANT_BYTES_PER_DIGIT)) { h1 = borrowGiant(BYTES_TO_GIANT_DIGITS(dataLen)); } else { h1 = borrowGiant(cp->maxDigits); } deserializeGiant(data, h1, dataLen); /* * Certicom SEC1 states that if the digest is larger than the modulus, * use the left q bits of the digest. */ unsigned hashBits = dataLen * 8; if(hashBits > cp->q) { gshiftright(hashBits - cp->q, h1); } sigLogGiant(" Wx : ", W->x); sigLogGiant(" f : ", h1); sigLogGiant(" c : ", c); sigLogGiant(" d : ", d); sigLogGiant(" s^(-1) : ", h); /* * 3) Compute h1 = f * h mod x1OrderPlus; */ SIGPROF_START; mulg(h, h1); // h1 := f * h x1OrderPlusMod(h1, cp); SIGPROF_END(vfyStep3); /* * 4) Compute h2 = c * h (mod x1OrderPlus); */ SIGPROF_START; h2 = borrowGiant(cp->maxDigits); gtog(c, h2); mulg(h, h2); // h2 := c * h x1OrderPlusMod(h2, cp); SIGPROF_END(vfyStep4); /* * 5) Compute h2W = h2 'o' W (W = theirPub) */ CKASSERT((W->y != NULL) && !isZero(W->y)); h2W = newPointProj(cp->maxDigits); gtog(W->x, h2W->x); gtog(W->y, h2W->y); int_to_giant(1, h2W->z); ellMulProjSimple(h2W, h2, cp); /* * 6) Compute h1G = h1 'o' G (G = {x1Plus, y1Plus, 1} ) */ CKASSERT((cp->y1Plus != NULL) && !isZero(cp->y1Plus)); h1G = newPointProj(cp->maxDigits); gtog(cp->x1Plus, h1G->x); gtog(cp->y1Plus, h1G->y); int_to_giant(1, h1G->z); ellMulProjSimple(h1G, h1, cp); /* * 7) h1G := (h1 'o' G) + (h2 'o' W) */ ellAddProj(h1G, h2W, cp); /* * 8) If elliptic sum is point at infinity, signature is bad; stop. */ if(isZero(h1G->z)) { dbgLog(("feeECDSAVerify: h1 * G = point at infinity\n")); result = 1; goto vfyDone; } normalizeProj(h1G, cp); /* * 9) cPrime = x coordinate of elliptic sum, mod x1OrderPlus */ cPrime = borrowGiant(cp->maxDigits); gtog(h1G->x, cPrime); x1OrderPlusMod(cPrime, cp); /* * 10) Good sig iff cPrime == c */ result = gcompg(c, cPrime); vfyDone: if(result) { frtn = FR_InvalidSignature; #if LOG_BAD_SIG printf("***yup, bad sig***\n"); #endif // LOG_BAD_SIG } else { frtn = FR_Success; } returnGiant(c); returnGiant(d); returnGiant(h); returnGiant(h1); returnGiant(h2); if(h1G != NULL) { freePointProj(h1G); } if(h2W != NULL) { freePointProj(h2W); } if(cPrime != NULL) { returnGiant(cPrime); } return frtn; }
feeReturn feeECDSASign( feePubKey pubKey, feeSigFormat format, // Signature format DER 9.62 / RAW const unsigned char *data, // data to be signed unsigned dataLen, // in bytes feeRandFcn randFcn, // optional void *randRef, // optional unsigned char **sigData, // malloc'd and RETURNED unsigned *sigDataLen) // RETURNED { curveParams *cp; /* giant integers per IEEE P1363 notation */ giant c; // both 1363 'c' and 'i' // i.e., x-coord of u's pub key giant d; giant u; // random private key giant s; // private key as giant giant f; // data (message) as giant feeReturn frtn = FR_Success; feeRand frand; unsigned char *randBytes; unsigned randBytesLen; unsigned groupBytesLen; giant privGiant; #if ECDSA_SIGN_USE_PROJ pointProjStruct pt; // pt->x = c giant pty; // pt->y giant ptz; // pt->z #endif // ECDSA_SIGN_USE_PROJ if(pubKey == NULL) { return FR_BadPubKey; } cp = feePubKeyCurveParams(pubKey); if(cp == NULL) { return FR_BadPubKey; } if(cp->curveType != FCT_Weierstrass) { return FR_IllegalCurve; } CKASSERT(!isZero(cp->x1OrderPlus)); /* * Private key and message to be signed as giants */ privGiant = feePubKeyPrivData(pubKey); if(privGiant == NULL) { dbgLog(("Attempt to Sign without private data\n")); return FR_IllegalArg; } s = borrowGiant(cp->maxDigits); gtog(privGiant, s); if(dataLen > (cp->maxDigits * GIANT_BYTES_PER_DIGIT)) { f = borrowGiant(BYTES_TO_GIANT_DIGITS(dataLen)); } else { f = borrowGiant(cp->maxDigits); } deserializeGiant(data, f, dataLen); /* * Certicom SEC1 states that if the digest is larger than the modulus, * use the left q bits of the digest. */ unsigned hashBits = dataLen * 8; if(hashBits > cp->q) { gshiftright(hashBits - cp->q, f); } sigDbg(("ECDSA sign:\n")); sigLogGiant(" s : ", s); sigLogGiant(" f : ", f); c = borrowGiant(cp->maxDigits); d = borrowGiant(cp->maxDigits); u = borrowGiant(cp->maxDigits); if(randFcn == NULL) { frand = feeRandAlloc(); } else { frand = NULL; } /* * Random size is just larger than base prime */ groupBytesLen = ((feePubKeyBitsize(pubKey)+7) / 8); randBytesLen = groupBytesLen+8; // +8bytes (64bits) to reduce the biais when with reduction mod prime. Per FIPS186-4 - "Using Extra Random Bits" randBytes = (unsigned char*) fmalloc(randBytesLen); #if ECDSA_SIGN_USE_PROJ /* quick temp pointProj */ pty = borrowGiant(cp->maxDigits); ptz = borrowGiant(cp->maxDigits); pt.x = c; pt.y = pty; pt.z = ptz; #endif // ECDSA_SIGN_USE_PROJ while(1) { /* Repeat this loop until we have a non-zero c and d */ /* * 1) Obtain random u in [2, x1OrderPlus-2] */ SIGPROF_START; if(randFcn) { randFcn(randRef, randBytes, randBytesLen); } else { feeRandBytes(frand, randBytes, randBytesLen); } deserializeGiant(randBytes, u, randBytesLen); sigLogGiant(" raw u : ", u); sigLogGiant(" order : ", cp->x1OrderPlus); x1OrderPlusJustify(u, cp); SIGPROF_END(signStep1); sigLogGiant(" in range u : ", u); /* * note 'o' indicates elliptic multiply, * is integer mult. * * 2) Compute x coordinate, call it c, of u 'o' G * 3) Reduce: c := c mod x1OrderPlus; * 4) If c == 0, goto (1); */ SIGPROF_START; gtog(cp->x1Plus, c); #if ECDSA_SIGN_USE_PROJ /* projective coordinates */ gtog(cp->y1Plus, pty); int_to_giant(1, ptz); ellMulProjSimple(&pt, u, cp); #else /* ECDSA_SIGN_USE_PROJ */ /* the FEE way */ elliptic_simple(c, u, cp); #endif /* ECDSA_SIGN_USE_PROJ */ SIGPROF_END(signStep2); SIGPROF_START; x1OrderPlusMod(c, cp); SIGPROF_END(signStep34); if(isZero(c)) { dbgLog(("feeECDSASign: zero modulo (1)\n")); continue; } /* * 5) Compute u^(-1) mod x1OrderPlus; */ SIGPROF_START; gtog(u, d); binvg_x1OrderPlus(cp, d); SIGPROF_END(signStep5); sigLogGiant(" u^(-1) : ", d); /* * 6) Compute signature d as: * d = [u^(-1) (f + s*c)] (mod x1OrderPlus) */ SIGPROF_START; mulg(c, s); // s *= c x1OrderPlusMod(s, cp); addg(f, s); // s := f + (s * c) x1OrderPlusMod(s, cp); mulg(s, d); // d := u^(-1) (f + (s * c)) x1OrderPlusMod(d, cp); SIGPROF_END(signStep67); /* * 7) If d = 0, goto (1); */ if(isZero(d)) { dbgLog(("feeECDSASign: zero modulo (2)\n")); continue; } sigLogGiant(" c : ", c); sigLogGiant(" d : ", d); break; // normal successful exit } /* * 8) signature is now the integer pair (c, d). */ /* * Cook up raw data representing the signature. */ SIGPROF_START; ECDSA_encode(format,groupBytesLen, c, d, sigData, sigDataLen); SIGPROF_END(signStep8); if(frand != NULL) { feeRandFree(frand); } ffree(randBytes); returnGiant(u); returnGiant(d); returnGiant(c); returnGiant(f); returnGiant(s); #if ECDSA_SIGN_USE_PROJ returnGiant(pty); returnGiant(ptz); #endif /* ECDSA_SIGN_USE_PROJ */ return frtn; }