-/* Copyright (c) 1998,2011,2014 Apple Inc. All Rights Reserved.
- *
- * NOTICE: USE OF THE MATERIALS ACCOMPANYING THIS NOTICE IS SUBJECT
- * TO THE TERMS OF THE SIGNED "FAST ELLIPTIC ENCRYPTION (FEE) REFERENCE
- * SOURCE CODE EVALUATION AGREEMENT" BETWEEN APPLE, INC. AND THE
- * ORIGINAL LICENSEE THAT OBTAINED THESE MATERIALS FROM APPLE,
- * INC. ANY USE OF THESE MATERIALS NOT PERMITTED BY SUCH AGREEMENT WILL
- * EXPOSE YOU TO LIABILITY.
- ***************************************************************************
- *
- * feeDigitalSignature.c
- *
- * Revision History
- * ----------------
- * 10/06/98 ap
- * Changed to compile with C++.
- * 9 Sep 98 at NeXT
- * Major changes to use projective elliptic algebra for
- * Weierstrass curves.
- * 15 Jan 97 at NeXT
- * FEE_SIG_VERSION = 3 (removed code for compatibilty with all older
- * versions).
- * Was modg(), is curveOrderJustify()
- * Use plus curve for ellipic algebra per IEEE standards
- * 22 Aug 96 at NeXT
- * Ported guts of Blaine Garst's NSFEEDigitalSignature.m to C.
- */
-
-#include "ckconfig.h"
-#include "feeTypes.h"
-#include "feePublicKey.h"
-#include "feePublicKeyPrivate.h"
-#include "feeDigitalSignature.h"
-#include "giantIntegers.h"
-#include "elliptic.h"
-#include "feeRandom.h"
-#include "curveParams.h"
-#include "falloc.h"
-#include "ckutilities.h"
-#include "feeDebug.h"
-#include "platform.h"
-#include "byteRep.h"
-#include "feeECDSA.h"
-#if CRYPTKIT_DER_ENABLE
-#include "CryptKitDER.h"
-#endif
-
-#include <stdlib.h>
-#include "ellipticProj.h"
-
-#define SIG_DEBUG 0
-#if SIG_DEBUG
-int sigDebug=1; // tweakable at runtime via debugger
-#endif // SIG_DEBUG
-
-#define SIG_CURVE DEFAULT_CURVE
-
-/*
- * true : justify randGiant to [2, x1OrderPlus-2]
- * false : no truncate or mod of randGiant
- */
-#define RAND_JUST_X1_ORDER_PLUS 1
-
-#define FEE_SIG_VERSION 4
-#define FEE_SIG_VERSION_MIN 4
-
-#ifndef max
-#define max(a,b) ((a)>(b)? (a) : (b))
-#endif // max
-
-typedef struct {
- giant PmX; // m 'o' P1; m = random
- #if CRYPTKIT_ELL_PROJ_ENABLE
- giant PmY; // y-coord of m 'o' P1 if we're
- // using projective coords
- #endif /* CRYPTKIT_ELL_PROJ_ENABLE */
-
- giant u;
- giant randGiant; // random m as giant - only known
- // when signing
-} sigInst;
-
-static sigInst *sinstAlloc()
-{
- sigInst *sinst = (sigInst*) fmalloc(sizeof(sigInst));
-
- bzero(sinst, sizeof(sigInst));
- return sinst;
-}
-
-/*
- * Create new feeSig object, including a random large integer 'randGiant' for
- * possible use in salting a feeHash object, and 'PmX', equal to
- * randGiant 'o' P1. Note that this is not called when *verifying* a
- * signature, only when signing.
- */
-feeSig feeSigNewWithKey(
- feePubKey pubKey,
- feeRandFcn randFcn, /* optional */
- void *randRef)
-{
- sigInst *sinst = sinstAlloc();
- feeRand frand;
- unsigned char *randBytes;
- unsigned randBytesLen;
- curveParams *cp;
-
- if(pubKey == NULL) {
- return NULL;
- }
- cp = feePubKeyCurveParams(pubKey);
- if(cp == NULL) {
- return NULL;
- }
-
- /*
- * Generate random m, a little larger than key size, save as randGiant
- */
- randBytesLen = (feePubKeyBitsize(pubKey) / 8) + 1;
- randBytes = (unsigned char*) fmalloc(randBytesLen);
- if(randFcn) {
- randFcn(randRef, randBytes, randBytesLen);
- }
- else {
- frand = feeRandAlloc();
- feeRandBytes(frand, randBytes, randBytesLen);
- feeRandFree(frand);
- }
- sinst->randGiant = giant_with_data(randBytes, randBytesLen);
- memset(randBytes, 0, randBytesLen);
- ffree(randBytes);
-
- #if FEE_DEBUG
- if(isZero(sinst->randGiant)) {
- printf("feeSigNewWithKey: randGiant = 0!\n");
- }
- #endif // FEE_DEBUG
-
- /*
- * Justify randGiant to be in [2, x1OrderPlus]
- */
- x1OrderPlusJustify(sinst->randGiant, cp);
-
- /* PmX := randGiant 'o' P1 */
- sinst->PmX = newGiant(cp->maxDigits);
-
- #if CRYPTKIT_ELL_PROJ_ENABLE
-
- if(cp->curveType == FCT_Weierstrass) {
-
- pointProjStruct pt0;
-
- sinst->PmY = newGiant(cp->maxDigits);
-
- /* cook up pt0 as P1 */
- pt0.x = sinst->PmX;
- pt0.y = sinst->PmY;
- pt0.z = borrowGiant(cp->maxDigits);
- gtog(cp->x1Plus, pt0.x);
- gtog(cp->y1Plus, pt0.y);
- int_to_giant(1, pt0.z);
-
- /* pt0 := P1 'o' randGiant */
- ellMulProjSimple(&pt0, sinst->randGiant, cp);
-
- returnGiant(pt0.z);
- }
- else {
- if(SIG_CURVE == CURVE_PLUS) {
- gtog(cp->x1Plus, sinst->PmX);
- }
- else {
- gtog(cp->x1Minus, sinst->PmX);
- }
- elliptic_simple(sinst->PmX, sinst->randGiant, cp);
- }
- #else /* CRYPTKIT_ELL_PROJ_ENABLE */
-
- if(SIG_CURVE == CURVE_PLUS) {
- gtog(cp->x1Plus, sinst->PmX);
- }
- else {
- gtog(cp->x1Minus, sinst->PmX);
- }
- elliptic_simple(sinst->PmX, sinst->randGiant, cp);
-
- #endif /* CRYPTKIT_ELL_PROJ_ENABLE */
-
- return sinst;
-}
-
-void feeSigFree(feeSig sig)
-{
- sigInst *sinst = (sigInst*) sig;
-
- if(sinst->PmX) {
- clearGiant(sinst->PmX);
- freeGiant(sinst->PmX);
- }
- #if CRYPTKIT_ELL_PROJ_ENABLE
- if(sinst->PmY) {
- clearGiant(sinst->PmY);
- freeGiant(sinst->PmY);
- }
- #endif /* CRYPTKIT_ELL_PROJ_ENABLE */
- if(sinst->u) {
- clearGiant(sinst->u);
- freeGiant(sinst->u);
- }
- if(sinst->randGiant) {
- clearGiant(sinst->randGiant);
- freeGiant(sinst->randGiant);
- }
- ffree(sinst);
-}
-
-/*
- * Obtain Pm after feeSigNewWithKey() or feeSigParse()
- */
-unsigned char *feeSigPm(feeSig sig,
- unsigned *PmLen)
-{
- sigInst *sinst = (sigInst*) sig;
- unsigned char *Pm;
-
- if(sinst->PmX == NULL) {
- dbgLog(("feeSigPm: no PmX!\n"));
- return NULL;
- }
- else {
- Pm = mem_from_giant(sinst->PmX, PmLen);
- #if SIG_DEBUG
- if(sigDebug)
- {
- int i;
-
- printf("Pm : "); printGiant(sinst->PmX);
- printf("PmData: ");
- for(i=0; i<*PmLen; i++) {
- printf("%x:", Pm[i]);
- }
- printf("\n");
- }
- #endif // SIG_DEBUG
- }
- return Pm;
-}
-
-/*
- * Sign specified block of data (most likely a hash result) using
- * specified feePubKey.
- */
-feeReturn feeSigSign(feeSig sig,
- const unsigned char *data, // data to be signed
- unsigned dataLen, // in bytes
- feePubKey pubKey)
-{
- sigInst *sinst = (sigInst*) sig;
- giant messageGiant = NULL;
- unsigned maxlen;
- giant privGiant;
- unsigned privGiantBytes;
- feeReturn frtn = FR_Success;
- unsigned randBytesLen;
- unsigned uDigits; // alloc'd digits in sinst->u
- curveParams *cp;
-
- if(pubKey == NULL) {
- return FR_BadPubKey;
- }
- cp = feePubKeyCurveParams(pubKey);
- if(cp == NULL) {
- return FR_BadPubKey;
- }
-
- privGiant = feePubKeyPrivData(pubKey);
- if(privGiant == NULL) {
- dbgLog(("Attempt to Sign without private data\n"));
- frtn = FR_IllegalArg;
- goto abort;
- }
- privGiantBytes = abs(privGiant->sign) * GIANT_BYTES_PER_DIGIT;
-
- /*
- * Note PmX = m 'o' P1.
- * Get message/digest as giant. May be significantly different
- * in size from pubKey's basePrime.
- */
- messageGiant = giant_with_data(data, dataLen); // M(text)
- randBytesLen = feePubKeyBitsize(pubKey) / 8;
- maxlen = max(randBytesLen, dataLen);
-
- /* leave plenty of room.... */
- uDigits = (3 * (privGiantBytes + maxlen)) / GIANT_BYTES_PER_DIGIT;
- sinst->u = newGiant(uDigits);
- gtog(privGiant, sinst->u); // u := ourPri
- mulg(messageGiant, sinst->u); // u *= M(text)
- addg(sinst->randGiant, sinst->u); // u += m
-
- /*
- * Paranoia: we're using the curveParams from the caller's pubKey;
- * this cp will have a valid x1OrderPlusRecip if pubKey is the same
- * as the one passed to feeSigNewWithKey() (since feeSigNewWithKey
- * called x1OrderPlusJustify()). But the caller could conceivably be
- * using a different instance of their pubKey, in which case
- * the key's cp->x1OrderPlusRecip may not be valid.
- */
- calcX1OrderPlusRecip(cp);
-
- /* u := u mod x1OrderPlus */
- #if SIG_DEBUG
- if(sigDebug) {
- printf("sigSign:\n");
- printf("u pre-modg : ");
- printGiant(sinst->u);
- }
- #endif
- modg_via_recip(cp->x1OrderPlus, cp->x1OrderPlusRecip, sinst->u);
-
- #if SIG_DEBUG
- if(sigDebug) {
- printf("privGiant : ");
- printGiant(privGiant);
- printf("u : ");
- printGiant(sinst->u);
- printf("messageGiant: ");
- printGiant(messageGiant);
- printf("curveParams :\n");
- printCurveParams(cp);
- }
- #endif // SIG_DEBUG
-abort:
- if(messageGiant) {
- freeGiant(messageGiant);
- }
- return frtn;
-}
-
-/*
- * Given a feeSig processed by feeSigSign, obtain a malloc'd byte
- * array representing the signature.
- * See ByteRep.doc for info on the format of the signature string;
- * PLEASE UPDATE THIS DOCUMENT WHEN YOU MAKE CHANGES TO THE STRING FORMAT.
- */
-feeReturn feeSigData(feeSig sig,
- unsigned char **sigData, // IGNORED....malloc'd and RETURNED
- unsigned *sigDataLen) // RETURNED
-{
- sigInst *sinst = (sigInst*) sig;
-
- #if CRYPTKIT_DER_ENABLE
- return feeDEREncodeElGamalSignature(sinst->u, sinst->PmX, sigData, sigDataLen);
- #else
- *sigDataLen = lengthOfByteRepSig(sinst->u, sinst->PmX);
- *sigData = (unsigned char*) fmalloc(*sigDataLen);
- sigToByteRep(FEE_SIG_MAGIC,
- FEE_SIG_VERSION,
- FEE_SIG_VERSION_MIN,
- sinst->u,
- sinst->PmX,
- *sigData);
- return FR_Success;
- #endif
-}
-
-/*
- * Obtain a feeSig object by parsing an existing signature block.
- * Note that if Pm is used to salt a hash of the signed data, this must
- * function must be called prior to hashing.
- */
-feeReturn feeSigParse(const unsigned char *sigData,
- size_t sigDataLen,
- feeSig *sig) // RETURNED
-{
- sigInst *sinst = NULL;
- feeReturn frtn;
- #if !CRYPTKIT_DER_ENABLE
- int version;
- int magic;
- int minVersion;
- int rtn;
- #endif
-
- sinst = sinstAlloc();
- #if CRYPTKIT_DER_ENABLE
- frtn = feeDERDecodeElGamalSignature(sigData, sigDataLen, &sinst->u, &sinst->PmX);
- if(frtn) {
- goto abort;
- }
- #else
- rtn = byteRepToSig(sigData,
- sigDataLen,
- FEE_SIG_VERSION,
- &magic,
- &version,
- &minVersion,
- &sinst->u,
- &sinst->PmX);
- if(rtn == 0) {
- frtn = FR_BadSignatureFormat;
- goto abort;
- }
- switch(magic) {
- case FEE_ECDSA_MAGIC:
- frtn = FR_WrongSignatureType; // ECDSA!
- goto abort;
- case FEE_SIG_MAGIC:
- break; // proceed
- default:
- frtn = FR_BadSignatureFormat;
- goto abort;
- }
- #endif /* CRYPTKIT_DER_ENABLE */
-
- #if SIG_DEBUG
- if(sigDebug) {
- printf("sigParse: \n");
- printf("u: ");
- printGiant(sinst->u);
- }
- #endif // SIG_DEBUG
-
- *sig = sinst;
- return FR_Success;
-
-abort:
- if(sinst) {
- feeSigFree(sinst);
- }
- return frtn;
-}
-
-/*
- * Verify signature, obtained via feeSigParse, for specified
- * data (most likely a hash result) and feePubKey. Returns non-zero if
- * signature valid.
- */
-
-#define LOG_BAD_SIG 0
-
-#if CRYPTKIT_ELL_PROJ_ENABLE
-
-feeReturn feeSigVerifyNoProj(feeSig sig,
- const unsigned char *data,
- unsigned dataLen,
- feePubKey pubKey);
-
-static void borrowPointProj(pointProj pt, unsigned maxDigits)
-{
- pt->x = borrowGiant(maxDigits);
- pt->y = borrowGiant(maxDigits);
- pt->z = borrowGiant(maxDigits);
-}
-
-static void returnPointProj(pointProj pt)
-{
- returnGiant(pt->x);
- returnGiant(pt->y);
- returnGiant(pt->z);
-}
-
-feeReturn feeSigVerify(feeSig sig,
- const unsigned char *data,
- unsigned dataLen,
- feePubKey pubKey)
-{
- pointProjStruct Q;
- giant messageGiant = NULL;
- pointProjStruct scratch;
- sigInst *sinst = (sigInst*) sig;
- feeReturn frtn;
- curveParams *cp;
- key origKey; // may be plus or minus key
-
- if(sinst->PmX == NULL) {
- dbgLog(("sigVerify without parse!\n"));
- return FR_IllegalArg;
- }
-
- cp = feePubKeyCurveParams(pubKey);
- if(cp->curveType != FCT_Weierstrass) {
- return feeSigVerifyNoProj(sig, data, dataLen, pubKey);
- }
-
- borrowPointProj(&Q, cp->maxDigits);
- borrowPointProj(&scratch, cp->maxDigits);
-
- /*
- * Q := P1
- */
- gtog(cp->x1Plus, Q.x);
- gtog(cp->y1Plus, Q.y);
- int_to_giant(1, Q.z);
-
- messageGiant = giant_with_data(data, dataLen); // M(ciphertext)
-
- /* Q := u 'o' P1 */
- ellMulProjSimple(&Q, sinst->u, cp);
-
- /* scratch := theirPub */
- origKey = feePubKeyPlusCurve(pubKey);
- gtog(origKey->x, scratch.x);
- gtog(origKey->y, scratch.y);
- int_to_giant(1, scratch.z);
-
- #if SIG_DEBUG
- if(sigDebug) {
- printf("verify origKey:\n");
- printKey(origKey);
- printf("messageGiant: ");
- printGiant(messageGiant);
- printf("curveParams:\n");
- printCurveParams(cp);
- }
- #endif // SIG_DEBUG
-
- /* scratch := M 'o' theirPub */
- ellMulProjSimple(&scratch, messageGiant, cp);
-
- #if SIG_DEBUG
- if(sigDebug) {
- printf("signature_compare, with\n");
- printf("p0 = Q:\n");
- printGiant(Q.x);
- printf("p1 = Pm:\n");
- printGiant(sinst->PmX);
- printf("p2 = scratch = R:\n");
- printGiant(scratch.x);
- }
- #endif // SIG_DEBUG
-
- if(signature_compare(Q.x, sinst->PmX, scratch.x, cp)) {
-
- frtn = FR_InvalidSignature;
- #if LOG_BAD_SIG
- printf("***yup, bad sig***\n");
- #endif // LOG_BAD_SIG
- }
- else {
- frtn = FR_Success;
- }
- freeGiant(messageGiant);
-
- returnPointProj(&Q);
- returnPointProj(&scratch);
- return frtn;
-}
-
-#else /* CRYPTKIT_ELL_PROJ_ENABLE */
-
-#define feeSigVerifyNoProj(s, d, l, k) feeSigVerify(s, d, l, k)
-
-#endif /* CRYPTKIT_ELL_PROJ_ENABLE */
-
-/*
- * FEE_SIG_USING_PROJ true : this is the "no Weierstrass" case
- * feeSigVerifyNoProj false : this is redefined to feeSigVerify
- */
-feeReturn feeSigVerifyNoProj(feeSig sig,
- const unsigned char *data,
- unsigned dataLen,
- feePubKey pubKey)
-{
- giant Q = NULL;
- giant messageGiant = NULL;
- giant scratch = NULL;
- sigInst *sinst = (sigInst*) sig;
- feeReturn frtn;
- curveParams *cp;
- key origKey; // may be plus or minus key
-
- if(sinst->PmX == NULL) {
- dbgLog(("sigVerify without parse!\n"));
- frtn = FR_IllegalArg;
- goto out;
- }
-
- cp = feePubKeyCurveParams(pubKey);
- Q = newGiant(cp->maxDigits);
-
- /*
- * pick a key (+/-)
- * Q := P1
- */
- if(SIG_CURVE == CURVE_PLUS) {
- origKey = feePubKeyPlusCurve(pubKey);
- gtog(cp->x1Plus, Q);
- }
- else {
- origKey = feePubKeyMinusCurve(pubKey);
- gtog(cp->x1Minus, Q);
- }
-
- messageGiant = giant_with_data(data, dataLen); // M(ciphertext)
-
- /* Q := u 'o' P1 */
- elliptic_simple(Q, sinst->u, cp);
-
- /* scratch := theirPub */
- scratch = newGiant(cp->maxDigits);
- gtog(origKey->x, scratch);
-
- #if SIG_DEBUG
- if(sigDebug) {
- printf("verify origKey:\n");
- printKey(origKey);
- printf("messageGiant: ");
- printGiant(messageGiant);
- printf("curveParams:\n");
- printCurveParams(cp);
- }
- #endif // SIG_DEBUG
-
- /* scratch := M 'o' theirPub */
- elliptic_simple(scratch, messageGiant, cp);
-
- #if SIG_DEBUG
- if(sigDebug) {
- printf("signature_compare, with\n");
- printf("p0 = Q:\n");
- printGiant(Q);
- printf("p1 = Pm:\n");
- printGiant(sinst->PmX);
- printf("p2 = scratch = R:\n");
- printGiant(scratch);
- }
- #endif // SIG_DEBUG
-
- if(signature_compare(Q, sinst->PmX, scratch, cp)) {
-
- frtn = FR_InvalidSignature;
- #if LOG_BAD_SIG
- printf("***yup, bad sig***\n");
- #endif // LOG_BAD_SIG
- }
- else {
- frtn = FR_Success;
- }
-out:
- if(messageGiant != NULL) {
- freeGiant(messageGiant);
- }
- if(Q != NULL) {
- freeGiant(Q);
- }
- if(scratch != NULL) {
- freeGiant(scratch);
- }
- return frtn;
-}
-
-/*
- * For given key, calculate maximum signature size.
- */
-feeReturn feeSigSize(
- feePubKey pubKey,
- unsigned *maxSigLen)
-{
- /* For now, assume that u and Pm.x in the signature are
- * same size as the key's associated curveParams->basePrime.
- * We might have to pad this a bit....
- */
- curveParams *cp = feePubKeyCurveParams(pubKey);
-
- if(cp == NULL) {
- return FR_BadPubKey;
- }
- #if CRYPTKIT_DER_ENABLE
- *maxSigLen = feeSizeOfDERSig(cp->basePrime, cp->basePrime);
- #else
- *maxSigLen = (unsigned)lengthOfByteRepSig(cp->basePrime, cp->basePrime);
- #endif
- return FR_Success;
-}