]>
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.
35 #if CRYPTKIT_ASYMMETRIC_ENABLE
38 #include "feeFEEDExp.h"
39 #include "feePublicKey.h"
40 #include "feePublicKeyPrivate.h"
43 #include "feeRandom.h"
44 #include "ckutilities.h"
45 #include "feeFunctions.h"
52 #define PRINT_GIANT(g) printGiant(g)
55 * Format of clue byte. Currently just one bit.
57 #define CLUE_ELL_ADD_SIGN 0x01
58 #define CLUE_ELL_ADD_SIGN_PLUS 0x01
59 #define CLUE_ELL_ADD_SIGN_MINUS 0x00
67 unsigned plainBlockSize
; /* plaintext block size */
68 unsigned cipherBlockSize
;/* ciphertext block size */
70 giant gPriv
; /* private data, only for decrypt */
71 /* one of the follow two is valid for encrypt */
72 feeRand rand
; /* only created for encrypt */
77 * temporary variables used for encrypt/decrypt. The values in these
78 * is not needed to be kept from block to block; we just
79 * alloc them once per lifetime of a feeFEED object as an optimization.
81 giant xp
; /* plaintext */
82 giant xc
; /* clue = r(P1?) */
83 giant xq
; /* r(pubB?) or priB?(xc) */
84 giant xm
; /* ciphertext */
85 giant xaux
; /* scratch */
86 unsigned char *randData
; /* only created for encrypt */
90 * "zero residue" indicator.
92 #define RESID_ZERO 0xff
95 * Alloc and init a feeFEEDExp object associated with specified feePubKey.
97 feeFEEDExp
feeFEEDExpNewWithPubKey(
99 feeRandFcn randFcn
, // optional
102 feedInst
*finst
= (feedInst
*) fmalloc(sizeof(feedInst
));
105 finst
->cp
= curveParamsCopy(feePubKeyCurveParams(pubKey
));
106 finst
->plus
= new_public_with_key(feePubKeyPlusCurve(pubKey
),
108 finst
->minus
= new_public_with_key(feePubKeyMinusCurve(pubKey
),
112 * These might yield NULL data; we can only encrypt in that case.
114 privGiant
= feePubKeyPrivData(pubKey
);
116 finst
->gPriv
= newGiant(finst
->cp
->maxDigits
);
117 gtog(privGiant
, finst
->gPriv
);
124 * Conservative, rounding down, on plaintext blocks since we don't
125 * want to split bytes.
127 if(finst
->cp
->primeType
== FPT_General
) {
128 unsigned blen
= bitlen(finst
->cp
->basePrime
);
130 finst
->plainBlockSize
= blen
/ 8;
131 if((blen
% 8) == 0) {
133 * round down some more...
135 finst
->plainBlockSize
--;
139 finst
->plainBlockSize
= finst
->cp
->q
/ 8;
140 if(((finst
->cp
->q
& 0x7) == 0) && (finst
->cp
->k
> 0)) {
142 * Special case, with q mod 8 == 0. Here we have to trim back
143 * the plainBlockSize by one byte.
145 finst
->plainBlockSize
--;
150 * One block of ciphertext - two giants (with implied sign) and a
153 finst
->cipherBlockSize
= (2 * finst
->cp
->minBytes
) + 1;
155 finst
->xp
= newGiant(finst
->cp
->maxDigits
);
156 finst
->xc
= newGiant(finst
->cp
->maxDigits
);
157 finst
->xq
= newGiant(finst
->cp
->maxDigits
);
158 finst
->xm
= newGiant(finst
->cp
->maxDigits
);
159 finst
->xaux
= newGiant(finst
->cp
->maxDigits
);
161 finst
->randData
= NULL
;
162 finst
->randFcn
= randFcn
;
163 finst
->randRef
= randRef
;
167 void feeFEEDExpFree(feeFEEDExp feed
)
169 feedInst
*finst
= (feedInst
*) feed
;
171 free_key(finst
->plus
);
172 free_key(finst
->minus
);
173 freeGiant(finst
->xc
);
174 clearGiant(finst
->xp
); freeGiant(finst
->xp
);
175 clearGiant(finst
->xq
); freeGiant(finst
->xq
);
176 freeGiant(finst
->xm
);
177 clearGiant(finst
->xaux
); freeGiant(finst
->xaux
);
179 clearGiant(finst
->gPriv
);
180 freeGiant(finst
->gPriv
);
183 feeRandFree(finst
->rand
);
185 if(finst
->randData
) {
186 ffree(finst
->randData
);
189 freeCurveParams(finst
->cp
);
194 unsigned feeFEEDExpPlainBlockSize(feeFEEDExp feed
)
196 feedInst
*finst
= (feedInst
*) feed
;
198 return finst
->plainBlockSize
;
201 unsigned feeFEEDExpCipherBlockSize(feeFEEDExp feed
)
203 feedInst
*finst
= (feedInst
*) feed
;
205 return finst
->cipherBlockSize
;
208 unsigned feeFEEDExpCipherBufSize(feeFEEDExp feed
)
210 feedInst
*finst
= (feedInst
*) feed
;
212 return 2 * finst
->cipherBlockSize
;
216 * Return the size of ciphertext to hold specified size of plaintext.
218 unsigned feeFEEDExpCipherTextSize(feeFEEDExp feed
, unsigned plainTextSize
)
221 * Normal case is one block of ciphertext for each block of
222 * plaintext. Add one cipherBlock if
223 * plainTextSize % plainBlockSize == 0.
225 feedInst
*finst
= (feedInst
*) feed
;
226 unsigned blocks
= (plainTextSize
+ finst
->plainBlockSize
- 1) /
227 finst
->plainBlockSize
;
229 if((plainTextSize
% finst
->plainBlockSize
) == 0) {
232 return blocks
* finst
->cipherBlockSize
;
236 * Return the size of plaintext to hold specified size of decrypted ciphertext.
238 unsigned feeFEEDExpPlainTextSize(feeFEEDExp feed
, unsigned cipherTextSize
)
240 feedInst
*finst
= (feedInst
*) feed
;
241 unsigned blocks
= (cipherTextSize
+ finst
->cipherBlockSize
- 1) /
242 finst
->cipherBlockSize
;
244 return blocks
* finst
->plainBlockSize
;
248 * Encrypt a block or less of data. Caller malloc's cipherText.
250 feeReturn
feeFEEDExpEncryptBlock(feeFEEDExp feed
,
251 const unsigned char *plainText
,
252 unsigned plainTextLen
,
253 unsigned char *cipherText
,
254 unsigned *cipherTextLen
, // RETURNED
257 feedInst
*finst
= (feedInst
*) feed
;
258 int index
; /* which curve (+/- 1) */
259 char g
= 0; /* parity, which_curve bits in ciphertext */
261 unsigned char *ptext
; /* for final block */
263 feeReturn frtn
= FR_Success
;
266 curveParams
*cp
= finst
->cp
;
267 randLen
= cp
->minBytes
+8; // +8bytes (64bits) to reduce the biais when with reduction mod prime. Per FIPS186-4 - "Using Extra Random Bits"
269 if(plainTextLen
> finst
->plainBlockSize
) {
270 return FR_IllegalArg
;
272 else if ((plainTextLen
< finst
->plainBlockSize
) && !finalBlock
) {
273 return FR_IllegalArg
;
277 * Init only on first encrypt
279 if((finst
->randFcn
== NULL
) && (finst
->rand
== NULL
)) {
280 finst
->rand
= feeRandAlloc();
282 if(finst
->randData
== NULL
) {
283 finst
->randData
= (unsigned char*) fmalloc(randLen
);
287 * plaintext as giant xp
290 ptext
= (unsigned char*) fmalloc(finst
->plainBlockSize
);
291 bzero(ptext
, finst
->plainBlockSize
);
294 * 0 for empty block with resid length 0
296 bcopy(plainText
, ptext
, plainTextLen
);
298 if(plainTextLen
< finst
->plainBlockSize
) {
299 if(plainTextLen
== 0) {
301 * Special case - can't actually write zero here;
302 * it screws up deserializing the giant during
305 ptext
[finst
->plainBlockSize
- 1] = RESID_ZERO
;
308 ptext
[finst
->plainBlockSize
- 1] = plainTextLen
;
311 printf("encrypt: resid 0x%x\n", ptext
[finst
->plainBlockSize
- 1]);
315 * else handle evenly aligned case below...
317 deserializeGiant(ptext
, finst
->xp
, finst
->plainBlockSize
);
321 deserializeGiant(plainText
, finst
->xp
, plainTextLen
);
324 printf("encrypt:\n");
325 printf(" xp : "); PRINT_GIANT(finst
->xp
);
329 * pick curve B? that data lies upon
331 index
= which_curve(finst
->xp
, finst
->cp
);
332 if(index
== CURVE_PLUS
) {
334 x1
= finst
->cp
->x1Plus
;
338 x1
= finst
->cp
->x1Minus
;
341 printf(" which_curve: %s\n",
342 (index
== CURVE_PLUS
) ? "CURVE_PLUS" : "CURVE_MINUS");
346 * random number as giant xaux
348 if(finst
->randFcn
!= NULL
) {
349 finst
->randFcn(finst
->randRef
, finst
->randData
, randLen
);
352 feeRandBytes(finst
->rand
, finst
->randData
, randLen
);
354 deserializeGiant(finst
->randData
, finst
->xaux
, randLen
);
357 if(isZero(finst
->xaux
)) {
358 printf("feeFEEDExpEncryptBlock: random xaux = 0!\n");
362 * Justify random # to be in [2, minimumX1Order].
364 lesserX1OrderJustify(finst
->xaux
, cp
);
366 printf(" xaux: "); PRINT_GIANT(finst
->xaux
);
369 gtog(B
->x
, finst
->xq
); // xq = pubB?
370 elliptic_simple(finst
->xq
, finst
->xaux
, cp
);
373 printf(" r(pubB?): "); PRINT_GIANT(finst
->xq
);
375 elliptic_add(finst
->xp
, finst
->xq
, finst
->xm
, cp
, SIGN_PLUS
);
376 // xm = data + r(pubB?)
378 elliptic_simple(finst
->xc
, finst
->xaux
, cp
);
380 elliptic_add(finst
->xm
, finst
->xq
, finst
->xaux
, cp
, SIGN_PLUS
);
381 // xaux = xm + xq (for curve +1)
382 // = (data + r(pubB?)) + r(pubB?)
383 if(gcompg(finst
->xaux
, finst
->xp
) == 0) {
384 g
|= CLUE_ELL_ADD_SIGN_PLUS
;
387 g
|= CLUE_ELL_ADD_SIGN_MINUS
;
389 /* this better be true.... */
390 elliptic_add(finst
->xm
, finst
->xq
, finst
->xaux
, cp
, SIGN_MINUS
);
391 if(gcompg(finst
->xaux
, finst
->xp
)) {
392 printf("*******elliptic_add(xm, xq, -1) != xp! *************\n");
393 printf(" xq : "); PRINT_GIANT(finst
->xq
);
394 printf(" ell_add(xm, xq, -1) : "); PRINT_GIANT(finst
->xaux
);
397 } // g = (xaux == data) ? add : subtract
400 * Ciphertext = (xm, xc, g)
402 serializeGiant(finst
->xm
, cipherText
, cp
->minBytes
);
403 cipherText
+= cp
->minBytes
;
404 serializeGiant(finst
->xc
, cipherText
, cp
->minBytes
);
405 cipherText
+= cp
->minBytes
;
407 ctextLen
= finst
->cipherBlockSize
;
409 printf(" xm : "); PRINT_GIANT(finst
->xm
);
410 printf(" xc : "); PRINT_GIANT(finst
->xc
);
411 printf(" g : %d\n", g
);
413 if(finalBlock
&& (plainTextLen
== finst
->plainBlockSize
)) {
415 * Special case: finalBlock true, plainTextLen == blockSize.
416 * In this case we generate one more block of ciphertext,
417 * with a resid length of zero.
419 unsigned moreCipher
; // additional cipherLen
422 printf("encrypt: one more empty block\n");
424 frtn
= feeFEEDExpEncryptBlock(feed
,
425 NULL
, // plainText not used
427 cipherText
, // append...
430 if(frtn
== FR_Success
) {
431 ctextLen
+= moreCipher
;
435 *cipherTextLen
= ctextLen
;
440 * Decrypt (exactly) a block of data. Caller malloc's plainText. Always
441 * generates feeFEEDExpPlainBlockSize of plaintext, unless finalBlock is
442 * non-zero (in which case feeFEEDExpPlainBlockSize or less bytes of
443 * plainText are generated).
445 feeReturn
feeFEEDExpDecryptBlock(feeFEEDExp feed
,
446 const unsigned char *cipherText
,
447 unsigned cipherTextLen
,
448 unsigned char *plainText
,
449 unsigned *plainTextLen
, // RETURNED
452 feedInst
*finst
= (feedInst
*) feed
;
455 feeReturn frtn
= FR_Success
;
456 curveParams
*cp
= finst
->cp
;
458 if(finst
->gPriv
== NULL
) {
460 * Can't decrypt without private data
466 * grab xm, xc, and g from cipherText
468 deserializeGiant(cipherText
, finst
->xm
, finst
->cp
->minBytes
);
469 cipherText
+= finst
->cp
->minBytes
;
470 deserializeGiant(cipherText
, finst
->xc
, finst
->cp
->minBytes
);
471 cipherText
+= finst
->cp
->minBytes
;
474 printf("decrypt g=%d\n", g
);
475 printf(" privKey : "); PRINT_GIANT(finst
->gPriv
);
476 printf(" xm : "); PRINT_GIANT(finst
->xm
);
477 printf(" xc : "); PRINT_GIANT(finst
->xc
);
480 if((g
& CLUE_ELL_ADD_SIGN
) == CLUE_ELL_ADD_SIGN_PLUS
) {
489 * xc := r(P1?)(pri) = xq
490 * xp = data + r(priB+) +/- pri(rB?)
492 elliptic_simple(finst
->xc
, finst
->gPriv
, cp
);
494 printf(" xc1 : "); PRINT_GIANT(finst
->xc
);
496 elliptic_add(finst
->xm
, finst
->xc
, finst
->xp
, cp
, s
);
502 printf(" xp : "); PRINT_GIANT(finst
->xp
);
507 * Snag data from xp in order to find out how much to move to
510 unsigned char *ptext
= (unsigned char*) fmalloc(finst
->plainBlockSize
);
512 serializeGiant(finst
->xp
, ptext
, finst
->plainBlockSize
);
513 *plainTextLen
= ptext
[finst
->plainBlockSize
- 1];
515 printf("decrypt: resid 0x%x\n", *plainTextLen
);
517 if(*plainTextLen
== RESID_ZERO
) {
520 else if(*plainTextLen
> (finst
->plainBlockSize
- 1)) {
521 dbgLog(("feeFEEDExpDecryptBlock: ptext overflow!\n"));
522 frtn
= FR_BadCipherText
;
525 bcopy(ptext
, plainText
, *plainTextLen
);
530 *plainTextLen
= finst
->plainBlockSize
;
531 serializeGiant(finst
->xp
, plainText
, *plainTextLen
);
537 * Convenience routines to encrypt & decrypt multi-block data.
539 feeReturn
feeFEEDExpEncrypt(feeFEEDExp feed
,
540 const unsigned char *plainText
,
541 unsigned plainTextLen
,
542 unsigned char **cipherText
, // malloc'd and RETURNED
543 unsigned *cipherTextLen
) // RETURNED
545 const unsigned char *ptext
; // per block
546 unsigned ptextLen
; // total to go
547 unsigned thisPtextLen
; // per block
548 unsigned char *ctext
; // per block
549 unsigned ctextLen
; // per block
550 unsigned char *ctextResult
; // to return
551 unsigned ctextResultLen
;
552 unsigned char *ctextPtr
;
553 unsigned ctextLenTotal
; // running total
557 unsigned plainBlockSize
;
559 if(plainTextLen
== 0) {
560 dbgLog(("feeFEEDExpDecrypt: NULL plainText\n"));
561 return FR_IllegalArg
;
565 ptextLen
= plainTextLen
;
566 ctext
= (unsigned char*) fmalloc(feeFEEDExpCipherBufSize(feed
));
567 plainBlockSize
= feeFEEDExpPlainBlockSize(feed
);
568 numBlocks
= (plainTextLen
+ plainBlockSize
- 1)/plainBlockSize
;
569 ctextResultLen
= (numBlocks
+ 1) * feeFEEDExpCipherBlockSize(feed
);
570 ctextResult
= (unsigned char*) fmalloc(ctextResultLen
);
571 ctextPtr
= ctextResult
;
575 if(ptextLen
<= plainBlockSize
) {
577 thisPtextLen
= ptextLen
;
581 thisPtextLen
= plainBlockSize
;
583 frtn
= feeFEEDExpEncryptBlock(feed
,
590 dbgLog(("feeFEEDExpEncrypt: encrypt error: %s\n",
591 feeReturnString(frtn
)));
595 dbgLog(("feeFEEDExpEncrypt: null ciphertext\n"));
599 bcopy(ctext
, ctextPtr
, ctextLen
);
600 ctextLenTotal
+= ctextLen
;
601 if(ctextLenTotal
> ctextResultLen
) {
602 dbgLog(("feeFEEDExpEncrypt: ciphertext overflow\n"));
609 ctextPtr
+= ctextLen
;
610 ptext
+= thisPtextLen
;
611 ptextLen
-= thisPtextLen
;
621 *cipherText
= ctextResult
;
622 *cipherTextLen
= ctextLenTotal
;
624 if(feeFEEDExpCipherTextSize(feed
, plainTextLen
) !=
626 printf("feeFEEDExpEncrypt: feeFEEDCipherTextSize "
628 printf("ptext %d exp ctext %d actual ctext %d\n",
630 feeFEEDExpCipherTextSize(feed
, plainTextLen
),
639 feeReturn
feeFEEDExpDecrypt(feeFEEDExp feed
,
640 const unsigned char *cipherText
,
641 unsigned cipherTextLen
,
642 unsigned char **plainText
, // malloc'd and RETURNED
643 unsigned *plainTextLen
) // RETURNED
645 const unsigned char *ctext
;
646 unsigned ctextLen
; // total to go
647 unsigned char *ptext
; // per block
648 unsigned ptextLen
; // per block
649 unsigned char *ptextResult
; // to return
650 unsigned char *ptextPtr
;
651 unsigned ptextLenTotal
; // running total
652 feeReturn frtn
= FR_Success
;
655 unsigned plainBlockSize
=
656 feeFEEDExpPlainBlockSize(feed
);
657 unsigned cipherBlockSize
=
658 feeFEEDExpCipherBlockSize(feed
);
660 if(cipherTextLen
% cipherBlockSize
) {
661 dbgLog(("feeFEEDExpDecrypt: unaligned cipherText\n"));
662 return FR_BadCipherText
;
664 if(cipherTextLen
== 0) {
665 dbgLog(("feeFEEDExpDecrypt: NULL cipherText\n"));
666 return FR_BadCipherText
;
669 ptext
= (unsigned char*) fmalloc(plainBlockSize
);
671 ctextLen
= cipherTextLen
;
672 numBlocks
= cipherTextLen
/ cipherBlockSize
;
673 ptextResult
= (unsigned char*) fmalloc(plainBlockSize
* numBlocks
);
674 ptextPtr
= ptextResult
;
678 if(ctextLen
== cipherBlockSize
) {
684 frtn
= feeFEEDExpDecryptBlock(feed
,
691 dbgLog(("feeFEEDExpDecryptBlock: %s\n",
692 feeReturnString(frtn
)));
697 * Normal termination case for
698 * plainTextLen % plainBlockSize == 0
701 dbgLog(("feeFEEDExpDecrypt: decrypt sync"
703 frtn
= FR_BadCipherText
;
707 else if(ptextLen
> plainBlockSize
) {
708 dbgLog(("feeFEEDExpDecrypt: ptext overflow!\n"));
713 bcopy(ptext
, ptextPtr
, ptextLen
);
714 ptextPtr
+= ptextLen
;
715 ptextLenTotal
+= ptextLen
;
717 ctext
+= cipherBlockSize
;
718 ctextLen
-= cipherBlockSize
;
728 *plainText
= ptextResult
;
729 *plainTextLen
= ptextLenTotal
;
735 #endif /* CRYPTKIT_ASYMMETRIC_ENABLE */