]>
git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_cryptkit/lib/feeECDSA.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 * feeECDSA.c - Elliptic Curve Digital Signature Algorithm (per IEEE 1363)
16 * Added ECDSA_VERIFY_ONLY dependencies.
18 * Changed to compile with C++.
20 * Rewrote using projective elliptic algebra, per IEEE P1363.
22 * Fixed c==0 bug in feeECDSAVerify()
27 Nomenclature, per IEEE P1363 D1, Dec. 1997
29 G = initial public point = (x1Plus, y1Plus) as usual
30 x1OrderPlus = IEEE r = (always prime) order of x1Plus
31 f = message to be signed, generally a SHA1 message digest
32 s = signer's private key
33 W = signer's public key
34 * : integer multiplication, as in (x * y)
35 'o' : elliptic multiply, as in (u 'o' G)
39 1) Obtain random u in [2, x1OrderPlus-2];
40 2) Compute x coordinate, call it c, of u 'o' G (elliptic mul);
41 3) Reduce: c := c mod x1OrderPlus;
42 4) If c = 0, goto (1);
43 5) Compute u^(-1) (mod x1OrderPlus);
44 6) Compute signature s as:
46 d = [u^(-1) (f + (s*c))] (mod x1OrderPlus)
48 7) If d = 0, goto (1);
49 8) Signature is the integer pair (c, d). Each integer
50 in the pair must be in [1, x1OrderPlus-1].
52 Note: therefore a component of the signature could be slightly
53 larger than base prime.
55 Verification algorithm, given signature (c, d):
57 1) Compute h = d^(-1) (mod x1OrderPlus);
58 2) Compute h1 = digest as giant integer (skips assigning to 'f' as in
60 3) Compute h1 = h1 * h (mod x1OrderPlus) (i.e., = f * h)
61 4) Compute h2 = c * h (mod x1OrderPlus);
62 5) Compute h2W = h2 'o' W
63 6) Compute h1G = h1 'o' G
64 7) Compute elliptic sum of h1G + h2W
65 8) If elliptic sum is point at infinity, signature is bad; stop.
66 9) cPrime = x coordinate of elliptic sum, mod x1OrderPlus
67 10) Signature is good iff cPrime == c.
74 #include "feePublicKey.h"
75 #include "feePublicKeyPrivate.h"
76 #include "giantIntegers.h"
78 #include "feeRandom.h"
79 #include "curveParams.h"
81 #include "ckutilities.h"
88 #include "feeDigitalSignature.h"
89 #include "ECDSA_Profile.h"
90 #include "ellipticProj.h"
91 #include "CryptKitDER.h"
93 #ifndef ECDSA_VERIFY_ONLY
94 static void ECDSA_encode(
95 feeSigFormat format
, // Signature format DER 9.62 / RAW
96 unsigned groupBytesLen
,
99 unsigned char **sigData
, // malloc'd and RETURNED
100 unsigned *sigDataLen
); // RETURNED
101 #endif /* ECDSA_VERIFY_ONLY */
103 static feeReturn
ECDSA_decode(
104 feeSigFormat format
, // Signature format DER 9.62 / RAW
105 unsigned groupBytesLen
,
106 const unsigned char *sigData
,
108 giant
*gs
, // alloc'd & RETURNED
109 giant
*x0
, // alloc'd & RETURNED
110 unsigned *sigVersion
); // RETURNED
113 #define ECDSA_DEBUG 0
115 int ecdsaDebug
=1; /* tweakable at runtime via debugger */
120 #define sigLogGiant(s, g) \
123 printGiant(g) /*printGiantExp(g)*/; \
127 #define sigLogGiant(s, g)
128 #endif // ECDSA_DEBUG
132 * Profiling accumulators.
147 #endif // ECDSA_PROFILE
150 * Totally incompatible with feeDigitalSignature.c. Caller must be aware of
151 * signature format. We will detect an ElGamal signature, however, and
152 * return FR_WrongSignatureType from feeECDSAVerify().
154 #define FEE_ECDSA_VERSION 2
155 #define FEE_ECDSA_VERSION_MIN 2
158 * When true, use ellMulProjSimple rather than elliptic_simple in
159 * sign operation. Using ellMulProjSimple is a *big* win.
161 #define ECDSA_SIGN_USE_PROJ 1
164 * Sign specified block of data (most likely a hash result) using
165 * specified private key. Result, an enc64-encoded signature block,
166 * is returned in *sigData.
169 #ifndef ECDSA_VERIFY_ONLY
171 feeReturn
feeECDSASign(
173 feeSigFormat format
, // Signature format DER 9.62 / RAW
174 const unsigned char *data
, // data to be signed
175 unsigned dataLen
, // in bytes
176 feeRandFcn randFcn
, // optional
177 void *randRef
, // optional
178 unsigned char **sigData
, // malloc'd and RETURNED
179 unsigned *sigDataLen
) // RETURNED
183 /* giant integers per IEEE P1363 notation */
185 giant c
; // both 1363 'c' and 'i'
186 // i.e., x-coord of u's pub key
188 giant u
; // random private key
189 giant s
; // private key as giant
190 giant f
; // data (message) as giant
192 feeReturn frtn
= FR_Success
;
194 unsigned char *randBytes
;
195 unsigned randBytesLen
;
196 unsigned groupBytesLen
;
198 #if ECDSA_SIGN_USE_PROJ
199 pointProjStruct pt
; // pt->x = c
202 #endif // ECDSA_SIGN_USE_PROJ
207 cp
= feePubKeyCurveParams(pubKey
);
211 if(cp
->curveType
!= FCT_Weierstrass
) {
212 return FR_IllegalCurve
;
215 CKASSERT(!isZero(cp
->x1OrderPlus
));
218 * Private key and message to be signed as giants
220 privGiant
= feePubKeyPrivData(pubKey
);
221 if(privGiant
== NULL
) {
222 dbgLog(("Attempt to Sign without private data\n"));
223 return FR_IllegalArg
;
225 s
= borrowGiant(cp
->maxDigits
);
227 if(dataLen
> (cp
->maxDigits
* GIANT_BYTES_PER_DIGIT
)) {
228 f
= borrowGiant(BYTES_TO_GIANT_DIGITS(dataLen
));
231 f
= borrowGiant(cp
->maxDigits
);
233 deserializeGiant(data
, f
, dataLen
);
236 * Certicom SEC1 states that if the digest is larger than the modulus,
237 * use the left q bits of the digest.
239 unsigned hashBits
= dataLen
* 8;
240 if(hashBits
> cp
->q
) {
241 gshiftright(hashBits
- cp
->q
, f
);
244 sigDbg(("ECDSA sign:\n"));
245 sigLogGiant(" s : ", s
);
246 sigLogGiant(" f : ", f
);
248 c
= borrowGiant(cp
->maxDigits
);
249 d
= borrowGiant(cp
->maxDigits
);
250 u
= borrowGiant(cp
->maxDigits
);
251 if(randFcn
== NULL
) {
252 frand
= feeRandAlloc();
259 * Random size is just larger than base prime
261 groupBytesLen
= ((feePubKeyBitsize(pubKey
)+7) / 8);
262 randBytesLen
= groupBytesLen
+8; // +8bytes (64bits) to reduce the biais when with reduction mod prime. Per FIPS186-4 - "Using Extra Random Bits"
263 randBytes
= (unsigned char*) fmalloc(randBytesLen
);
265 #if ECDSA_SIGN_USE_PROJ
266 /* quick temp pointProj */
267 pty
= borrowGiant(cp
->maxDigits
);
268 ptz
= borrowGiant(cp
->maxDigits
);
272 #endif // ECDSA_SIGN_USE_PROJ
275 /* Repeat this loop until we have a non-zero c and d */
278 * 1) Obtain random u in [2, x1OrderPlus-2]
282 randFcn(randRef
, randBytes
, randBytesLen
);
285 feeRandBytes(frand
, randBytes
, randBytesLen
);
287 deserializeGiant(randBytes
, u
, randBytesLen
);
288 sigLogGiant(" raw u : ", u
);
289 sigLogGiant(" order : ", cp
->x1OrderPlus
);
290 x1OrderPlusJustify(u
, cp
);
291 SIGPROF_END(signStep1
);
292 sigLogGiant(" in range u : ", u
);
295 * note 'o' indicates elliptic multiply, * is integer mult.
297 * 2) Compute x coordinate, call it c, of u 'o' G
298 * 3) Reduce: c := c mod x1OrderPlus;
299 * 4) If c == 0, goto (1);
304 #if ECDSA_SIGN_USE_PROJ
306 /* projective coordinates */
307 gtog(cp
->y1Plus
, pty
);
308 int_to_giant(1, ptz
);
309 ellMulProjSimple(&pt
, u
, cp
);
311 #else /* ECDSA_SIGN_USE_PROJ */
314 elliptic_simple(c
, u
, cp
);
316 #endif /* ECDSA_SIGN_USE_PROJ */
318 SIGPROF_END(signStep2
);
320 x1OrderPlusMod(c
, cp
);
321 SIGPROF_END(signStep34
);
323 dbgLog(("feeECDSASign: zero modulo (1)\n"));
328 * 5) Compute u^(-1) mod x1OrderPlus;
332 binvg_x1OrderPlus(cp
, d
);
333 SIGPROF_END(signStep5
);
334 sigLogGiant(" u^(-1) : ", d
);
337 * 6) Compute signature d as:
338 * d = [u^(-1) (f + s*c)] (mod x1OrderPlus)
341 mulg(c
, s
); // s *= c
342 x1OrderPlusMod(s
, cp
);
343 addg(f
, s
); // s := f + (s * c)
344 x1OrderPlusMod(s
, cp
);
345 mulg(s
, d
); // d := u^(-1) (f + (s * c))
346 x1OrderPlusMod(d
, cp
);
347 SIGPROF_END(signStep67
);
350 * 7) If d = 0, goto (1);
353 dbgLog(("feeECDSASign: zero modulo (2)\n"));
356 sigLogGiant(" c : ", c
);
357 sigLogGiant(" d : ", d
);
358 break; // normal successful exit
362 * 8) signature is now the integer pair (c, d).
366 * Cook up raw data representing the signature.
369 ECDSA_encode(format
,groupBytesLen
, c
, d
, sigData
, sigDataLen
);
370 SIGPROF_END(signStep8
);
381 #if ECDSA_SIGN_USE_PROJ
384 #endif /* ECDSA_SIGN_USE_PROJ */
388 #endif /* ECDSA_VERIFY_ONLY */
391 * Verify signature for specified data (most likely a hash result) and
392 * feePubKey. Returns FR_Success or FR_InvalidSignature.
395 #define LOG_BAD_SIG 0
397 feeReturn
feeECDSAVerify(const unsigned char *sigData
,
399 const unsigned char *data
,
404 /* giant integers per IEEE P1363 notation */
407 giant h2
; // c times h
408 giant littleC
; // newGiant from ECDSA_decode
409 giant littleD
; // ditto
410 giant c
; // borrowed, full size
412 giant cPrime
= NULL
; // i mod r
413 pointProj h1G
= NULL
; // h1 'o' G
414 pointProj h2W
= NULL
; // h2 'o' W
415 key W
; // i.e., their public key
419 curveParams
*cp
= feePubKeyCurveParams(pubKey
);
420 unsigned groupBytesLen
= ((feePubKeyBitsize(pubKey
)+7) / 8);
428 * First decode the byteRep string.
443 * littleC and littleD have capacity = abs(sign), probably
446 c
= borrowGiant(cp
->maxDigits
);
447 d
= borrowGiant(cp
->maxDigits
);
453 sigDbg(("ECDSA verify:\n"));
456 * Verify that c and d are within [1,group_order-1]
458 if((gcompg(cp
->cOrderPlus
, c
) != 1) || (gcompg(cp
->cOrderPlus
, d
) != 1) ||
459 isZero(c
) || isZero(d
))
463 return FR_InvalidSignature
;
467 * W = signer's public key
469 W
= feePubKeyPlusCurve(pubKey
);
472 * 1) Compute h = d^(-1) (mod x1OrderPlus);
475 h
= borrowGiant(cp
->maxDigits
);
477 binvg_x1OrderPlus(cp
, h
);
478 SIGPROF_END(vfyStep1
);
481 * 2) h1 = digest as giant (skips assigning to 'f' in P1363)
483 if(dataLen
> (cp
->maxDigits
* GIANT_BYTES_PER_DIGIT
)) {
484 h1
= borrowGiant(BYTES_TO_GIANT_DIGITS(dataLen
));
487 h1
= borrowGiant(cp
->maxDigits
);
489 deserializeGiant(data
, h1
, dataLen
);
492 * Certicom SEC1 states that if the digest is larger than the modulus,
493 * use the left q bits of the digest.
495 unsigned hashBits
= dataLen
* 8;
496 if(hashBits
> cp
->q
) {
497 gshiftright(hashBits
- cp
->q
, h1
);
500 sigLogGiant(" Wx : ", W
->x
);
501 sigLogGiant(" f : ", h1
);
502 sigLogGiant(" c : ", c
);
503 sigLogGiant(" d : ", d
);
504 sigLogGiant(" s^(-1) : ", h
);
507 * 3) Compute h1 = f * h mod x1OrderPlus;
510 mulg(h
, h1
); // h1 := f * h
511 x1OrderPlusMod(h1
, cp
);
512 SIGPROF_END(vfyStep3
);
515 * 4) Compute h2 = c * h (mod x1OrderPlus);
518 h2
= borrowGiant(cp
->maxDigits
);
520 mulg(h
, h2
); // h2 := c * h
521 x1OrderPlusMod(h2
, cp
);
522 SIGPROF_END(vfyStep4
);
525 * 5) Compute h2W = h2 'o' W (W = theirPub)
527 CKASSERT((W
->y
!= NULL
) && !isZero(W
->y
));
528 h2W
= newPointProj(cp
->maxDigits
);
531 int_to_giant(1, h2W
->z
);
532 ellMulProjSimple(h2W
, h2
, cp
);
535 * 6) Compute h1G = h1 'o' G (G = {x1Plus, y1Plus, 1} )
537 CKASSERT((cp
->y1Plus
!= NULL
) && !isZero(cp
->y1Plus
));
538 h1G
= newPointProj(cp
->maxDigits
);
539 gtog(cp
->x1Plus
, h1G
->x
);
540 gtog(cp
->y1Plus
, h1G
->y
);
541 int_to_giant(1, h1G
->z
);
542 ellMulProjSimple(h1G
, h1
, cp
);
545 * 7) h1G := (h1 'o' G) + (h2 'o' W)
547 ellAddProj(h1G
, h2W
, cp
);
550 * 8) If elliptic sum is point at infinity, signature is bad; stop.
553 dbgLog(("feeECDSAVerify: h1 * G = point at infinity\n"));
557 normalizeProj(h1G
, cp
);
560 * 9) cPrime = x coordinate of elliptic sum, mod x1OrderPlus
562 cPrime
= borrowGiant(cp
->maxDigits
);
563 gtog(h1G
->x
, cPrime
);
564 x1OrderPlusMod(cPrime
, cp
);
567 * 10) Good sig iff cPrime == c
569 result
= gcompg(c
, cPrime
);
573 frtn
= FR_InvalidSignature
;
575 printf("***yup, bad sig***\n");
576 #endif // LOG_BAD_SIG
599 #ifndef ECDSA_VERIFY_ONLY
602 * Encode to/from byteRep.
604 static void ECDSA_encode(
605 feeSigFormat format
, // Signature format DER 9.62 / RAW
606 unsigned groupBytesLen
,
609 unsigned char **sigData
, // malloc'd and RETURNED
610 unsigned *sigDataLen
) // RETURNED
612 if (format
==FSF_RAW
) {
613 feeRAWEncodeECDSASignature(groupBytesLen
,c
, d
, sigData
, sigDataLen
);
615 feeDEREncodeECDSASignature(c
, d
, sigData
, sigDataLen
);
619 #endif /* ECDSA_VERIFY_ONLY */
621 static feeReturn
ECDSA_decode(
622 feeSigFormat format
, // Signature format DER 9.62 / RAW
623 unsigned groupBytesLen
,
624 const unsigned char *sigData
,
626 giant
*c
, // alloc'd & RETURNED
627 giant
*d
, // alloc'd & RETURNED
628 unsigned *sigVersion
) // RETURNED
631 if (format
==FSF_RAW
) {
632 frtn
= feeRAWDecodeECDSASignature(groupBytesLen
, sigData
, sigDataLen
, c
, d
);
634 frtn
= feeDERDecodeECDSASignature(sigData
, sigDataLen
, c
, d
);
636 if(frtn
== FR_Success
) {
637 *sigVersion
= FEE_ECDSA_VERSION
;
643 * For given key, calculate maximum signature size.
645 feeReturn
feeECDSASigSize(
649 /* For now, assume that c and d in the signature are
650 * same size as the key's associated curveParams->basePrime.
651 * We might have to pad this a bit....
653 curveParams
*cp
= feePubKeyCurveParams(pubKey
);
659 *maxSigLen
= feeSizeOfDERSig(cp
->basePrime
, cp
->basePrime
);