]>
git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_cryptkit/lib/feeDigitalSignature.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 * feeDigitalSignature.c
16 * Changed to compile with C++.
18 * Major changes to use projective elliptic algebra for
21 * FEE_SIG_VERSION = 3 (removed code for compatibilty with all older
23 * Was modg(), is curveOrderJustify()
24 * Use plus curve for ellipic algebra per IEEE standards
26 * Ported guts of Blaine Garst's NSFEEDigitalSignature.m to C.
31 #include "feePublicKey.h"
32 #include "feePublicKeyPrivate.h"
33 #include "feeDigitalSignature.h"
34 #include "giantIntegers.h"
36 #include "feeRandom.h"
37 #include "curveParams.h"
39 #include "ckutilities.h"
44 #include "CryptKitDER.h"
47 #include "ellipticProj.h"
51 int sigDebug
= 1 ; // tweakable at runtime via debugger
54 #define SIG_CURVE DEFAULT_CURVE
57 * true : justify randGiant to [2, x1OrderPlus-2]
58 * false : no truncate or mod of randGiant
60 #define RAND_JUST_X1_ORDER_PLUS 1
62 #define FEE_SIG_VERSION 4
63 #define FEE_SIG_VERSION_MIN 4
66 #define max(a,b) ((a)>(b)? (a) : (b))
70 giant PmX
; // m 'o' P1; m = random
71 giant PmY
; // y-coord of m 'o' P1 if we're
72 // using projective coords
75 giant randGiant
; // random m as giant - only known
79 static sigInst
* sinstAlloc ()
81 sigInst
* sinst
= ( sigInst
*) fmalloc ( sizeof ( sigInst
));
83 bzero ( sinst
, sizeof ( sigInst
));
88 * Create new feeSig object, including a random large integer 'randGiant' for
89 * possible use in salting a feeHash object, and 'PmX', equal to
90 * randGiant 'o' P1. Note that this is not called when *verifying* a
91 * signature, only when signing.
93 feeSig
feeSigNewWithKey (
95 feeRandFcn randFcn
, /* optional */
98 sigInst
* sinst
= sinstAlloc ();
100 unsigned char * randBytes
;
101 unsigned randBytesLen
;
107 cp
= feePubKeyCurveParams ( pubKey
);
113 * Generate random m, a little larger than key size, save as randGiant
115 randBytesLen
= ( feePubKeyBitsize ( pubKey
) / 8 ) + 1 + 8 ; // +8bytes (64bits) to reduce the biais when with reduction mod prime. Per FIPS186-4 - "Using Extra Random Bits"
116 randBytes
= ( unsigned char *) fmalloc ( randBytesLen
);
118 randFcn ( randRef
, randBytes
, randBytesLen
);
121 frand
= feeRandAlloc ();
122 feeRandBytes ( frand
, randBytes
, randBytesLen
);
125 sinst
-> randGiant
= giant_with_data ( randBytes
, randBytesLen
);
126 memset ( randBytes
, 0 , randBytesLen
);
130 if ( isZero ( sinst
-> randGiant
)) {
131 printf ( "feeSigNewWithKey: randGiant = 0! \n " );
136 * Justify randGiant to be in [2, x1OrderPlus]
138 x1OrderPlusJustify ( sinst
-> randGiant
, cp
);
140 /* PmX := randGiant 'o' P1 */
141 sinst
-> PmX
= newGiant ( cp
-> maxDigits
);
143 if ( cp
-> curveType
== FCT_Weierstrass
) {
147 sinst
-> PmY
= newGiant ( cp
-> maxDigits
);
149 /* cook up pt0 as P1 */
152 pt0
. z
= borrowGiant ( cp
-> maxDigits
);
153 gtog ( cp
-> x1Plus
, pt0
. x
);
154 gtog ( cp
-> y1Plus
, pt0
. y
);
155 int_to_giant ( 1 , pt0
. z
);
157 /* pt0 := P1 'o' randGiant */
158 ellMulProjSimple (& pt0
, sinst
-> randGiant
, cp
);
163 #pragma clang diagnostic push
164 #pragma clang diagnostic ignored "-Wunreachable-code"
165 if ( SIG_CURVE
== CURVE_PLUS
) {
166 gtog ( cp
-> x1Plus
, sinst
-> PmX
);
169 gtog ( cp
-> x1Minus
, sinst
-> PmX
);
171 #pragma clang diagnostic pop
172 elliptic_simple ( sinst
-> PmX
, sinst
-> randGiant
, cp
);
178 void feeSigFree ( feeSig sig
)
180 sigInst
* sinst
= ( sigInst
*) sig
;
183 clearGiant ( sinst
-> PmX
);
184 freeGiant ( sinst
-> PmX
);
188 clearGiant ( sinst
-> PmY
);
189 freeGiant ( sinst
-> PmY
);
193 clearGiant ( sinst
-> u
);
196 if ( sinst
-> randGiant
) {
197 clearGiant ( sinst
-> randGiant
);
198 freeGiant ( sinst
-> randGiant
);
204 * Obtain Pm after feeSigNewWithKey() or feeSigParse()
206 unsigned char * feeSigPm ( feeSig sig
,
209 sigInst
* sinst
= ( sigInst
*) sig
;
212 if ( sinst
-> PmX
== NULL
) {
213 dbgLog (( "feeSigPm: no PmX! \n " ));
217 Pm
= mem_from_giant ( sinst
-> PmX
, PmLen
);
223 printf ( "Pm : " ); printGiant ( sinst
-> PmX
);
225 for ( i
= 0 ; i
<* PmLen
; i
++) {
226 printf ( " %x :" , Pm
[ i
]);
236 * Sign specified block of data (most likely a hash result) using
237 * specified feePubKey.
239 feeReturn
feeSigSign ( feeSig sig
,
240 const unsigned char * data
, // data to be signed
241 unsigned dataLen
, // in bytes
244 sigInst
* sinst
= ( sigInst
*) sig
;
245 giant messageGiant
= NULL
;
248 unsigned privGiantBytes
;
249 feeReturn frtn
= FR_Success
;
250 unsigned randBytesLen
;
251 unsigned uDigits
; // alloc'd digits in sinst->u
257 cp
= feePubKeyCurveParams ( pubKey
);
262 privGiant
= feePubKeyPrivData ( pubKey
);
263 if ( privGiant
== NULL
) {
264 dbgLog (( "Attempt to Sign without private data \n " ));
265 frtn
= FR_IllegalArg
;
268 privGiantBytes
= abs ( privGiant
-> sign
) * GIANT_BYTES_PER_DIGIT
;
271 * Note PmX = m 'o' P1.
272 * Get message/digest as giant. May be significantly different
273 * in size from pubKey's basePrime.
275 messageGiant
= giant_with_data ( data
, dataLen
); // M(text)
276 randBytesLen
= feePubKeyBitsize ( pubKey
) / 8 ;
277 maxlen
= max ( randBytesLen
, dataLen
);
279 /* leave plenty of room.... */
280 uDigits
= ( 3 * ( privGiantBytes
+ maxlen
)) / GIANT_BYTES_PER_DIGIT
;
281 sinst
-> u
= newGiant ( uDigits
);
282 gtog ( privGiant
, sinst
-> u
); // u := ourPri
283 mulg ( messageGiant
, sinst
-> u
); // u *= M(text)
284 addg ( sinst
-> randGiant
, sinst
-> u
); // u += m
287 * Paranoia: we're using the curveParams from the caller's pubKey;
288 * this cp will have a valid x1OrderPlusRecip if pubKey is the same
289 * as the one passed to feeSigNewWithKey() (since feeSigNewWithKey
290 * called x1OrderPlusJustify()). But the caller could conceivably be
291 * using a different instance of their pubKey, in which case
292 * the key's cp->x1OrderPlusRecip may not be valid.
294 calcX1OrderPlusRecip ( cp
);
296 /* u := u mod x1OrderPlus */
299 printf ( "sigSign: \n " );
300 printf ( "u pre-modg : " );
301 printGiant ( sinst
-> u
);
304 modg_via_recip ( cp
-> x1OrderPlus
, cp
-> x1OrderPlusRecip
, sinst
-> u
);
308 printf ( "privGiant : " );
309 printGiant ( privGiant
);
311 printGiant ( sinst
-> u
);
312 printf ( "messageGiant: " );
313 printGiant ( messageGiant
);
314 printf ( "curveParams : \n " );
315 printCurveParams ( cp
);
320 freeGiant ( messageGiant
);
326 * Given a feeSig processed by feeSigSign, obtain a malloc'd byte
327 * array representing the signature.
328 * See ByteRep.doc for info on the format of the signature string;
329 * PLEASE UPDATE THIS DOCUMENT WHEN YOU MAKE CHANGES TO THE STRING FORMAT.
331 feeReturn
feeSigData ( feeSig sig
,
332 unsigned char ** sigData
, // IGNORED....malloc'd and RETURNED
333 unsigned * sigDataLen
) // RETURNED
335 sigInst
* sinst
= ( sigInst
*) sig
;
337 return feeDEREncodeElGamalSignature ( sinst
-> u
, sinst
-> PmX
, sigData
, sigDataLen
);
342 * Obtain a feeSig object by parsing an existing signature block.
343 * Note that if Pm is used to salt a hash of the signed data, this must
344 * function must be called prior to hashing.
346 feeReturn
feeSigParse ( const unsigned char * sigData
,
348 feeSig
* sig
) // RETURNED
350 sigInst
* sinst
= NULL
;
353 sinst
= sinstAlloc ();
355 frtn
= feeDERDecodeElGamalSignature ( sigData
, sigDataLen
, & sinst
-> u
, & sinst
-> PmX
);
363 printf ( "sigParse: \n " );
365 printGiant ( sinst
-> u
);
380 * Verify signature, obtained via feeSigParse, for specified
381 * data (most likely a hash result) and feePubKey. Returns non-zero if
385 #define LOG_BAD_SIG 0
387 feeReturn
feeSigVerifyNoProj ( feeSig sig
,
388 const unsigned char * data
,
392 static void borrowPointProj ( pointProj pt
, unsigned maxDigits
)
394 pt
-> x
= borrowGiant ( maxDigits
);
395 pt
-> y
= borrowGiant ( maxDigits
);
396 pt
-> z
= borrowGiant ( maxDigits
);
399 static void returnPointProj ( pointProj pt
)
406 feeReturn
feeSigVerify ( feeSig sig
,
407 const unsigned char * data
,
412 giant messageGiant
= NULL
;
413 pointProjStruct scratch
;
414 sigInst
* sinst
= ( sigInst
*) sig
;
417 key origKey
; // may be plus or minus key
419 if ( sinst
-> PmX
== NULL
) {
420 dbgLog (( "sigVerify without parse! \n " ));
421 return FR_IllegalArg
;
424 cp
= feePubKeyCurveParams ( pubKey
);
425 if ( cp
-> curveType
!= FCT_Weierstrass
) {
426 return feeSigVerifyNoProj ( sig
, data
, dataLen
, pubKey
);
429 borrowPointProj (& Q
, cp
-> maxDigits
);
430 borrowPointProj (& scratch
, cp
-> maxDigits
);
435 gtog ( cp
-> x1Plus
, Q
. x
);
436 gtog ( cp
-> y1Plus
, Q
. y
);
437 int_to_giant ( 1 , Q
. z
);
439 messageGiant
= giant_with_data ( data
, dataLen
); // M(ciphertext)
442 ellMulProjSimple (& Q
, sinst
-> u
, cp
);
444 /* scratch := theirPub */
445 origKey
= feePubKeyPlusCurve ( pubKey
);
446 gtog ( origKey
-> x
, scratch
. x
);
447 gtog ( origKey
-> y
, scratch
. y
);
448 int_to_giant ( 1 , scratch
. z
);
452 printf ( "verify origKey: \n " );
454 printf ( "messageGiant: " );
455 printGiant ( messageGiant
);
456 printf ( "curveParams: \n " );
457 printCurveParams ( cp
);
461 /* scratch := M 'o' theirPub */
462 ellMulProjSimple (& scratch
, messageGiant
, cp
);
466 printf ( "signature_compare, with \n " );
469 printf ( "p1 = Pm: \n " );
470 printGiant ( sinst
-> PmX
);
471 printf ( "p2 = scratch = R: \n " );
472 printGiant ( scratch
. x
);
476 if ( signature_compare ( Q
. x
, sinst
-> PmX
, scratch
. x
, cp
)) {
478 frtn
= FR_InvalidSignature
;
480 printf ( "***yup, bad sig*** \n " );
481 #endif // LOG_BAD_SIG
486 freeGiant ( messageGiant
);
489 returnPointProj (& scratch
);
494 * FEE_SIG_USING_PROJ true : this is the "no Weierstrass" case
495 * feeSigVerifyNoProj false : this is redefined to feeSigVerify
497 feeReturn
feeSigVerifyNoProj ( feeSig sig
,
498 const unsigned char * data
,
503 giant messageGiant
= NULL
;
504 giant scratch
= NULL
;
505 sigInst
* sinst
= ( sigInst
*) sig
;
508 key origKey
; // may be plus or minus key
510 if ( sinst
-> PmX
== NULL
) {
511 dbgLog (( "sigVerify without parse! \n " ));
512 frtn
= FR_IllegalArg
;
516 cp
= feePubKeyCurveParams ( pubKey
);
517 Q
= newGiant ( cp
-> maxDigits
);
523 #pragma clang diagnostic push
524 #pragma clang diagnostic ignored "-Wunreachable-code"
525 if ( SIG_CURVE
== CURVE_PLUS
) {
526 origKey
= feePubKeyPlusCurve ( pubKey
);
530 origKey
= feePubKeyMinusCurve ( pubKey
);
531 gtog ( cp
-> x1Minus
, Q
);
533 #pragma clang diagnostic pop
535 messageGiant
= giant_with_data ( data
, dataLen
); // M(ciphertext)
538 elliptic_simple ( Q
, sinst
-> u
, cp
);
540 /* scratch := theirPub */
541 scratch
= newGiant ( cp
-> maxDigits
);
542 gtog ( origKey
-> x
, scratch
);
546 printf ( "verify origKey: \n " );
548 printf ( "messageGiant: " );
549 printGiant ( messageGiant
);
550 printf ( "curveParams: \n " );
551 printCurveParams ( cp
);
555 /* scratch := M 'o' theirPub */
556 elliptic_simple ( scratch
, messageGiant
, cp
);
560 printf ( "signature_compare, with \n " );
563 printf ( "p1 = Pm: \n " );
564 printGiant ( sinst
-> PmX
);
565 printf ( "p2 = scratch = R: \n " );
570 if ( signature_compare ( Q
, sinst
-> PmX
, scratch
, cp
)) {
572 frtn
= FR_InvalidSignature
;
574 printf ( "***yup, bad sig*** \n " );
575 #endif // LOG_BAD_SIG
581 if ( messageGiant
!= NULL
) {
582 freeGiant ( messageGiant
);
587 if ( scratch
!= NULL
) {
594 * For given key, calculate maximum signature size.
596 feeReturn
feeSigSize (
600 /* For now, assume that u and Pm.x in the signature are
601 * same size as the key's associated curveParams->basePrime.
602 * We might have to pad this a bit....
604 curveParams
* cp
= feePubKeyCurveParams ( pubKey
);
610 * maxSigLen
= feeSizeOfDERSig ( cp
-> basePrime
, cp
-> basePrime
);