feeReturn feeCreateECDSAPrivBlob(feePubKey pubKey, unsigned char **keyBlob, unsigned *keyBlobLen) { pubKeyInst *pkinst = (pubKeyInst *)pubKey; if(pkinst == NULL) { return FR_BadPubKey; } if(pkinst->privGiant == NULL) { return FR_IncompatibleKey; } /* * Return the raw private key bytes padded with zeroes in * the m.s. end to fill exactly one prime-size byte array. */ unsigned giantBytes = (pkinst->cp->q + 7) / 8; unsigned char *blob = fmalloc(giantBytes); if(blob == NULL) { return FR_Memory; } serializeGiant(pkinst->privGiant, blob, giantBytes); *keyBlob = blob; *keyBlobLen = giantBytes; return FR_Success; }
/* * Obtain a malloc'd memory chunk init'd with specified giant's data. * Resulting bytes are portable. Size of malloc'd memory is always zero * mod GIANT_BYTES_PER_DIGIT. * * Calling this function for a giant obtained by giant_with_data() yields * the original data, with extra byte(s) of leading zeros if the original * was not zero mod GIANT_BYTES_PER_DIGIT. */ unsigned char *mem_from_giant(giant g, unsigned *memLen) /* RETURNED size of malloc'd region */ { unsigned char *cp; unsigned numDigits = (g->sign < 0) ? -g->sign : g->sign; *memLen = numDigits * GIANT_BYTES_PER_DIGIT; cp = (unsigned char*) fmalloc(*memLen); serializeGiant(g, cp, *memLen); return cp; }
/* * ANSI X9.62/Certicom key support. * Public key is 04 || x || y * Private key is privData per Certicom SEC1 C.4. */ feeReturn feeCreateECDSAPubBlob(feePubKey pubKey, unsigned char **keyBlob, unsigned *keyBlobLen) { pubKeyInst *pkinst = (pubKeyInst *)pubKey; if(pkinst == NULL) { return FR_BadPubKey; } unsigned giantBytes = (pkinst->cp->q + 7) / 8; unsigned blobSize = 1 + (2 * giantBytes); unsigned char *blob = fmalloc(blobSize); if(blob == NULL) { return FR_Memory; } *blob = 0x04; serializeGiant(pkinst->plus->x, blob+1, giantBytes); serializeGiant(pkinst->plus->y, blob+1+giantBytes, giantBytes); *keyBlob = blob; *keyBlobLen = blobSize; return FR_Success; }
static OSStatus sslGiantToBuffer( SSLContext *ctx, // Currently unused. giant g, SSLBuffer *buffer) { gi_uint8 *chars; gi_uint16 ioLen; gi_uint16 zeroCount; GIReturn giReturn; OSStatus status; ioLen = serializeGiantBytes(g); status = SSLAllocBuffer(buffer, ioLen, ctx); if (status) return status; chars = buffer->data; /* Serialize the giant g into chars. */ giReturn = serializeGiant(g, chars, &ioLen); if(giReturn) { SSLFreeBuffer(buffer, ctx); return giReturnToSSL(giReturn); } /* Trim off leading zeroes (but leave one zero if that's all there is). */ for (zeroCount = 0; zeroCount < (ioLen - 1); ++zeroCount) if (chars[zeroCount]) break; if (zeroCount > 0) { buffer->length = ioLen - zeroCount; memmove(chars, chars + zeroCount, buffer->length); } return status; }
/* * 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; }
/* * 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; }
/* * 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; }