]>
git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_cryptkit/lib/feeFEEDExp.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 * FeeFEEDExp.c - generic FEED encryption object, 2:1 expansion
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 * 03 Mar 1997 at Apple
22 * Trimmed plainBlockSize by one byte if q mod 8 = 0
24 * Renamed to feeFEEDExp.c
25 * Justified random xaux to [2, minimumX1Order]
26 * Added feeFEEDExpCipherTextSize()
28 * Cleaned up which_curve/index code to use CURVE_MINUS/CURVE_PLUS
30 * Created from Blaine Garst's NSFEECryptor.m.
36 #include "feeFEEDExp.h"
37 #include "feePublicKey.h"
38 #include "feePublicKeyPrivate.h"
41 #include "feeRandom.h"
42 #include "ckutilities.h"
43 #include "feeFunctions.h"
50 #define PRINT_GIANT(g) printGiant(g)
53 * Format of clue byte. Currently just one bit.
55 #define CLUE_ELL_ADD_SIGN 0x01
56 #define CLUE_ELL_ADD_SIGN_PLUS 0x01
57 #define CLUE_ELL_ADD_SIGN_MINUS 0x00
65 unsigned plainBlockSize
; /* plaintext block size */
66 unsigned cipherBlockSize
;/* ciphertext block size */
68 giant gPriv
; /* private data, only for decrypt */
69 /* one of the follow two is valid for encrypt */
70 feeRand rand
; /* only created for encrypt */
75 * temporary variables used for encrypt/decrypt. The values in these
76 * is not needed to be kept from block to block; we just
77 * alloc them once per lifetime of a feeFEED object as an optimization.
79 giant xp
; /* plaintext */
80 giant xc
; /* clue = r(P1?) */
81 giant xq
; /* r(pubB?) or priB?(xc) */
82 giant xm
; /* ciphertext */
83 giant xaux
; /* scratch */
84 unsigned char *randData
; /* only created for encrypt */
88 * "zero residue" indicator.
90 #define RESID_ZERO 0xff
93 * Alloc and init a feeFEEDExp object associated with specified feePubKey.
95 feeFEEDExp
feeFEEDExpNewWithPubKey(
97 feeRandFcn randFcn
, // optional
100 feedInst
*finst
= (feedInst
*) fmalloc(sizeof(feedInst
));
103 finst
->cp
= curveParamsCopy(feePubKeyCurveParams(pubKey
));
104 finst
->plus
= new_public_with_key(feePubKeyPlusCurve(pubKey
),
106 finst
->minus
= new_public_with_key(feePubKeyMinusCurve(pubKey
),
110 * These might yield NULL data; we can only encrypt in that case.
112 privGiant
= feePubKeyPrivData(pubKey
);
114 finst
->gPriv
= newGiant(finst
->cp
->maxDigits
);
115 gtog(privGiant
, finst
->gPriv
);
122 * Conservative, rounding down, on plaintext blocks since we don't
123 * want to split bytes.
125 if(finst
->cp
->primeType
== FPT_General
) {
126 unsigned blen
= bitlen(finst
->cp
->basePrime
);
128 finst
->plainBlockSize
= blen
/ 8;
129 if((blen
% 8) == 0) {
131 * round down some more...
133 finst
->plainBlockSize
--;
137 finst
->plainBlockSize
= finst
->cp
->q
/ 8;
138 if(((finst
->cp
->q
& 0x7) == 0) && (finst
->cp
->k
> 0)) {
140 * Special case, with q mod 8 == 0. Here we have to trim back
141 * the plainBlockSize by one byte.
143 finst
->plainBlockSize
--;
148 * One block of ciphertext - two giants (with implied sign) and a
151 finst
->cipherBlockSize
= (2 * finst
->cp
->minBytes
) + 1;
153 finst
->xp
= newGiant(finst
->cp
->maxDigits
);
154 finst
->xc
= newGiant(finst
->cp
->maxDigits
);
155 finst
->xq
= newGiant(finst
->cp
->maxDigits
);
156 finst
->xm
= newGiant(finst
->cp
->maxDigits
);
157 finst
->xaux
= newGiant(finst
->cp
->maxDigits
);
159 finst
->randData
= NULL
;
160 finst
->randFcn
= randFcn
;
161 finst
->randRef
= randRef
;
165 void feeFEEDExpFree(feeFEEDExp feed
)
167 feedInst
*finst
= (feedInst
*) feed
;
169 free_key(finst
->plus
);
170 free_key(finst
->minus
);
171 freeGiant(finst
->xc
);
172 clearGiant(finst
->xp
); freeGiant(finst
->xp
);
173 clearGiant(finst
->xq
); freeGiant(finst
->xq
);
174 freeGiant(finst
->xm
);
175 clearGiant(finst
->xaux
); freeGiant(finst
->xaux
);
177 clearGiant(finst
->gPriv
);
178 freeGiant(finst
->gPriv
);
181 feeRandFree(finst
->rand
);
183 if(finst
->randData
) {
184 ffree(finst
->randData
);
187 freeCurveParams(finst
->cp
);
192 unsigned feeFEEDExpPlainBlockSize(feeFEEDExp feed
)
194 feedInst
*finst
= (feedInst
*) feed
;
196 return finst
->plainBlockSize
;
199 unsigned feeFEEDExpCipherBlockSize(feeFEEDExp feed
)
201 feedInst
*finst
= (feedInst
*) feed
;
203 return finst
->cipherBlockSize
;
206 unsigned feeFEEDExpCipherBufSize(feeFEEDExp feed
)
208 feedInst
*finst
= (feedInst
*) feed
;
210 return 2 * finst
->cipherBlockSize
;
214 * Return the size of ciphertext to hold specified size of plaintext.
216 unsigned feeFEEDExpCipherTextSize(feeFEEDExp feed
, unsigned plainTextSize
)
219 * Normal case is one block of ciphertext for each block of
220 * plaintext. Add one cipherBlock if
221 * plainTextSize % plainBlockSize == 0.
223 feedInst
*finst
= (feedInst
*) feed
;
224 unsigned blocks
= (plainTextSize
+ finst
->plainBlockSize
- 1) /
225 finst
->plainBlockSize
;
227 if((plainTextSize
% finst
->plainBlockSize
) == 0) {
230 return blocks
* finst
->cipherBlockSize
;
234 * Return the size of plaintext to hold specified size of decrypted ciphertext.
236 unsigned feeFEEDExpPlainTextSize(feeFEEDExp feed
, unsigned cipherTextSize
)
238 feedInst
*finst
= (feedInst
*) feed
;
239 unsigned blocks
= (cipherTextSize
+ finst
->cipherBlockSize
- 1) /
240 finst
->cipherBlockSize
;
242 return blocks
* finst
->plainBlockSize
;
246 * Encrypt a block or less of data. Caller malloc's cipherText.
248 feeReturn
feeFEEDExpEncryptBlock(feeFEEDExp feed
,
249 const unsigned char *plainText
,
250 unsigned plainTextLen
,
251 unsigned char *cipherText
,
252 unsigned *cipherTextLen
, // RETURNED
255 feedInst
*finst
= (feedInst
*) feed
;
256 int index
; /* which curve (+/- 1) */
257 char g
= 0; /* parity, which_curve bits in ciphertext */
259 unsigned char *ptext
; /* for final block */
261 feeReturn frtn
= FR_Success
;
264 curveParams
*cp
= finst
->cp
;
265 randLen
= cp
->minBytes
+8; // +8bytes (64bits) to reduce the biais when with reduction mod prime. Per FIPS186-4 - "Using Extra Random Bits"
267 if(plainTextLen
> finst
->plainBlockSize
) {
268 return FR_IllegalArg
;
270 else if ((plainTextLen
< finst
->plainBlockSize
) && !finalBlock
) {
271 return FR_IllegalArg
;
275 * Init only on first encrypt
277 if((finst
->randFcn
== NULL
) && (finst
->rand
== NULL
)) {
278 finst
->rand
= feeRandAlloc();
280 if(finst
->randData
== NULL
) {
281 finst
->randData
= (unsigned char*) fmalloc(randLen
);
285 * plaintext as giant xp
288 ptext
= (unsigned char*) fmalloc(finst
->plainBlockSize
);
289 bzero(ptext
, finst
->plainBlockSize
);
292 * 0 for empty block with resid length 0
294 bcopy(plainText
, ptext
, plainTextLen
);
296 if(plainTextLen
< finst
->plainBlockSize
) {
297 if(plainTextLen
== 0) {
299 * Special case - can't actually write zero here;
300 * it screws up deserializing the giant during
303 ptext
[finst
->plainBlockSize
- 1] = RESID_ZERO
;
306 ptext
[finst
->plainBlockSize
- 1] = plainTextLen
;
309 printf("encrypt: resid 0x%x\n", ptext
[finst
->plainBlockSize
- 1]);
313 * else handle evenly aligned case below...
315 deserializeGiant(ptext
, finst
->xp
, finst
->plainBlockSize
);
319 deserializeGiant(plainText
, finst
->xp
, plainTextLen
);
322 printf("encrypt:\n");
323 printf(" xp : "); PRINT_GIANT(finst
->xp
);
327 * pick curve B? that data lies upon
329 index
= which_curve(finst
->xp
, finst
->cp
);
330 if(index
== CURVE_PLUS
) {
332 x1
= finst
->cp
->x1Plus
;
336 x1
= finst
->cp
->x1Minus
;
339 printf(" which_curve: %s\n",
340 (index
== CURVE_PLUS
) ? "CURVE_PLUS" : "CURVE_MINUS");
344 * random number as giant xaux
346 if(finst
->randFcn
!= NULL
) {
347 finst
->randFcn(finst
->randRef
, finst
->randData
, randLen
);
350 feeRandBytes(finst
->rand
, finst
->randData
, randLen
);
352 deserializeGiant(finst
->randData
, finst
->xaux
, randLen
);
355 if(isZero(finst
->xaux
)) {
356 printf("feeFEEDExpEncryptBlock: random xaux = 0!\n");
360 * Justify random # to be in [2, minimumX1Order].
362 lesserX1OrderJustify(finst
->xaux
, cp
);
364 printf(" xaux: "); PRINT_GIANT(finst
->xaux
);
367 gtog(B
->x
, finst
->xq
); // xq = pubB?
368 elliptic_simple(finst
->xq
, finst
->xaux
, cp
);
371 printf(" r(pubB?): "); PRINT_GIANT(finst
->xq
);
373 elliptic_add(finst
->xp
, finst
->xq
, finst
->xm
, cp
, SIGN_PLUS
);
374 // xm = data + r(pubB?)
376 elliptic_simple(finst
->xc
, finst
->xaux
, cp
);
378 elliptic_add(finst
->xm
, finst
->xq
, finst
->xaux
, cp
, SIGN_PLUS
);
379 // xaux = xm + xq (for curve +1)
380 // = (data + r(pubB?)) + r(pubB?)
381 if(gcompg(finst
->xaux
, finst
->xp
) == 0) {
382 g
|= CLUE_ELL_ADD_SIGN_PLUS
;
385 g
|= CLUE_ELL_ADD_SIGN_MINUS
;
387 /* this better be true.... */
388 elliptic_add(finst
->xm
, finst
->xq
, finst
->xaux
, cp
, SIGN_MINUS
);
389 if(gcompg(finst
->xaux
, finst
->xp
)) {
390 printf("*******elliptic_add(xm, xq, -1) != xp! *************\n");
391 printf(" xq : "); PRINT_GIANT(finst
->xq
);
392 printf(" ell_add(xm, xq, -1) : "); PRINT_GIANT(finst
->xaux
);
395 } // g = (xaux == data) ? add : subtract
398 * Ciphertext = (xm, xc, g)
400 serializeGiant(finst
->xm
, cipherText
, cp
->minBytes
);
401 cipherText
+= cp
->minBytes
;
402 serializeGiant(finst
->xc
, cipherText
, cp
->minBytes
);
403 cipherText
+= cp
->minBytes
;
405 ctextLen
= finst
->cipherBlockSize
;
407 printf(" xm : "); PRINT_GIANT(finst
->xm
);
408 printf(" xc : "); PRINT_GIANT(finst
->xc
);
409 printf(" g : %d\n", g
);
411 if(finalBlock
&& (plainTextLen
== finst
->plainBlockSize
)) {
413 * Special case: finalBlock true, plainTextLen == blockSize.
414 * In this case we generate one more block of ciphertext,
415 * with a resid length of zero.
417 unsigned moreCipher
; // additional cipherLen
420 printf("encrypt: one more empty block\n");
422 frtn
= feeFEEDExpEncryptBlock(feed
,
423 NULL
, // plainText not used
425 cipherText
, // append...
428 if(frtn
== FR_Success
) {
429 ctextLen
+= moreCipher
;
433 *cipherTextLen
= ctextLen
;
438 * Decrypt (exactly) a block of data. Caller malloc's plainText. Always
439 * generates feeFEEDExpPlainBlockSize of plaintext, unless finalBlock is
440 * non-zero (in which case feeFEEDExpPlainBlockSize or less bytes of
441 * plainText are generated).
443 feeReturn
feeFEEDExpDecryptBlock(feeFEEDExp feed
,
444 const unsigned char *cipherText
,
445 unsigned cipherTextLen
,
446 unsigned char *plainText
,
447 unsigned *plainTextLen
, // RETURNED
450 feedInst
*finst
= (feedInst
*) feed
;
453 feeReturn frtn
= FR_Success
;
454 curveParams
*cp
= finst
->cp
;
456 if(finst
->gPriv
== NULL
) {
458 * Can't decrypt without private data
464 * grab xm, xc, and g from cipherText
466 deserializeGiant(cipherText
, finst
->xm
, finst
->cp
->minBytes
);
467 cipherText
+= finst
->cp
->minBytes
;
468 deserializeGiant(cipherText
, finst
->xc
, finst
->cp
->minBytes
);
469 cipherText
+= finst
->cp
->minBytes
;
472 printf("decrypt g=%d\n", g
);
473 printf(" privKey : "); PRINT_GIANT(finst
->gPriv
);
474 printf(" xm : "); PRINT_GIANT(finst
->xm
);
475 printf(" xc : "); PRINT_GIANT(finst
->xc
);
478 if((g
& CLUE_ELL_ADD_SIGN
) == CLUE_ELL_ADD_SIGN_PLUS
) {
487 * xc := r(P1?)(pri) = xq
488 * xp = data + r(priB+) +/- pri(rB?)
490 elliptic_simple(finst
->xc
, finst
->gPriv
, cp
);
492 printf(" xc1 : "); PRINT_GIANT(finst
->xc
);
494 elliptic_add(finst
->xm
, finst
->xc
, finst
->xp
, cp
, s
);
500 printf(" xp : "); PRINT_GIANT(finst
->xp
);
505 * Snag data from xp in order to find out how much to move to
508 unsigned char *ptext
= (unsigned char*) fmalloc(finst
->plainBlockSize
);
510 serializeGiant(finst
->xp
, ptext
, finst
->plainBlockSize
);
511 *plainTextLen
= ptext
[finst
->plainBlockSize
- 1];
513 printf("decrypt: resid 0x%x\n", *plainTextLen
);
515 if(*plainTextLen
== RESID_ZERO
) {
518 else if(*plainTextLen
> (finst
->plainBlockSize
- 1)) {
519 dbgLog(("feeFEEDExpDecryptBlock: ptext overflow!\n"));
520 frtn
= FR_BadCipherText
;
523 bcopy(ptext
, plainText
, *plainTextLen
);
528 *plainTextLen
= finst
->plainBlockSize
;
529 serializeGiant(finst
->xp
, plainText
, *plainTextLen
);
535 * Convenience routines to encrypt & decrypt multi-block data.
537 feeReturn
feeFEEDExpEncrypt(feeFEEDExp feed
,
538 const unsigned char *plainText
,
539 unsigned plainTextLen
,
540 unsigned char **cipherText
, // malloc'd and RETURNED
541 unsigned *cipherTextLen
) // RETURNED
543 const unsigned char *ptext
; // per block
544 unsigned ptextLen
; // total to go
545 unsigned thisPtextLen
; // per block
546 unsigned char *ctext
; // per block
547 unsigned ctextLen
; // per block
548 unsigned char *ctextResult
; // to return
549 unsigned ctextResultLen
;
550 unsigned char *ctextPtr
;
551 unsigned ctextLenTotal
; // running total
555 unsigned plainBlockSize
;
557 if(plainTextLen
== 0) {
558 dbgLog(("feeFEEDExpDecrypt: NULL plainText\n"));
559 return FR_IllegalArg
;
563 ptextLen
= plainTextLen
;
564 ctext
= (unsigned char*) fmalloc(feeFEEDExpCipherBufSize(feed
));
565 plainBlockSize
= feeFEEDExpPlainBlockSize(feed
);
566 numBlocks
= (plainTextLen
+ plainBlockSize
- 1)/plainBlockSize
;
567 ctextResultLen
= (numBlocks
+ 1) * feeFEEDExpCipherBlockSize(feed
);
568 ctextResult
= (unsigned char*) fmalloc(ctextResultLen
);
569 ctextPtr
= ctextResult
;
573 if(ptextLen
<= plainBlockSize
) {
575 thisPtextLen
= ptextLen
;
579 thisPtextLen
= plainBlockSize
;
581 frtn
= feeFEEDExpEncryptBlock(feed
,
588 dbgLog(("feeFEEDExpEncrypt: encrypt error: %s\n",
589 feeReturnString(frtn
)));
593 dbgLog(("feeFEEDExpEncrypt: null ciphertext\n"));
597 bcopy(ctext
, ctextPtr
, ctextLen
);
598 ctextLenTotal
+= ctextLen
;
599 if(ctextLenTotal
> ctextResultLen
) {
600 dbgLog(("feeFEEDExpEncrypt: ciphertext overflow\n"));
607 ctextPtr
+= ctextLen
;
608 ptext
+= thisPtextLen
;
609 ptextLen
-= thisPtextLen
;
619 *cipherText
= ctextResult
;
620 *cipherTextLen
= ctextLenTotal
;
622 if(feeFEEDExpCipherTextSize(feed
, plainTextLen
) !=
624 printf("feeFEEDExpEncrypt: feeFEEDCipherTextSize "
626 printf("ptext %d exp ctext %d actual ctext %d\n",
628 feeFEEDExpCipherTextSize(feed
, plainTextLen
),
637 feeReturn
feeFEEDExpDecrypt(feeFEEDExp feed
,
638 const unsigned char *cipherText
,
639 unsigned cipherTextLen
,
640 unsigned char **plainText
, // malloc'd and RETURNED
641 unsigned *plainTextLen
) // RETURNED
643 const unsigned char *ctext
;
644 unsigned ctextLen
; // total to go
645 unsigned char *ptext
; // per block
646 unsigned ptextLen
; // per block
647 unsigned char *ptextResult
; // to return
648 unsigned char *ptextPtr
;
649 unsigned ptextLenTotal
; // running total
650 feeReturn frtn
= FR_Success
;
653 unsigned plainBlockSize
=
654 feeFEEDExpPlainBlockSize(feed
);
655 unsigned cipherBlockSize
=
656 feeFEEDExpCipherBlockSize(feed
);
658 if(cipherTextLen
% cipherBlockSize
) {
659 dbgLog(("feeFEEDExpDecrypt: unaligned cipherText\n"));
660 return FR_BadCipherText
;
662 if(cipherTextLen
== 0) {
663 dbgLog(("feeFEEDExpDecrypt: NULL cipherText\n"));
664 return FR_BadCipherText
;
667 ptext
= (unsigned char*) fmalloc(plainBlockSize
);
669 ctextLen
= cipherTextLen
;
670 numBlocks
= cipherTextLen
/ cipherBlockSize
;
671 ptextResult
= (unsigned char*) fmalloc(plainBlockSize
* numBlocks
);
672 ptextPtr
= ptextResult
;
676 if(ctextLen
== cipherBlockSize
) {
682 frtn
= feeFEEDExpDecryptBlock(feed
,
689 dbgLog(("feeFEEDExpDecryptBlock: %s\n",
690 feeReturnString(frtn
)));
695 * Normal termination case for
696 * plainTextLen % plainBlockSize == 0
699 dbgLog(("feeFEEDExpDecrypt: decrypt sync"
701 frtn
= FR_BadCipherText
;
705 else if(ptextLen
> plainBlockSize
) {
706 dbgLog(("feeFEEDExpDecrypt: ptext overflow!\n"));
711 bcopy(ptext
, ptextPtr
, ptextLen
);
712 ptextPtr
+= ptextLen
;
713 ptextLenTotal
+= ptextLen
;
715 ctext
+= cipherBlockSize
;
716 ctextLen
-= cipherBlockSize
;
726 *plainText
= ptextResult
;
727 *plainTextLen
= ptextLenTotal
;