]>
git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_cryptkit/lib/feeFEED.c
1 /* Copyright (c) 1998,2011,2014 Apple Inc. All Rights Reserved.
3 * NOTICE: USE OF THE MATERIALS ACCOMPANYING THIS NOTICE IS SUBJECT
4 * TO THE TERMS OF THE SIGNED "FAST ELLIPTIC ENCRYPTION (FEE) REFERENCE
5 * SOURCE CODE EVALUATION AGREEMENT" BETWEEN APPLE, INC. AND THE
6 * ORIGINAL LICENSEE THAT OBTAINED THESE MATERIALS FROM APPLE,
7 * INC. ANY USE OF THESE MATERIALS NOT PERMITTED BY SUCH AGREEMENT WILL
8 * EXPOSE YOU TO LIABILITY.
9 ***************************************************************************
11 * FeeFEED.c - generic, portable FEED encryption object, expanionless version
16 * Changed to compile with C++.
17 * 20 Jan 1998 at Apple
18 * Mods for primeType == PT_GENERAL case.
19 * 12 Jun 1997 at Apple
20 * Was curveOrderJustify(), is lesserX1OrderJustify()
21 * 31 Mar 1997 at Apple
22 * Fixed initialRS leak
24 * Trimmed plainBlockSize by one byte if q mod 8 = 0
30 * FIXME - a reusable init function would be nice (i.e., free up
31 * session-dependent state and re-init it)...
37 #include "feeFEEDExp.h"
38 #include "feePublicKey.h"
39 #include "feePublicKeyPrivate.h"
42 #include "feeRandom.h"
43 #include "ckutilities.h"
44 #include "feeFunctions.h"
46 #include "curveParams.h"
52 #define BUFFER_DEBUG 0
54 #define bprintf(s) printf s
60 * Minimum combined size of random r and s, in bytes. For small q sizes,
61 * r and s may be even smaller, but we never truncate them to smaller than
63 * This must be kept in sync with constant of same name in FEED.java.
65 #define RS_MIN_SIZE 16
74 * the clues are initially (r * ourPriv * theirPub(+/-)).
80 * sPlus and sMinus are based on the random s generated at encrypt
81 * time. Values are s * x1{Plus,Minus}.
85 giant r
; /* random, generated at encrypt time */
86 unsigned plainBlockSize
; /* plaintext block size */
87 unsigned cipherBlockSize
; /* ciphertext block size */
88 unsigned char *initialRS
; /* initial random R,S as bytes */
89 unsigned initialRSSize
; /* in bytes */
90 feeFEEDExp feedExp
; /* for encr/decr r+s params */
93 * The first few blocks of ciphertext in a stream are the 2:1-FEED
94 * encrypted r and s parameters. While decrypting, we stash incoming
95 * ciphertext in rsCtext until we get enough ciphertext to decrypt
96 * initialRS. RsBlockCount keeps a running count of the
97 * cipherBlocks received. When rsBlockCount == rsSizeCipherBlocks, we
98 * FEEDExp-decrypt rsCtext to get r and s (actually, to get
99 * initialRS; r and s are extraced later in initFromRS()).
101 * During encrypt, if rsBlockCount is zero, the first thing we send as
102 * ciphertext is the FEED-encrypted initialRS.
104 unsigned char *rsCtext
; /* buffer for encrypted initialRS */
105 unsigned rsBlockCount
; /* running total of incoming rs
108 int forEncrypt
; /* added for feeFEED*TextSize() */
111 * These are calculated at init time - for encrypt and
112 * decrypt - as an optimization.
114 unsigned rsCtextSize
; /* number of meaningful bytes in
116 unsigned rsSizeCipherBlocks
; /* # of our cipherblocks holding
120 * temporary variables used for encrypt/decrypt. The values in these
121 * are not needed to be kept from block to block; we just
122 * alloc them once per lifetime of a feeFEED object as an optimization.
124 giant xp
; /* plaintext */
125 giant xm
; /* ciphertext */
126 giant tmp1
; /* scratch */
127 giant tmp2
; /* scratch */
131 * "zero residue" indicator.
133 #define RESID_ZERO 0xff
143 * cluePlus = clueMinus = ourPriv * theirPub
148 * Called at feeFEEDNewWithPubKey while encrypting, or upon decrypting
149 * first block of data.
151 static feeReturn
initFromRS(feedInst
*finst
)
154 unsigned rSize
= finst
->initialRSSize
/ 2;
157 if((finst
->initialRS
== NULL
) ||
158 (finst
->cp
== NULL
) ||
159 (finst
->cluePlus
== NULL
) ||
160 (finst
->clueMinus
== NULL
) ||
161 (finst
->initialRSSize
== 0)) {
162 dbgLog(("initFromRS: resource shortage\n"));
167 finst
->r
= giant_with_data(finst
->initialRS
, rSize
);
168 s
= giant_with_data(finst
->initialRS
+rSize
, rSize
);
171 if(isZero(finst
->r
)) {
172 printf("initFromRS: r = 0! initialRSSize = %d; encr = %s\n",
173 finst
->initialRSSize
,
174 (finst
->rsCtext
== NULL
) ? "TRUE" : "FALSE");
177 printf("initFromRS: s = 0! initialRSSize = %d; encr = %s\n",
178 finst
->initialRSSize
,
179 (finst
->rsCtext
== NULL
) ? "TRUE" : "FALSE");
183 * Justify r and s to be in [2, minimumX1Order].
185 lesserX1OrderJustify(finst
->r
, finst
->cp
);
186 lesserX1OrderJustify(s
, finst
->cp
);
190 * sMinus = s * x1Minus
192 finst
->sPlus
= newGiant(finst
->cp
->maxDigits
);
193 finst
->sMinus
= newGiant(finst
->cp
->maxDigits
);
194 gtog(finst
->cp
->x1Plus
, finst
->sPlus
);
195 elliptic_simple(finst
->sPlus
, s
, finst
->cp
);
196 gtog(finst
->cp
->x1Minus
, finst
->sMinus
);
197 elliptic_simple(finst
->sMinus
, s
, finst
->cp
);
200 * And finally, the initial clues. They are currently set to
201 * ourPriv * theirPub.
204 printf("cluePlus : "); printGiant(finst
->cluePlus
);
205 printf("clueMinus: "); printGiant(finst
->clueMinus
);
208 elliptic_simple(finst
->cluePlus
, finst
->r
, finst
->cp
);
209 elliptic_simple(finst
->clueMinus
, finst
->r
, finst
->cp
);
212 printf("r : "); printGiant(finst
->r
);
213 printf("s : "); printGiant(s
);
214 printf("sPlus : "); printGiant(finst
->sPlus
);
215 printf("sMinus : "); printGiant(finst
->sMinus
);
216 printf("cluePlus : "); printGiant(finst
->cluePlus
);
217 printf("clueMinus: "); printGiant(finst
->clueMinus
);
225 * Alloc and init a feeFEED object associated with specified public and
228 feeFEED
feeFEEDNewWithPubKey(feePubKey myPrivKey
,
229 feePubKey theirPubKey
,
230 int forEncrypt
, // 0 ==> decrypt 1 ==> encrypt
231 feeRandFcn randFcn
, // optional
237 unsigned expPlainSize
;
238 unsigned expCipherSize
;
241 if(!curveParamsEquivalent(feePubKeyCurveParams(theirPubKey
),
242 feePubKeyCurveParams(myPrivKey
))) {
243 dbgLog(("feeFEEDNewWithPubKey: Incompatible Keys\n"));
246 finst
= (feedInst
*) fmalloc(sizeof(feedInst
));
247 bzero(finst
, sizeof(feedInst
));
248 finst
->forEncrypt
= forEncrypt
;
249 finst
->cp
= curveParamsCopy(feePubKeyCurveParams(theirPubKey
));
250 finst
->rsBlockCount
= 0;
251 finst
->xp
= newGiant(finst
->cp
->maxDigits
);
252 finst
->xm
= newGiant(finst
->cp
->maxDigits
);
253 finst
->tmp1
= newGiant(finst
->cp
->maxDigits
);
255 finst
->tmp2
= newGiant(finst
->cp
->maxDigits
);
259 * cluePlus = ourPriv * theirPub+
260 * clueMinus = ourPriv * theirPub-
262 finst
->cluePlus
= newGiant(finst
->cp
->maxDigits
);
263 finst
->clueMinus
= newGiant(finst
->cp
->maxDigits
);
264 privGiant
= feePubKeyPrivData(myPrivKey
);
265 if(privGiant
== NULL
) {
266 dbgLog(("feeFEEDNewWithPubKey: no private key\n"));
269 k
= feePubKeyPlusCurve(theirPubKey
);
270 gtog(k
->x
, finst
->cluePlus
); // cluePlus = theirPub+
271 elliptic_simple(finst
->cluePlus
, privGiant
, finst
->cp
);
272 k
= feePubKeyMinusCurve(theirPubKey
);
273 gtog(k
->x
, finst
->clueMinus
); // theirPub-
274 elliptic_simple(finst
->clueMinus
, privGiant
, finst
->cp
);
277 * Set up block sizes.
279 if(finst
->cp
->primeType
== FPT_General
) {
280 unsigned blen
= bitlen(finst
->cp
->basePrime
);
282 finst
->plainBlockSize
= blen
/ 8;
283 if((blen
& 0x7) == 0) {
285 * round down some more...
287 finst
->plainBlockSize
--;
291 finst
->plainBlockSize
= finst
->cp
->q
/ 8;
292 if(((finst
->cp
->q
& 0x7) == 0) && (finst
->cp
->k
> 0)) {
294 * Special case, with q mod 8 == 0. Here we have to
295 * trim back the plainBlockSize by one byte.
297 finst
->plainBlockSize
--;
300 finst
->cipherBlockSize
= finst
->cp
->minBytes
+ 1;
303 * the size of initialRS is subject to tweaking - if we make it
304 * not a multiple of plainBlockSize, we save one FEEDExp cipherBlock
307 finst
->initialRSSize
= finst
->plainBlockSize
* 2;
308 if(finst
->initialRSSize
> RS_MIN_SIZE
) {
309 unsigned minPlainBlocks
;
313 * How many plainblocks to hold RS_MIN_SIZE?
315 minPlainBlocks
= (RS_MIN_SIZE
+ finst
->plainBlockSize
- 1) /
316 finst
->plainBlockSize
;
319 * Max size = that many plainblocks, less 2 bytes (to avoid
320 * extra residue block).
322 maxSize
= minPlainBlocks
* finst
->plainBlockSize
- 2;
325 * But don't bother with more than 2 plainblocks worth
327 if(finst
->initialRSSize
> maxSize
) {
328 finst
->initialRSSize
= maxSize
;
331 /* else leave it alone, that's small enough */
334 feeRand frand
= NULL
;
337 * Encrypt-capable FEEDExp object
339 finst
->feedExp
= feeFEEDExpNewWithPubKey(theirPubKey
,
342 if(finst
->feedExp
== NULL
) {
347 * Generate initial r and s data.
349 finst
->initialRS
= (unsigned char*) fmalloc(finst
->initialRSSize
);
350 if(randFcn
!= NULL
) {
351 randFcn(randRef
, finst
->initialRS
, finst
->initialRSSize
);
354 frand
= feeRandAlloc();
355 feeRandBytes(frand
, finst
->initialRS
, finst
->initialRSSize
);
358 if(initFromRS(finst
)) {
364 * Decrypt-capable FEEDExp object
366 finst
->feedExp
= feeFEEDExpNewWithPubKey(myPrivKey
,
369 if(finst
->feedExp
== NULL
) {
376 * Figure out how many of our cipherblocks it takes to hold
377 * a FEEDExp-encrypted initialRS. If initialRSSize is an exact
378 * multiple of expPlainSize, we get an additional feedExp
381 expPlainSize
= feeFEEDExpPlainBlockSize(finst
->feedExp
);
382 expCipherSize
= feeFEEDExpCipherBlockSize(finst
->feedExp
);
383 expBlocks
= (finst
->initialRSSize
+ expPlainSize
- 1) /
385 if((finst
->initialRSSize
% expPlainSize
) == 0) {
390 * Total meaningful bytes of encrypted initialRS
392 finst
->rsCtextSize
= expBlocks
* expCipherSize
;
395 * Number of our cipherblocks it takes to hold rsCtextSize
397 finst
->rsSizeCipherBlocks
= (finst
->rsCtextSize
+
398 finst
->cipherBlockSize
- 1) / finst
->cipherBlockSize
;
400 finst
->rsCtext
= (unsigned char*) fmalloc(finst
->rsSizeCipherBlocks
*
401 finst
->cipherBlockSize
);
409 unsigned fexpBlockSize
= feeFEEDExpCipherBlockSize(finst
->feedExp
);
412 * FEEDExp has one more giant in ciphertext, plaintext is
415 if((finst
->cipherBlockSize
+ finst
->cp
->minBytes
) !=
417 dbgLog(("feeFEEDNewWithPubKey: FEEDExp CBlock Size "
421 fexpBlockSize
= feeFEEDExpPlainBlockSize(finst
->feedExp
);
422 if(fexpBlockSize
!= finst
->plainBlockSize
) {
423 dbgLog(("feeFEEDNewWithPubKey: FEEDExp PBlock Size "
437 void feeFEEDFree(feeFEED feed
)
439 feedInst
*finst
= (feedInst
*) feed
;
442 freeCurveParams(finst
->cp
);
444 if(finst
->initialRS
) {
445 ffree(finst
->initialRS
);
447 if(finst
->cluePlus
) {
448 freeGiant(finst
->cluePlus
);
450 if(finst
->clueMinus
) {
451 freeGiant(finst
->clueMinus
);
454 freeGiant(finst
->sPlus
);
457 freeGiant(finst
->sMinus
);
463 feeFEEDExpFree(finst
->feedExp
);
466 ffree(finst
->rsCtext
);
469 freeGiant(finst
->xp
);
472 freeGiant(finst
->xm
);
475 freeGiant(finst
->tmp1
);
478 freeGiant(finst
->tmp2
);
483 unsigned feeFEEDPlainBlockSize(feeFEED feed
)
485 feedInst
*finst
= (feedInst
*) feed
;
487 return finst
->plainBlockSize
;
490 unsigned feeFEEDCipherBlockSize(feeFEED feed
)
492 feedInst
*finst
= (feedInst
*) feed
;
494 return finst
->cipherBlockSize
;
498 * Calculate size of buffer currently needed to encrypt one block of
499 * plaintext. Also used to calculate required input during decrypt
502 unsigned feeFEEDCipherBufSize(feeFEED feed
,
505 feedInst
*finst
= (feedInst
*) feed
;
506 unsigned blocks
= 1; // always at least one block of ciphertext
508 if(finst
->rsBlockCount
== 0) {
509 /* haven't sent/seen encrypted RS yet */
510 blocks
+= finst
->rsSizeCipherBlocks
;
514 /* only needed if ptext is aligned, but tell caller to malloc */
517 bprintf(("$$$ feeFEEDCipherBufSize( %s, %s): rtn 0x%x\n",
518 finst
->forEncrypt
? "encrypt" : "decrypt",
519 finalBlock
? " final" : "!final",
520 blocks
* finst
->cipherBlockSize
));
521 return blocks
* finst
->cipherBlockSize
;
525 * Return the size of ciphertext currently needed to encrypt specified
526 * size of plaintext. Also can be used to calculate size of ciphertext
527 * which can be decrypted into specified size of plaintext.
529 unsigned feeFEEDCipherTextSize(feeFEED feed
,
530 unsigned plainTextSize
,
533 feedInst
*finst
= (feedInst
*) feed
;
535 /* how many blocks of plaintext? */
536 unsigned blocks
= (plainTextSize
+ finst
->plainBlockSize
- 1) /
537 finst
->plainBlockSize
;
539 if(finst
->forEncrypt
) {
540 /* have we generated RS? */
541 if(finst
->rsBlockCount
== 0) {
542 /* haven't sent encrypted RS yet */
543 blocks
+= finst
->rsSizeCipherBlocks
;
546 /* final? residue? */
548 if((plainTextSize
% finst
->plainBlockSize
) == 0) {
555 * Decrypting - how much ciphertext can we decrypt safely into
556 * specified plaintext? Add in RS if we haven't seen it all
560 if(finst
->rsBlockCount
> finst
->rsSizeCipherBlocks
) {
561 printf("******HEY! rsBlockCount overflow! (blockCount %d rsSize %d)\n",
562 finst
->rsBlockCount
, finst
->rsSizeCipherBlocks
);
565 blocks
+= (finst
->rsSizeCipherBlocks
- finst
->rsBlockCount
);
567 bprintf(("$$$ feeFEEDCipherTextSize(%s, %s, 0x%x): rtn 0x%x\n",
568 finst
->forEncrypt
? "encrypt" : "decrypt",
569 finalBlock
? " final" : "!final",
570 plainTextSize
, blocks
* finst
->cipherBlockSize
));
571 return blocks
* finst
->cipherBlockSize
;
575 * Return the size of plaintext currently needed to decrypt specified size
576 * of ciphertext. Also can be used to calculate size of plaintext
577 * which can be encrypted into specified size of ciphertext.
579 unsigned feeFEEDPlainTextSize(feeFEED feed
,
580 unsigned cipherTextSize
,
581 int finalBlock
) // ignored if !forEncrypt
583 feedInst
*finst
= (feedInst
*) feed
;
585 /* start with basic cipher block count */
586 unsigned cipherBlocks
= (cipherTextSize
+ finst
->cipherBlockSize
- 1) /
587 finst
->cipherBlockSize
;
589 /* where are we in the RS stream? */
590 unsigned rsBlocksToGo
= finst
->rsSizeCipherBlocks
- finst
->rsBlockCount
;
591 if(finst
->forEncrypt
) {
593 * Encrypting, seeking plaintext size we can encrypt given
594 * a specified size of ciphertext.
596 if(rsBlocksToGo
>= cipherBlocks
) {
597 /* no room! next encrypt would overflow ctext buffer! */
600 cipherBlocks
-= rsBlocksToGo
;
602 /* another constraint - residue */
605 /* skip if already zero... */
612 if(rsBlocksToGo
>= cipherBlocks
) {
613 /* still processing RS, no plaintext will be generated. Play it real
614 * safe and just tell caller one block. */
618 /* diminish by size of RS to be gobbled with no output */
619 cipherBlocks
-= rsBlocksToGo
;
622 bprintf(("$$$ feeFEEDPlainTextSize( %s, %s, 0x%x): rtn 0x%x\n",
623 finst
->forEncrypt
? "encrypt" : "decrypt",
624 finalBlock
? " final" : "!final",
625 cipherTextSize
, cipherBlocks
* finst
->plainBlockSize
));
626 return cipherBlocks
* finst
->plainBlockSize
;
630 * Bits in last byte of cipherblock
632 #define CLUE_BIT 0x01 /* 1 ==> plus curve */
633 #define CLUE_PLUS 0x01
634 #define CLUE_MINUS 0x00
635 #define PARITY_BIT 0x02 /* 1 ==> plus 's' arg to elliptic_add() */
636 #define PARITY_PLUS 0x02
637 #define PARITY_MINUS 0x00
640 * Encrypt a block or less of data. Caller malloc's cipherText.
641 * Generates up to feeFEEDCipherBufSize() bytes of ciphertext.
643 feeReturn
feeFEEDEncryptBlock(feeFEED feed
,
644 const unsigned char *plainText
,
645 unsigned plainTextLen
,
646 unsigned char *cipherText
,
647 unsigned *cipherTextLen
, // RETURNED
650 feedInst
*finst
= (feedInst
*) feed
;
651 unsigned ctextLen
= 0;
652 feeReturn frtn
= FR_Success
;
654 giant thisClue
; // not alloc'd or freed
655 giant thisS
; // ditto
656 unsigned char clueByte
;
658 if(plainTextLen
> finst
->plainBlockSize
) {
659 return FR_IllegalArg
;
661 if((plainTextLen
< finst
->plainBlockSize
) && !finalBlock
) {
662 return FR_IllegalArg
;
664 if(finst
->initialRS
== NULL
) {
666 * Init'd for decrypt?
668 return FR_IllegalArg
;
672 * First block - encrypt initialRS via FEEDExp
674 if(finst
->rsBlockCount
== 0) {
675 unsigned char *thisCtext
; // malloc's by FEEDExp
678 if(finst
->initialRS
== NULL
) {
680 * init'd for decrypt or reused
682 dbgLog(("feeFEEDEncryptBlock: NULL initialRS!\n"));
683 return FR_IllegalArg
;
686 frtn
= feeFEEDExpEncrypt(finst
->feedExp
,
688 finst
->initialRSSize
,
693 * Should never happen...
695 dbgLog(("feeFEEDEncryptBlock: error writing encrypted"
696 " initialRS (%s)\n", feeReturnString(frtn
)));
699 bcopy(thisCtext
, cipherText
, ctextLen
);
700 cipherText
+= ctextLen
;
703 finst
->rsBlockCount
= finst
->rsSizeCipherBlocks
;
704 padLen
= finst
->cipherBlockSize
-
705 (ctextLen
% finst
->cipherBlockSize
); // zeros to write
707 #if 0 /* FEED_DEBUG */
710 * Hard-coded assumptions and tests about initRSSize...
711 * Currently we assume that initRSSize % expBlockSize = 0
713 if((ctextLen
/ finst
->cipherBlockSize
) != 5) {
714 dbgLog(("feeFEEDEncryptBlock: cipherblock size screwup (1)\n"));
718 dbgLog(("feeFEEDEncryptBlock: cipherblock size screwup (2)\n"));
724 * pad to multiple of (our) cipherblock size.
734 * plaintext to giant xp
737 unsigned char *ptext
= (unsigned char*) fmalloc(finst
->plainBlockSize
);
738 bzero(ptext
, finst
->plainBlockSize
);
741 * skip for empty block with resid length 0
743 bcopy(plainText
, ptext
, plainTextLen
);
745 if(plainTextLen
< finst
->plainBlockSize
) {
746 if(plainTextLen
== 0) {
748 * Special case - resid block with no actual plaintext.
749 * Can't actually write zero here; it screws up
750 * deserializing the giant during decrypt
752 ptext
[finst
->plainBlockSize
- 1] = RESID_ZERO
;
753 bprintf(("=== FEED encrypt: RESID_ZERO\n"));
756 ptext
[finst
->plainBlockSize
- 1] = plainTextLen
;
757 bprintf(("=== FEED encrypt: resid len 0x%x\n", plainTextLen
));
761 * else handle evenly aligned case (i.e., finalBlock true
762 * and (plainTextLen == plainBlockSize)) below...
764 deserializeGiant(ptext
, finst
->xp
, finst
->plainBlockSize
);
768 deserializeGiant(plainText
, finst
->xp
, plainTextLen
);
773 * xm = xp + clue(+/-)
774 * determine parity needed to restore xp
775 * parity = ((xm + clue(+/-) == xp) ? 1 : -1
777 * clue[n+1] = r * clue[n] + (s * P1)
779 whichCurve
= which_curve(finst
->xp
, finst
->cp
);
780 if(whichCurve
== CURVE_PLUS
) {
781 thisClue
= finst
->cluePlus
;
782 thisS
= finst
->sPlus
;
783 clueByte
= CLUE_PLUS
;
786 thisClue
= finst
->clueMinus
;
787 thisS
= finst
->sMinus
;
788 clueByte
= CLUE_MINUS
;
791 elliptic_add(thisClue
, finst
->xp
, finst
->xm
, finst
->cp
, SIGN_PLUS
);
792 // save xm + clue in tmp1
793 elliptic_add(finst
->xm
, thisClue
, finst
->tmp1
, finst
->cp
, SIGN_PLUS
);
795 elliptic_simple(thisClue
, finst
->r
, finst
->cp
);
796 gtog(thisClue
, finst
->tmp2
);
797 elliptic_add(finst
->tmp2
, thisS
, thisClue
, finst
->cp
, SIGN_PLUS
);
802 if(gcompg(finst
->tmp1
, finst
->xp
) == 0) {
803 clueByte
|= PARITY_PLUS
;
807 * Ciphertext = (xm, clueByte)
809 serializeGiant(finst
->xm
, cipherText
, finst
->cp
->minBytes
);
810 cipherText
+= finst
->cp
->minBytes
;
811 ctextLen
+= finst
->cp
->minBytes
;
812 *cipherText
++ = clueByte
;
816 printf("encrypt clue %d\n", clueByte
);
817 printf(" xp : "); printGiant(finst
->xp
);
818 printf(" xm : "); printGiant(finst
->xm
);
819 printf(" cluePlus :"); printGiant(finst
->cluePlus
);
820 printf(" clueMinus :"); printGiant(finst
->clueMinus
);
823 if(finalBlock
&& (plainTextLen
== finst
->plainBlockSize
)) {
825 * Special case: finalBlock true, plainTextLen == blockSize.
826 * In this case we generate one more block of ciphertext,
827 * with a resid length of zero.
829 unsigned moreCipher
; // additional cipherLen
831 frtn
= feeFEEDEncryptBlock(feed
,
832 NULL
, // plainText not used
834 cipherText
, // append...
837 if(frtn
== FR_Success
) {
838 ctextLen
+= moreCipher
;
841 bprintf(("=== FEED encryptBlock ptextLen 0x%x ctextLen 0x%x\n",
842 plainTextLen
, ctextLen
));
844 *cipherTextLen
= ctextLen
;
849 * Decrypt (exactly) a block of data. Caller malloc's plainText. Always
850 * generates feeFEEDPlainBlockSize of plaintext, unless finalBlock is
851 * non-zero (in which case feeFEEDPlainBlockSize or less bytes of plainText are
854 feeReturn
feeFEEDDecryptBlock(feeFEED feed
,
855 const unsigned char *cipherText
,
856 unsigned cipherTextLen
,
857 unsigned char *plainText
,
858 unsigned *plainTextLen
, // RETURNED
861 feedInst
*finst
= (feedInst
*) feed
;
862 feeReturn frtn
= FR_Success
;
863 unsigned char clueByte
;
864 giant thisClue
; // not alloc'd
865 giant thisS
; // ditto
868 if(finst
->rsCtext
== NULL
) {
870 * Init'd for encrypt?
872 return FR_IllegalArg
;
874 if(cipherTextLen
!= finst
->cipherBlockSize
) {
875 dbgLog(("feeFEEDDecryptBlock: bad cipherTextLen\n"));
876 return FR_IllegalArg
;
878 if(finst
->rsBlockCount
< finst
->rsSizeCipherBlocks
) {
880 * Processing initialRS, FEEDExp-encrypted
882 unsigned char *rsPtr
= finst
->rsCtext
+
883 (finst
->rsBlockCount
* finst
->cipherBlockSize
);
884 unsigned feedExpCipherSize
;
887 dbgLog(("feeFEEDDecryptBlock: incomplete initialRS\n"));
888 return FR_BadCipherText
;
890 bcopy(cipherText
, rsPtr
, finst
->cipherBlockSize
);
891 finst
->rsBlockCount
++;
892 if(finst
->rsBlockCount
< finst
->rsSizeCipherBlocks
) {
894 * Not done with this yet...
896 bprintf(("=== FEED Decrypt: gobbled 0x%x bytes ctext, no ptext (1)\n",
903 if((finst
->rsBlockCount
* finst
->cipherBlockSize
) <
904 finst
->rsCtextSize
) {
905 dbgLog(("feeFEEDDecryptBlock: rsCtextSize underflow!\n"));
911 * OK, we should have the FEEDExp ciphertext for initialRS
912 * in rsCtext. Note the last few bytes are extra; we don't
913 * pass them to FEEDExp.
915 feedExpCipherSize
= feeFEEDCipherBlockSize(finst
->feedExp
);
916 frtn
= feeFEEDExpDecrypt(finst
->feedExp
,
920 &finst
->initialRSSize
);
922 dbgLog(("feeFEEDDecryptBlock: error decrypting "
923 "initialRS (%s)\n", feeReturnString(frtn
)));
924 return FR_BadCipherText
;
930 if(initFromRS(finst
)) {
931 dbgLog(("feeFEEDDecryptBlock: bad initialRS\n"));
932 return FR_BadCipherText
;
936 * Normal completion of last cipherblock containing
939 bprintf(("=== FEED Decrypt: gobbled 0x%x bytes ctext, no ptext (2)\n",
947 * grab xm and clueByte from cipherText
949 deserializeGiant(cipherText
, finst
->xm
, finst
->cp
->minBytes
);
950 cipherText
+= finst
->cp
->minBytes
;
951 clueByte
= *cipherText
;
953 if((clueByte
& CLUE_BIT
) == CLUE_PLUS
) {
954 thisClue
= finst
->cluePlus
;
955 thisS
= finst
->sPlus
;
958 thisClue
= finst
->clueMinus
;
959 thisS
= finst
->sMinus
;
961 if((clueByte
& PARITY_BIT
) == PARITY_PLUS
) {
970 * xp = xm + clue(+/-) w/parity
972 * clue[n+1] = r * clue[n] + (s * P1)
974 elliptic_add(thisClue
, finst
->xm
, finst
->xp
, finst
->cp
, parity
);
976 elliptic_simple(thisClue
, finst
->r
, finst
->cp
);
977 gtog(thisClue
, finst
->tmp1
);
978 elliptic_add(finst
->tmp1
, thisS
, thisClue
, finst
->cp
, SIGN_PLUS
);
984 printf("decrypt clue %d\n", clueByte
);
985 printf(" xp : "); printGiant(finst
->xp
);
986 printf(" xm : "); printGiant(finst
->xm
);
987 printf(" cluePlus :"); printGiant(finst
->cluePlus
);
988 printf(" clueMinus :"); printGiant(finst
->clueMinus
);
993 * Snag data from xp in order to find out how much to move to
996 unsigned char *ptext
= (unsigned char*) fmalloc(finst
->plainBlockSize
);
998 serializeGiant(finst
->xp
, ptext
, finst
->plainBlockSize
);
999 *plainTextLen
= ptext
[finst
->plainBlockSize
- 1];
1000 if(*plainTextLen
== RESID_ZERO
) {
1001 bprintf(("=== FEED Decrypt: RESID_ZERO\n"));
1004 else if(*plainTextLen
> (finst
->plainBlockSize
- 1)) {
1005 dbgLog(("feeFEEDDecryptBlock: ptext overflow!\n"));
1006 bprintf(("feeFEEDDecryptBlock: ptext overflow!\n"));
1007 frtn
= FR_BadCipherText
;
1010 bprintf(("=== FEED Decrypt: resid len 0x%x\n", *plainTextLen
));
1011 bcopy(ptext
, plainText
, *plainTextLen
);
1016 *plainTextLen
= finst
->plainBlockSize
;
1017 serializeGiant(finst
->xp
, plainText
, *plainTextLen
);
1019 bprintf(("=== FEED decryptBlock ptextLen 0x%x ctextLen 0x%x\n",
1020 *plainTextLen
, cipherTextLen
));
1026 * Convenience routines to encrypt & decrypt multi-block data.
1028 feeReturn
feeFEEDEncrypt(feeFEED feed
,
1029 const unsigned char *plainText
,
1030 unsigned plainTextLen
,
1031 unsigned char **cipherText
, // malloc'd and RETURNED
1032 unsigned *cipherTextLen
) // RETURNED
1034 const unsigned char *ptext
; // per block
1035 unsigned ptextLen
; // total to go
1036 unsigned thisPtextLen
; // per block
1037 unsigned char *ctext
; // per block
1038 unsigned ctextLen
; // per block
1039 unsigned char *ctextResult
; // to return
1040 unsigned ctextResultLen
; // size of ctextResult
1041 unsigned char *ctextPtr
;
1042 unsigned ctextLenTotal
; // running total
1046 unsigned plainBlockSize
;
1048 unsigned expectedCtextSize
;
1050 expectedCtextSize
= feeFEEDCipherTextSize(feed
, plainTextLen
, 1);
1053 if(plainTextLen
== 0) {
1054 dbgLog(("feeFEEDDecrypt: NULL plainText\n"));
1055 return FR_IllegalArg
;
1059 ptextLen
= plainTextLen
;
1060 ctext
= (unsigned char*) fmalloc(feeFEEDCipherBufSize(feed
, 1));
1061 plainBlockSize
= feeFEEDPlainBlockSize(feed
);
1062 numBlocks
= (plainTextLen
+ plainBlockSize
- 1)/plainBlockSize
;
1065 * Calculate the worst-case size needed to hold all of the ciphertext
1067 ctextResultLen
= feeFEEDCipherTextSize(feed
, plainTextLen
, 1);
1068 ctextResult
= (unsigned char*) fmalloc(ctextResultLen
);
1069 ctextPtr
= ctextResult
;
1073 if(ptextLen
<= plainBlockSize
) {
1075 thisPtextLen
= ptextLen
;
1079 thisPtextLen
= plainBlockSize
;
1081 frtn
= feeFEEDEncryptBlock(feed
,
1088 dbgLog(("feeFEEDEncrypt: encrypt error: %s\n",
1089 feeReturnString(frtn
)));
1093 dbgLog(("feeFEEDEncrypt: null ciphertext\n"));
1097 bcopy(ctext
, ctextPtr
, ctextLen
);
1098 ctextLenTotal
+= ctextLen
;
1099 if(ctextLenTotal
> ctextResultLen
) {
1100 dbgLog(("feeFEEDEncrypt: ciphertext overflow\n"));
1107 ctextPtr
+= ctextLen
;
1108 ptext
+= thisPtextLen
;
1109 ptextLen
-= thisPtextLen
;
1119 *cipherText
= ctextResult
;
1120 *cipherTextLen
= ctextLenTotal
;
1122 if(expectedCtextSize
!= ctextLenTotal
) {
1123 printf("feeFEEDEncrypt: feeFEEDCipherTextSize error!\n");
1124 printf("ptext %d exp ctext %d actual ctext %d\n",
1135 feeReturn
feeFEEDDecrypt(feeFEED feed
,
1136 const unsigned char *cipherText
,
1137 unsigned cipherTextLen
,
1138 unsigned char **plainText
, // malloc'd and RETURNED
1139 unsigned *plainTextLen
) // RETURNED
1141 const unsigned char *ctext
;
1142 unsigned ctextLen
; // total to go
1143 unsigned char *ptext
; // per block
1144 unsigned ptextLen
; // per block
1145 unsigned char *ptextResult
; // to return
1146 unsigned char *ptextPtr
;
1147 unsigned ptextLenTotal
; // running total
1148 feeReturn frtn
= FR_Success
;
1151 unsigned plainBlockSize
= feeFEEDPlainBlockSize(feed
);
1152 unsigned cipherBlockSize
= feeFEEDCipherBlockSize(feed
);
1154 if(cipherTextLen
% cipherBlockSize
) {
1155 dbgLog(("feeFEEDDecrypt: unaligned cipherText\n"));
1156 return FR_BadCipherText
;
1158 if(cipherTextLen
== 0) {
1159 dbgLog(("feeFEEDDecrypt: NULL cipherText\n"));
1160 return FR_BadCipherText
;
1163 ptext
= (unsigned char*) fmalloc(plainBlockSize
);
1165 ctextLen
= cipherTextLen
;
1166 numBlocks
= cipherTextLen
/ cipherBlockSize
;
1167 ptextResult
= (unsigned char*) fmalloc(plainBlockSize
* numBlocks
);
1168 ptextPtr
= ptextResult
;
1172 if(ctextLen
== cipherBlockSize
) {
1178 frtn
= feeFEEDDecryptBlock(feed
,
1185 dbgLog(("feeFEEDDecryptBlock: %s\n",
1186 feeReturnString(frtn
)));
1190 if(ptextLen
> plainBlockSize
) {
1191 dbgLog(("feeFEEDDecrypt: ptext overflow!\n"));
1195 bcopy(ptext
, ptextPtr
, ptextLen
);
1196 ptextPtr
+= ptextLen
;
1197 ptextLenTotal
+= ptextLen
;
1200 * note ptextLen == 0 is normal termination case for
1201 * plainTextLen % plainBlockSize == 0.
1202 * Also expected for first 4 blocks of ciphertext;
1203 * proceed (we break when ctextLen is exhausted).
1205 ctext
+= cipherBlockSize
;
1206 ctextLen
-= cipherBlockSize
;
1216 *plainText
= ptextResult
;
1217 *plainTextLen
= ptextLenTotal
;