/* 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; }
int init(void) { static char fn[]="init()"; errno = 0; if( (atexit(&doProperClose)) != 0){ snprintf(mainDbgBuffer,sizeof(mainDbgBuffer),"atexit reg failed. err:%d %s",errno,strerror(errno)); dbgLog(FATAL,fn,__LINE__,mainDbgBuffer); return -1; } if((installSignalHdlr()) < 0){ dbgLog(FATAL,fn,__LINE__,"Signal Hdlr Install Failed."); return -1; } if((i2cFd=openI2CBus(I2C_CHA_2,devAddr)) <= 0){ dbgLog(FATAL,fn,__LINE__," I2C Init Failed."); return -1; } if((mcUartFd=openSerPort(BB_MC_UART_NUM)) <= 0){ dbgLog(FATAL,fn,__LINE__,"Serial Port Init Failed"); return -1; } if( (initSock(QC_LISTN_PORT)) < 0){ dbgLog(FATAL,fn,__LINE__,"Socket Init Failed"); return -1; } return 0; }
const unsigned int openI2CBus(const char *devName,const int devAddr) { static char fn[]="openI2CBus()"; static int fd= 0; errno=0; fd =-1; if((fd = open(devName,O_RDWR)) <= 0){ snprintf(i2cDbgBuffer,sizeof(i2cDbgBuffer),"I2CDev : %s Open Failed",devName); dbgLog(FATAL,fn,__LINE__,i2cDbgBuffer); return -1; } else{ snprintf(i2cDbgBuffer,sizeof(i2cDbgBuffer),"I2CDev : %s Open Success",devName); dbgLog(INFORM,fn,__LINE__,"Opening I2C-[ OK ] "); } errno = 0; if((ioctl(fd,I2C_SLAVE,devAddr)) < 0) { snprintf(i2cDbgBuffer,sizeof(i2cDbgBuffer),"I2CDev;%s Dev:%d Access Failed",devName,devAddr); dbgLog(FATAL,fn,__LINE__,i2cDbgBuffer); return -1; } else{ snprintf(i2cDbgBuffer,sizeof(i2cDbgBuffer),"I2CDev:%s Dev:%d Access Success",devName,devAddr); dbgLog(INFORM,fn,__LINE__,i2cDbgBuffer); } return fd; }
int main(int argc,char *argv) { static char fnName[]="main():"; errno=0; if(argc == 2) { msgQType = atoi(argv[1]); } else msgQType = 0; keyValue = ftok(FILE_PATH,PROJ_ID); if(keyValue <= 0) { snprintf(dbgLogStr,sizeof(dbgLogStr), "%s:%s:%d: ftok failed. Err:%d", __FILE__,fnName,__LINE__,errno); dbgLog(INFORM,dbgLogStr); return 0; } #if 1 errno=0; msgQId = msgget(keyValue, IPC_CREAT|0644); if(msgQId < 0) { snprintf(dbgLogStr, sizeof(dbgLogStr), "%s:%s:%d msgget error:%d", __FILE__,fnName,__LINE__,errno); dbgLog(INFORM,dbgLogStr); return 0; } snprintf(dbgLogStr,sizeof(dbgLogStr),"%s: MSG Q ID:%d",fnName,msgQId); dbgLog(INFORM,dbgLogStr); #endif errno =0; int ret =0; if((ret = msgrcv(msgQId,(char *)buffer,sizeof(buffer),msgQType,IPC_NOWAIT)) < 0) // if((msgrcv(msgQId,(char *)&mqstructVar,sizeof(mqstructVar),2,IPC_NOWAIT)) < 0) { snprintf(dbgLogStr,sizeof(dbgLogStr),"%s:%s:%d msgrecv error:%d. %s",__FILE__,fnName,__LINE__,errno,strerror(errno)); dbgLog(INFORM,dbgLogStr); } else { // snprintf(dbgLogStr,sizeof(dbgLogStr),"%s Msg Recvd: %s",fnName,mqstructVar.msg); snprintf(dbgLogStr,sizeof(dbgLogStr),"%s Msg Recvd:%d: %s", fnName,ret,&buffer[4]); dbgLog(INFORM,dbgLogStr); } // stopService(0); return 0; }
int writeToI2CBus(const unsigned int fd,const unsigned char *buffer,const unsigned int len) { static char fn[]="readFromI2CBus()"; int ret= 0; errno = 0; if((ret = write(fd,buffer,len)) <= 0){ sprintf(i2cDbgBuffer,"write failed. Err:%d:%s",errno,strerror(errno)); dbgLog(REPORT,fn,__LINE__,i2cDbgBuffer); } else{ sprintf(i2cDbgBuffer,"Write Success. wrote:%d bytes",ret); dbgLog(REPORT,fn,__LINE__,i2cDbgBuffer); } return ret; }
int stopService(char flag) { static char fnName[]="stopService():"; errno =0; if( (msgctl(msgQId,IPC_RMID,NULL)) < 0) { sprintf(dbgLogStr, "%s:%s:%d: Err while removing MSG-Q. Err:%d", __FILE__,fnName,__LINE__,errno); dbgLog(INFORM,dbgLogStr); return -1; } snprintf(dbgLogStr,sizeof(dbgLogStr),"%s: MSG Q remove-SUCCESS",fnName); dbgLog(INFORM,dbgLogStr); return 0; }
/* * Obtain Pm after feeSigNewWithKey() or feeSigParse() */ unsigned char *feeSigPm(feeSig sig, unsigned *PmLen) { sigInst *sinst = (sigInst*) sig; unsigned char *Pm; if(sinst->PmX == NULL) { dbgLog(("feeSigPm: no PmX!\n")); return NULL; } else { Pm = mem_from_giant(sinst->PmX, PmLen); #if SIG_DEBUG if(sigDebug) { int i; printf("Pm : "); printGiant(sinst->PmX); printf("PmData: "); for(i=0; i<*PmLen; i++) { printf("%x:", Pm[i]); } printf("\n"); } #endif // SIG_DEBUG } return Pm; }
/* * Generate digital signature, ECDSA style. */ feeReturn feePubKeyCreateECDSASignature(feePubKey pubKey, const unsigned char *data, unsigned dataLen, unsigned char **signature, /* fmalloc'd and RETURNED */ unsigned *signatureLen) /* RETURNED */ { pubKeyInst *pkinst = (pubKeyInst *) pubKey; sha1Obj sha1; feeReturn frtn; if(pkinst->privGiant == NULL) { dbgLog(("feePubKeyCreateECDSASignature: Attempt to Sign " "without private data\n")); return FR_BadPubKey; } sha1 = sha1Alloc(); sha1AddData(sha1, data, dataLen); frtn = feeECDSASign(pubKey, sha1Digest(sha1), sha1DigestLen(), NULL, // randFcn NULL, signature, signatureLen); sha1Free(sha1); return frtn; }
/* * Init feePubKey from curve parameters matching existing oldKey. */ feeReturn feePubKeyInitFromKey(feePubKey pubKey, const unsigned char *privData, unsigned privDataLen, feePubKey oldKey, char hashPrivData) { pubKeyInst *pkinst = (pubKeyInst *) pubKey; pubKeyInst *oldInst = (pubKeyInst *) oldKey; feeReturn frtn; if(oldKey == NULL) { dbgLog(("NULL existing key\n")); return FR_BadPubKey; } pkinst->cp = curveParamsCopy(oldInst->cp); if(pkinst->cp->x1Minus != NULL) { pkinst->minus = new_public(pkinst->cp, CURVE_MINUS); if(pkinst->minus == NULL) { goto abort; } } /* else this curve only usable for ECDSA */ pkinst->plus = new_public(pkinst->cp, CURVE_PLUS); if(pkinst->plus == NULL) { goto abort; } frtn = feeGenPrivate(pkinst, privData, privDataLen, hashPrivData); if(frtn) { return frtn; } set_priv_key_giant(pkinst->plus, pkinst->privGiant); if(pkinst->cp->x1Minus != NULL) { set_priv_key_giant(pkinst->minus, pkinst->privGiant); } return FR_Success; abort: dbgLog(("Bad Existing Public Key\n")); return FR_BadPubKey; }
/* * New optimzation of curveOrderJustify using known reciprocal, 11 June 1997. * g is set to be within [2, curveOrder-2]. */ static void curveOrderJustifyWithRecip(giant g, giant curveOrder, giant recip) { giant tmp; CKASSERT(!isZero(curveOrder)); modg_via_recip(curveOrder, recip, g); // g now in [0, curveOrder-1] if(isZero(g)) { /* * First degenerate case - (g == 0) : set g := 2 */ dbgLog(("curveOrderJustify: case 1\n")); int_to_giant(2, g); return; } if(isone(g)) { /* * Second case - (g == 1) : set g := 2 */ dbgLog(("curveOrderJustify: case 2\n")); int_to_giant(2, g); return; } tmp = borrowGiant(g->capacity); gtog(g, tmp); iaddg(1, tmp); if(gcompg(tmp, curveOrder) == 0) { /* * Third degenerate case - (g == (curveOrder-1)) : set g -= 1 */ dbgLog(("curveOrderJustify: case 3\n")); int_to_giant(1, tmp); subg(tmp, g); } returnGiant(tmp); return; }
/* * Generate digital signature, ElGamal style. */ feeReturn feePubKeyCreateSignature(feePubKey pubKey, const unsigned char *data, unsigned dataLen, unsigned char **signature, /* fmalloc'd and RETURNED */ unsigned *signatureLen) /* RETURNED */ { pubKeyInst *pkinst = (pubKeyInst *) pubKey; feeHash hash; feeSig sig; unsigned char *Pm = NULL; unsigned PmLen; feeReturn frtn; if(pkinst->privGiant == NULL) { dbgLog(("feePubKeyCreateSignature: Attempt to Sign without" " private data\n")); return FR_BadPubKey; } hash = feeHashAlloc(); sig = feeSigNewWithKey(pubKey, NULL, NULL); if(sig == NULL) { /* * Shouldn't happen, but... */ feeHashFree(hash); return FR_BadPubKey; } /* * Get Pm to salt hash object */ Pm = feeSigPm(sig, &PmLen); feeHashAddData(hash, Pm, PmLen); /* * Now hash the data proper, then sign the hash */ feeHashAddData(hash, data, dataLen); frtn = feeSigSign(sig, feeHashDigest(hash), feeHashDigestLen(), pubKey); if(frtn == FR_Success) { frtn = feeSigData(sig, signature, signatureLen); } feeHashFree(hash); feeSigFree(sig); ffree(Pm); return frtn; }
feeReturn feePubKeyInitFromPrivDataDepth(feePubKey pubKey, const unsigned char *privData, unsigned privDataLen, feeDepth depth, char hashPrivData) { pubKeyInst *pkinst = (pubKeyInst *) pubKey; feeReturn frtn; #if ENGINE_127_BITS if(depth != FEE_DEPTH_127_1) { dbgLog(("Illegal Depth\n")); return FR_IllegalDepth; } #endif // ENGINE_127_BITS if(depth > FEE_DEPTH_MAX) { dbgLog(("Illegal Depth\n")); return FR_IllegalDepth; } pkinst->cp = curveParamsForDepth(depth); pkinst->plus = new_public(pkinst->cp, CURVE_PLUS); if(pkinst->cp->x1Minus != NULL) { pkinst->minus = new_public(pkinst->cp, CURVE_MINUS); } /* else only usable for ECDSA */ frtn = feeGenPrivate(pkinst, privData, privDataLen, hashPrivData); if(frtn) { return frtn; } set_priv_key_giant(pkinst->plus, pkinst->privGiant); if(pkinst->cp->x1Minus != NULL) { set_priv_key_giant(pkinst->minus, pkinst->privGiant); } return FR_Success; }
void doProperClose(void) { static char fn[]="doProperClose()"; if(i2cFd != 0) close(i2cFd); if(mcUartFd != 0) close(mcUartFd); if(sockWaitFd != 0) close(sockWaitFd); if(eamSockFd != 0) close(eamSockFd); dbgLog(FATAL,fn,__LINE__,"Finished Proper Closing. Exitting.."); return; }
/*** *** Common native blob support ***/ static feeReturn createKeyBlob(pubKeyInst *pkinst, int isPrivate, // 0 : public 1 : private unsigned char **keyBlob, // mallocd and RETURNED unsigned *keyBlobLen) // RETURNED { unsigned char *s; // running ptr into *origS unsigned sLen; int magic; /* common blob elements */ sLen = (4 * sizeof(int)) + // magic, version, minVersion, // spare lengthOfByteRepCurveParams(pkinst->cp); if(isPrivate) { /* private only */ sLen += lengthOfByteRepGiant(pkinst->privGiant); magic = PUBLIC_KEY_BLOB_MAGIC_PRIV; } else { /* public only */ sLen += (lengthOfByteRepKey(pkinst->plus) + lengthOfByteRepKey(pkinst->minus)); magic = PUBLIC_KEY_BLOB_MAGIC_PUB; } *keyBlob = s = (unsigned char*) fmalloc(sLen); s += intToByteRep(magic, s); s += intToByteRep(PUBLIC_KEY_BLOB_VERSION, s); s += intToByteRep(PUBLIC_KEY_BLOB_MINVERSION, s); s += intToByteRep(0, s); // spare s += curveParamsToByteRep(pkinst->cp, s); if(isPrivate) { s += giantToByteRep(pkinst->privGiant, s); } else { /* keyToByteRep writes y for plus curve only */ s += keyToByteRep(pkinst->plus, s); if(pkinst->minus != NULL) { s += keyToByteRep(pkinst->minus, s); } else { /* TBD */ dbgLog(("work needed here for blobs with no minus key\n")); } } *keyBlobLen = sLen; return FR_Success; }
/* * Init feePubKey from a public key string. * * See ByteRep.doc for info on the format of the public key string and blobs; * PLEASE UPDATE THIS DOCUMENT WHEN YOU MAKE CHANGES TO THE STRING FORMAT. */ feeReturn feePubKeyInitFromKeyString(feePubKey pubKey, const char *keyStr, unsigned keyStrLen) { unsigned char *blob = NULL; unsigned blobLen; feeReturn frtn; blob = dec64((unsigned char *)keyStr, keyStrLen, &blobLen); if(blob == NULL) { dbgLog(("Bad Public Key String (not enc64)\n")); return FR_BadPubKeyString; } frtn = feePubKeyInitFromKeyBlob(pubKey, blob, blobLen); ffree(blob); return frtn; }
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; }
/* * FEE_SIG_USING_PROJ true : this is the "no Weierstrass" case * feeSigVerifyNoProj false : this is redefined to feeSigVerify */ feeReturn feeSigVerifyNoProj(feeSig sig, const unsigned char *data, unsigned dataLen, feePubKey pubKey) { giant Q = NULL; giant messageGiant = NULL; giant scratch = NULL; sigInst *sinst = (sigInst*) sig; feeReturn frtn; curveParams *cp; key origKey; // may be plus or minus key if(sinst->PmX == NULL) { dbgLog(("sigVerify without parse!\n")); frtn = FR_IllegalArg; goto out; } cp = feePubKeyCurveParams(pubKey); Q = newGiant(cp->maxDigits); /* * pick a key (+/-) * Q := P1 */ if(SIG_CURVE == CURVE_PLUS) { origKey = feePubKeyPlusCurve(pubKey); gtog(cp->x1Plus, Q); } else { origKey = feePubKeyMinusCurve(pubKey); gtog(cp->x1Minus, Q); } messageGiant = giant_with_data(data, dataLen); // M(ciphertext) /* Q := u 'o' P1 */ elliptic_simple(Q, sinst->u, cp); /* scratch := theirPub */ scratch = newGiant(cp->maxDigits); gtog(origKey->x, scratch); #if SIG_DEBUG if(sigDebug) { printf("verify origKey:\n"); printKey(origKey); printf("messageGiant: "); printGiant(messageGiant); printf("curveParams:\n"); printCurveParams(cp); } #endif // SIG_DEBUG /* scratch := M 'o' theirPub */ elliptic_simple(scratch, messageGiant, cp); #if SIG_DEBUG if(sigDebug) { printf("signature_compare, with\n"); printf("p0 = Q:\n"); printGiant(Q); printf("p1 = Pm:\n"); printGiant(sinst->PmX); printf("p2 = scratch = R:\n"); printGiant(scratch); } #endif // SIG_DEBUG if(signature_compare(Q, sinst->PmX, scratch, cp)) { frtn = FR_InvalidSignature; #if LOG_BAD_SIG printf("***yup, bad sig***\n"); #endif // LOG_BAD_SIG } else { frtn = FR_Success; } out: if(messageGiant != NULL) { freeGiant(messageGiant); } if(Q != NULL) { freeGiant(Q); } if(scratch != NULL) { freeGiant(scratch); } return frtn; }
/* * cons up: * cluePlus(0) * clueMinus(0) * sPlus * sMinus * r * Assumes: * cluePlus = clueMinus = ourPriv * theirPub * initialRS * initialRSSize * cp * * Called at feeFEEDNewWithPubKey while encrypting, or upon decrypting * first block of data. */ static feeReturn initFromRS(feedInst *finst) { giant s; unsigned rSize = finst->initialRSSize / 2; #if FEED_DEBUG if((finst->initialRS == NULL) || (finst->cp == NULL) || (finst->cluePlus == NULL) || (finst->clueMinus == NULL) || (finst->initialRSSize == 0)) { dbgLog(("initFromRS: resource shortage\n")); return FR_Internal; } #endif // FEED_DEBUG finst->r = giant_with_data(finst->initialRS, rSize); s = giant_with_data(finst->initialRS+rSize, rSize); #if FEED_DEBUG if(isZero(finst->r)) { printf("initFromRS: r = 0! initialRSSize = %d; encr = %s\n", finst->initialRSSize, (finst->rsCtext == NULL) ? "TRUE" : "FALSE"); } if(isZero(s)) { printf("initFromRS: s = 0! initialRSSize = %d; encr = %s\n", finst->initialRSSize, (finst->rsCtext == NULL) ? "TRUE" : "FALSE"); } #endif // FEE_DEBUG /* * Justify r and s to be in [2, minimumX1Order]. */ lesserX1OrderJustify(finst->r, finst->cp); lesserX1OrderJustify(s, finst->cp); /* * sPlus = s * x1Plus * sMinus = s * x1Minus */ finst->sPlus = newGiant(finst->cp->maxDigits); finst->sMinus = newGiant(finst->cp->maxDigits); gtog(finst->cp->x1Plus, finst->sPlus); elliptic_simple(finst->sPlus, s, finst->cp); gtog(finst->cp->x1Minus, finst->sMinus); elliptic_simple(finst->sMinus, s, finst->cp); /* * And finally, the initial clues. They are currently set to * ourPriv * theirPub. */ #if FEED_DEBUG printf("cluePlus : "); printGiant(finst->cluePlus); printf("clueMinus: "); printGiant(finst->clueMinus); #endif // FEED_EEBUG elliptic_simple(finst->cluePlus, finst->r, finst->cp); elliptic_simple(finst->clueMinus, finst->r, finst->cp); #if FEED_DEBUG printf("r : "); printGiant(finst->r); printf("s : "); printGiant(s); printf("sPlus : "); printGiant(finst->sPlus); printf("sMinus : "); printGiant(finst->sMinus); printf("cluePlus : "); printGiant(finst->cluePlus); printf("clueMinus: "); printGiant(finst->clueMinus); #endif // FEED_DEBUG freeGiant(s); return FR_Success; }
/* * Alloc and init a feeFEED object associated with specified public and * private keys. */ feeFEED feeFEEDNewWithPubKey(feePubKey myPrivKey, feePubKey theirPubKey, int forEncrypt, // 0 ==> decrypt 1 ==> encrypt feeRandFcn randFcn, // optional void *randRef) { feedInst *finst; giant privGiant; key k; unsigned expPlainSize; unsigned expCipherSize; unsigned expBlocks; if(!curveParamsEquivalent(feePubKeyCurveParams(theirPubKey), feePubKeyCurveParams(myPrivKey))) { dbgLog(("feeFEEDNewWithPubKey: Incompatible Keys\n")); return NULL; } finst = (feedInst*) fmalloc(sizeof(feedInst)); bzero(finst, sizeof(feedInst)); finst->forEncrypt = forEncrypt; finst->cp = curveParamsCopy(feePubKeyCurveParams(theirPubKey)); finst->rsBlockCount = 0; finst->xp = newGiant(finst->cp->maxDigits); finst->xm = newGiant(finst->cp->maxDigits); finst->tmp1 = newGiant(finst->cp->maxDigits); if(forEncrypt) { finst->tmp2 = newGiant(finst->cp->maxDigits); } /* * cluePlus = ourPriv * theirPub+ * clueMinus = ourPriv * theirPub- */ finst->cluePlus = newGiant(finst->cp->maxDigits); finst->clueMinus = newGiant(finst->cp->maxDigits); privGiant = feePubKeyPrivData(myPrivKey); if(privGiant == NULL) { dbgLog(("feeFEEDNewWithPubKey: no private key\n")); goto abort; } k = feePubKeyPlusCurve(theirPubKey); gtog(k->x, finst->cluePlus); // cluePlus = theirPub+ elliptic_simple(finst->cluePlus, privGiant, finst->cp); k = feePubKeyMinusCurve(theirPubKey); gtog(k->x, finst->clueMinus); // theirPub- elliptic_simple(finst->clueMinus, privGiant, finst->cp); /* * Set up block sizes. */ if(finst->cp->primeType == FPT_General) { unsigned blen = bitlen(finst->cp->basePrime); finst->plainBlockSize = blen / 8; if((blen & 0x7) == 0) { /* * round down some more... */ finst->plainBlockSize--; } } else { finst->plainBlockSize = finst->cp->q / 8; if(((finst->cp->q & 0x7) == 0) && (finst->cp->k > 0)) { /* * Special case, with q mod 8 == 0. Here we have to * trim back the plainBlockSize by one byte. */ finst->plainBlockSize--; } } finst->cipherBlockSize = finst->cp->minBytes + 1; /* * the size of initialRS is subject to tweaking - if we make it * not a multiple of plainBlockSize, we save one FEEDExp cipherBlock * in our ciphertext. */ finst->initialRSSize = finst->plainBlockSize * 2; if(finst->initialRSSize > RS_MIN_SIZE) { unsigned minPlainBlocks; unsigned maxSize; /* * How many plainblocks to hold RS_MIN_SIZE? */ minPlainBlocks = (RS_MIN_SIZE + finst->plainBlockSize - 1) / finst->plainBlockSize; /* * Max size = that many plainblocks, less 2 bytes (to avoid * extra residue block). */ maxSize = minPlainBlocks * finst->plainBlockSize - 2; /* * But don't bother with more than 2 plainblocks worth */ if(finst->initialRSSize > maxSize) { finst->initialRSSize = maxSize; } } /* else leave it alone, that's small enough */ if(forEncrypt) { feeRand frand = NULL; /* * Encrypt-capable FEEDExp object */ finst->feedExp = feeFEEDExpNewWithPubKey(theirPubKey, randFcn, randRef); if(finst->feedExp == NULL) { goto abort; } /* * Generate initial r and s data. */ finst->initialRS = (unsigned char*) fmalloc(finst->initialRSSize); if(randFcn != NULL) { randFcn(randRef, finst->initialRS, finst->initialRSSize); } else { frand = feeRandAlloc(); feeRandBytes(frand, finst->initialRS, finst->initialRSSize); feeRandFree(frand); } if(initFromRS(finst)) { goto abort; } } else { /* * Decrypt-capable FEEDExp object */ finst->feedExp = feeFEEDExpNewWithPubKey(myPrivKey, randFcn, randRef); if(finst->feedExp == NULL) { goto abort; } } /* * Figure out how many of our cipherblocks it takes to hold * a FEEDExp-encrypted initialRS. If initialRSSize is an exact * multiple of expPlainSize, we get an additional feedExp * residue block. */ expPlainSize = feeFEEDExpPlainBlockSize(finst->feedExp); expCipherSize = feeFEEDExpCipherBlockSize(finst->feedExp); expBlocks = (finst->initialRSSize + expPlainSize - 1) / expPlainSize; if((finst->initialRSSize % expPlainSize) == 0) { expBlocks++; } /* * Total meaningful bytes of encrypted initialRS */ finst->rsCtextSize = expBlocks * expCipherSize; /* * Number of our cipherblocks it takes to hold rsCtextSize */ finst->rsSizeCipherBlocks = (finst->rsCtextSize + finst->cipherBlockSize - 1) / finst->cipherBlockSize; if(!forEncrypt) { finst->rsCtext = (unsigned char*) fmalloc(finst->rsSizeCipherBlocks * finst->cipherBlockSize); } /* * Sanity check... */ #if FEED_DEBUG { unsigned fexpBlockSize = feeFEEDExpCipherBlockSize(finst->feedExp); /* * FEEDExp has one more giant in ciphertext, plaintext is * same size */ if((finst->cipherBlockSize + finst->cp->minBytes) != fexpBlockSize) { dbgLog(("feeFEEDNewWithPubKey: FEEDExp CBlock Size " "screwup\n")); goto abort; } fexpBlockSize = feeFEEDExpPlainBlockSize(finst->feedExp); if(fexpBlockSize != finst->plainBlockSize) { dbgLog(("feeFEEDNewWithPubKey: FEEDExp PBlock Size " "screwup\n")); goto abort; } } #endif // FEED_DEBUG return finst; abort: feeFEEDFree(finst); return NULL; }
/* * 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; }
/* * Init an empty feePubKey from a native blob (non-DER format). */ static feeReturn feePubKeyInitFromKeyBlob(feePubKey pubKey, unsigned char *keyBlob, unsigned keyBlobLen) { pubKeyInst *pkinst = (pubKeyInst *) pubKey; unsigned char *s; // running pointer unsigned sLen; // bytes remaining in *s int magic; unsigned len; // for length of individual components int minVersion; int version; int isPrivate; s = keyBlob; sLen = keyBlobLen; if(sLen < (4 * sizeof(int))) { // magic, version, minVersion, spare /* * Too short for all the ints we need */ dbgLog(("feePublicKey: key blob (1)\n")); return FR_BadKeyBlob; } magic = byteRepToInt(s); s += sizeof(int); sLen -= sizeof(int); switch(magic) { case PUBLIC_KEY_BLOB_MAGIC_PUB: isPrivate = 0; break; case PUBLIC_KEY_BLOB_MAGIC_PRIV: isPrivate = 1; break; default: dbgLog(("feePublicKey: Bad Public Key Magic Number\n")); return FR_BadKeyBlob; } /* * Switch on this for version-specific cases */ version = byteRepToInt(s); s += sizeof(int); sLen -= sizeof(int); minVersion = byteRepToInt(s); s += sizeof(int); sLen -= sizeof(int); if(minVersion > PUBLIC_KEY_BLOB_VERSION) { /* * old code, newer key blob - can't parse */ dbgLog(("feePublicKey: Incompatible Public Key (1)\n")); return FR_BadKeyBlob; } s += sizeof(int); // skip spare sLen -= sizeof(int); pkinst->cp = byteRepToCurveParams(s, sLen, &len); if(pkinst->cp == NULL) { dbgLog(("feePublicKey: Bad Key Blob(2)\n")); return FR_BadKeyBlob; } s += len; sLen -= len; /* * Private key blob: privGiant. * Public Key blob: plusX, minusX, plusY. */ if(isPrivate) { pkinst->privGiant = byteRepToGiant(s, sLen, &len); if(pkinst->privGiant == NULL) { dbgLog(("feePublicKey: Bad Key Blob(3)\n")); return FR_BadKeyBlob; } s += len; sLen -= len; } else { /* this writes x and y */ pkinst->plus = byteRepToKey(s, sLen, CURVE_PLUS, // twist pkinst->cp, &len); if(pkinst->plus == NULL) { dbgLog(("feePublicKey: Bad Key Blob(4)\n")); return FR_BadKeyBlob; } s += len; sLen -= len; /* this only writes x */ pkinst->minus = byteRepToKey(s, sLen, CURVE_MINUS, // twist pkinst->cp, &len); if(pkinst->minus == NULL) { dbgLog(("feePublicKey: Bad Key Blob(5)\n")); return FR_BadKeyBlob; } s += len; sLen -= len; } /* * One more thing: cook up public plusX and minusX for private key * blob case. */ if(isPrivate) { pkinst->plus = new_public(pkinst->cp, CURVE_PLUS); pkinst->minus = new_public(pkinst->cp, CURVE_MINUS); set_priv_key_giant(pkinst->plus, pkinst->privGiant); set_priv_key_giant(pkinst->minus, pkinst->privGiant); } return FR_Success; }
feeReturn feeFEEDDecrypt(feeFEED feed, const unsigned char *cipherText, unsigned cipherTextLen, unsigned char **plainText, // malloc'd and RETURNED unsigned *plainTextLen) // RETURNED { const unsigned char *ctext; unsigned ctextLen; // total to go unsigned char *ptext; // per block unsigned ptextLen; // per block unsigned char *ptextResult; // to return unsigned char *ptextPtr; unsigned ptextLenTotal; // running total feeReturn frtn = FR_Success; int finalBlock; unsigned numBlocks; unsigned plainBlockSize = feeFEEDPlainBlockSize(feed); unsigned cipherBlockSize = feeFEEDCipherBlockSize(feed); if(cipherTextLen % cipherBlockSize) { dbgLog(("feeFEEDDecrypt: unaligned cipherText\n")); return FR_BadCipherText; } if(cipherTextLen == 0) { dbgLog(("feeFEEDDecrypt: NULL cipherText\n")); return FR_BadCipherText; } ptext = (unsigned char*) fmalloc(plainBlockSize); ctext = cipherText; ctextLen = cipherTextLen; numBlocks = cipherTextLen / cipherBlockSize; ptextResult = (unsigned char*) fmalloc(plainBlockSize * numBlocks); ptextPtr = ptextResult; ptextLenTotal = 0; while(ctextLen) { if(ctextLen == cipherBlockSize) { finalBlock = 1; } else { finalBlock = 0; } frtn = feeFEEDDecryptBlock(feed, ctext, cipherBlockSize, ptext, &ptextLen, finalBlock); if(frtn) { dbgLog(("feeFEEDDecryptBlock: %s\n", feeReturnString(frtn))); break; } if(ptextLen) { if(ptextLen > plainBlockSize) { dbgLog(("feeFEEDDecrypt: ptext overflow!\n")); frtn = FR_Internal; break; } bcopy(ptext, ptextPtr, ptextLen); ptextPtr += ptextLen; ptextLenTotal += ptextLen; } /* * note ptextLen == 0 is normal termination case for * plainTextLen % plainBlockSize == 0. * Also expected for first 4 blocks of ciphertext; * proceed (we break when ctextLen is exhausted). */ ctext += cipherBlockSize; ctextLen -= cipherBlockSize; } ffree(ptext); if(frtn) { ffree(ptextResult); *plainText = NULL; *plainTextLen = 0; } else { *plainText = ptextResult; *plainTextLen = ptextLenTotal; } 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; }
/* * Convenience routines to encrypt & decrypt multi-block data. */ feeReturn feeFEEDExpEncrypt(feeFEEDExp feed, const unsigned char *plainText, unsigned plainTextLen, unsigned char **cipherText, // malloc'd and RETURNED unsigned *cipherTextLen) // RETURNED { const unsigned char *ptext; // per block unsigned ptextLen; // total to go unsigned thisPtextLen; // per block unsigned char *ctext; // per block unsigned ctextLen; // per block unsigned char *ctextResult; // to return unsigned ctextResultLen; unsigned char *ctextPtr; unsigned ctextLenTotal; // running total feeReturn frtn; int finalBlock; unsigned numBlocks; unsigned plainBlockSize; if(plainTextLen == 0) { dbgLog(("feeFEEDExpDecrypt: NULL plainText\n")); return FR_IllegalArg; } ptext = plainText; ptextLen = plainTextLen; ctext = (unsigned char*) fmalloc(feeFEEDExpCipherBufSize(feed)); plainBlockSize = feeFEEDExpPlainBlockSize(feed); numBlocks = (plainTextLen + plainBlockSize - 1)/plainBlockSize; ctextResultLen = (numBlocks + 1) * feeFEEDExpCipherBlockSize(feed); ctextResult = (unsigned char*) fmalloc(ctextResultLen); ctextPtr = ctextResult; ctextLenTotal = 0; while(1) { if(ptextLen <= plainBlockSize) { finalBlock = 1; thisPtextLen = ptextLen; } else { finalBlock = 0; thisPtextLen = plainBlockSize; } frtn = feeFEEDExpEncryptBlock(feed, ptext, thisPtextLen, ctext, &ctextLen, finalBlock); if(frtn) { dbgLog(("feeFEEDExpEncrypt: encrypt error: %s\n", feeReturnString(frtn))); break; } if(ctextLen == 0) { dbgLog(("feeFEEDExpEncrypt: null ciphertext\n")); frtn = FR_Internal; break; } bcopy(ctext, ctextPtr, ctextLen); ctextLenTotal += ctextLen; if(ctextLenTotal > ctextResultLen) { dbgLog(("feeFEEDExpEncrypt: ciphertext overflow\n")); frtn = FR_Internal; break; } if(finalBlock) { break; } ctextPtr += ctextLen; ptext += thisPtextLen; ptextLen -= thisPtextLen; } ffree(ctext); if(frtn) { ffree(ctextResult); *cipherText = NULL; *cipherTextLen = 0; } else { *cipherText = ctextResult; *cipherTextLen = ctextLenTotal; #if FEE_DEBUG if(feeFEEDExpCipherTextSize(feed, plainTextLen) != ctextLenTotal) { printf("feeFEEDExpEncrypt: feeFEEDCipherTextSize " "error!\n"); printf("ptext %d exp ctext %d actual ctext %d\n", plainTextLen, feeFEEDExpCipherTextSize(feed, plainTextLen), ctextLenTotal); } #endif // FEE_DEBUG } return frtn; }
/* * Diffie-Hellman. Public key is specified either as a feePubKey or * a ANSI X9.62 format public key string (0x04 | x | y). In either case * the caller must ensure that the two keys are on the same curve. * Output data is fmalloc'd here; caller must free. Output data is * exactly the size of the curve's modulus in bytes. */ feeReturn feePubKeyECDH( feePubKey privKey, /* one of the following two is non-NULL */ feePubKey pubKey, const unsigned char *pubKeyStr, unsigned pubKeyStrLen, /* output fmallocd and RETURNED here */ unsigned char **output, unsigned *outputLen) { feePubKey theirPub = pubKey; feeReturn frtn = FR_Success; pubKeyInst *privInst = (pubKeyInst *) privKey; if(privInst->privGiant == NULL) { dbgLog(("feePubKeyECDH: privKey not a private key\n")); return FR_IncompatibleKey; } if(theirPub == NULL) { if(pubKeyStr == NULL) { return FR_IllegalArg; } /* Cook up a public key with the same curveParams as the private key */ feeDepth depth; frtn = curveParamsDepth(privInst->cp, &depth); if(frtn) { return frtn; } theirPub = feePubKeyAlloc(); if(theirPub == NULL) { return FR_Memory; } frtn = feePubKeyInitFromECDSAPubBlob(theirPub, pubKeyStr, pubKeyStrLen, depth); if(frtn) { goto errOut; } } pubKeyInst *pubInst = (pubKeyInst *) theirPub; giant outputGiant = make_pad(privInst->privGiant, pubInst->plus); if(outputGiant == NULL) { dbgLog(("feePubKeyECDH: make_pad error\n")); frtn = FR_Internal; } else { *outputLen = (privInst->cp->q + 7) / 8; *output = (unsigned char *)fmalloc(*outputLen); if(*output == NULL) { frtn = FR_Memory; goto errOut; } serializeGiant(outputGiant, *output, *outputLen); freeGiant(outputGiant); } errOut: if((pubKey == NULL) && (theirPub != NULL)) { feePubKeyFree(theirPub); } 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; }
/* * 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; }
/* * Sign specified block of data (most likely a hash result) using * specified feePubKey. */ feeReturn feeSigSign(feeSig sig, const unsigned char *data, // data to be signed unsigned dataLen, // in bytes feePubKey pubKey) { sigInst *sinst = (sigInst*) sig; giant messageGiant = NULL; unsigned maxlen; giant privGiant; unsigned privGiantBytes; feeReturn frtn = FR_Success; unsigned randBytesLen; unsigned uDigits; // alloc'd digits in sinst->u curveParams *cp; if(pubKey == NULL) { return FR_BadPubKey; } cp = feePubKeyCurveParams(pubKey); if(cp == NULL) { return FR_BadPubKey; } privGiant = feePubKeyPrivData(pubKey); if(privGiant == NULL) { dbgLog(("Attempt to Sign without private data\n")); frtn = FR_IllegalArg; goto abort; } privGiantBytes = abs(privGiant->sign) * GIANT_BYTES_PER_DIGIT; /* * Note PmX = m 'o' P1. * Get message/digest as giant. May be significantly different * in size from pubKey's basePrime. */ messageGiant = giant_with_data(data, dataLen); // M(text) randBytesLen = feePubKeyBitsize(pubKey) / 8; maxlen = max(randBytesLen, dataLen); /* leave plenty of room.... */ uDigits = (3 * (privGiantBytes + maxlen)) / GIANT_BYTES_PER_DIGIT; sinst->u = newGiant(uDigits); gtog(privGiant, sinst->u); // u := ourPri mulg(messageGiant, sinst->u); // u *= M(text) addg(sinst->randGiant, sinst->u); // u += m /* * Paranoia: we're using the curveParams from the caller's pubKey; * this cp will have a valid x1OrderPlusRecip if pubKey is the same * as the one passed to feeSigNewWithKey() (since feeSigNewWithKey * called x1OrderPlusJustify()). But the caller could conceivably be * using a different instance of their pubKey, in which case * the key's cp->x1OrderPlusRecip may not be valid. */ calcX1OrderPlusRecip(cp); /* u := u mod x1OrderPlus */ #if SIG_DEBUG if(sigDebug) { printf("sigSign:\n"); printf("u pre-modg : "); printGiant(sinst->u); } #endif modg_via_recip(cp->x1OrderPlus, cp->x1OrderPlusRecip, sinst->u); #if SIG_DEBUG if(sigDebug) { printf("privGiant : "); printGiant(privGiant); printf("u : "); printGiant(sinst->u); printf("messageGiant: "); printGiant(messageGiant); printf("curveParams :\n"); printCurveParams(cp); } #endif // SIG_DEBUG abort: if(messageGiant) { freeGiant(messageGiant); } return frtn; }
feeReturn feeFEEDExpDecrypt(feeFEEDExp feed, const unsigned char *cipherText, unsigned cipherTextLen, unsigned char **plainText, // malloc'd and RETURNED unsigned *plainTextLen) // RETURNED { const unsigned char *ctext; unsigned ctextLen; // total to go unsigned char *ptext; // per block unsigned ptextLen; // per block unsigned char *ptextResult; // to return unsigned char *ptextPtr; unsigned ptextLenTotal; // running total feeReturn frtn = FR_Success; int finalBlock; unsigned numBlocks; unsigned plainBlockSize = feeFEEDExpPlainBlockSize(feed); unsigned cipherBlockSize = feeFEEDExpCipherBlockSize(feed); if(cipherTextLen % cipherBlockSize) { dbgLog(("feeFEEDExpDecrypt: unaligned cipherText\n")); return FR_BadCipherText; } if(cipherTextLen == 0) { dbgLog(("feeFEEDExpDecrypt: NULL cipherText\n")); return FR_BadCipherText; } ptext = (unsigned char*) fmalloc(plainBlockSize); ctext = cipherText; ctextLen = cipherTextLen; numBlocks = cipherTextLen / cipherBlockSize; ptextResult = (unsigned char*) fmalloc(plainBlockSize * numBlocks); ptextPtr = ptextResult; ptextLenTotal = 0; while(ctextLen) { if(ctextLen == cipherBlockSize) { finalBlock = 1; } else { finalBlock = 0; } frtn = feeFEEDExpDecryptBlock(feed, ctext, cipherBlockSize, ptext, &ptextLen, finalBlock); if(frtn) { dbgLog(("feeFEEDExpDecryptBlock: %s\n", feeReturnString(frtn))); break; } if(ptextLen == 0) { /* * Normal termination case for * plainTextLen % plainBlockSize == 0 */ if(!finalBlock) { dbgLog(("feeFEEDExpDecrypt: decrypt sync" " error!\n")); frtn = FR_BadCipherText; } break; } else if(ptextLen > plainBlockSize) { dbgLog(("feeFEEDExpDecrypt: ptext overflow!\n")); frtn = FR_Internal; break; } else { bcopy(ptext, ptextPtr, ptextLen); ptextPtr += ptextLen; ptextLenTotal += ptextLen; } ctext += cipherBlockSize; ctextLen -= cipherBlockSize; } ffree(ptext); if(frtn) { ffree(ptextResult); *plainText = NULL; *plainTextLen = 0; } else { *plainText = ptextResult; *plainTextLen = ptextLenTotal; } return frtn; }
feeReturn feeSigVerify(feeSig sig, const unsigned char *data, unsigned dataLen, feePubKey pubKey) { pointProjStruct Q; giant messageGiant = NULL; pointProjStruct scratch; sigInst *sinst = (sigInst*) sig; feeReturn frtn; curveParams *cp; key origKey; // may be plus or minus key if(sinst->PmX == NULL) { dbgLog(("sigVerify without parse!\n")); return FR_IllegalArg; } cp = feePubKeyCurveParams(pubKey); if(cp->curveType != FCT_Weierstrass) { return feeSigVerifyNoProj(sig, data, dataLen, pubKey); } borrowPointProj(&Q, cp->maxDigits); borrowPointProj(&scratch, cp->maxDigits); /* * Q := P1 */ gtog(cp->x1Plus, Q.x); gtog(cp->y1Plus, Q.y); int_to_giant(1, Q.z); messageGiant = giant_with_data(data, dataLen); // M(ciphertext) /* Q := u 'o' P1 */ ellMulProjSimple(&Q, sinst->u, cp); /* scratch := theirPub */ origKey = feePubKeyPlusCurve(pubKey); gtog(origKey->x, scratch.x); gtog(origKey->y, scratch.y); int_to_giant(1, scratch.z); #if SIG_DEBUG if(sigDebug) { printf("verify origKey:\n"); printKey(origKey); printf("messageGiant: "); printGiant(messageGiant); printf("curveParams:\n"); printCurveParams(cp); } #endif // SIG_DEBUG /* scratch := M 'o' theirPub */ ellMulProjSimple(&scratch, messageGiant, cp); #if SIG_DEBUG if(sigDebug) { printf("signature_compare, with\n"); printf("p0 = Q:\n"); printGiant(Q.x); printf("p1 = Pm:\n"); printGiant(sinst->PmX); printf("p2 = scratch = R:\n"); printGiant(scratch.x); } #endif // SIG_DEBUG if(signature_compare(Q.x, sinst->PmX, scratch.x, cp)) { frtn = FR_InvalidSignature; #if LOG_BAD_SIG printf("***yup, bad sig***\n"); #endif // LOG_BAD_SIG } else { frtn = FR_Success; } freeGiant(messageGiant); returnPointProj(&Q); returnPointProj(&scratch); return frtn; }