Example #1
0
/*
 * Alloc and init a feeFEEDExp object associated with specified feePubKey.
 */
feeFEEDExp feeFEEDExpNewWithPubKey(
	feePubKey pubKey,
	feeRandFcn randFcn,		// optional 
	void *randRef)
{
	feedInst 		*finst = (feedInst *) fmalloc(sizeof(feedInst));
	giant 			privGiant;

	finst->cp = curveParamsCopy(feePubKeyCurveParams(pubKey));
	finst->plus = new_public_with_key(feePubKeyPlusCurve(pubKey),
		finst->cp);
	finst->minus = new_public_with_key(feePubKeyMinusCurve(pubKey),
		finst->cp);

	/*
	 * These might yield NULL data; we can only encrypt in that case.
	 */
	privGiant = feePubKeyPrivData(pubKey);
	if(privGiant) {
		finst->gPriv = newGiant(finst->cp->maxDigits);
		gtog(privGiant, finst->gPriv);
	}
	else {
		finst->gPriv = NULL;
	}

	/*
	 * Conservative, rounding down, on plaintext blocks since we don't
	 * want to split bytes.
	 */
	if(finst->cp->primeType == FPT_General) {
	    unsigned blen = bitlen(finst->cp->basePrime);

	    finst->plainBlockSize = blen / 8;
	    if((blen % 8) == 0) {
	    	/*
		 * round down some more...
		 */
		finst->plainBlockSize--;
	    }
	}
	else {
	    finst->plainBlockSize = finst->cp->q / 8;
	    if(((finst->cp->q & 0x7) == 0) && (finst->cp->k > 0)) {
		/*
		 * Special case, with q mod 8 == 0. Here we have to trim back
		 * the plainBlockSize by one byte.
		 */
		finst->plainBlockSize--;
	    }
	}

	/*
	 * One block of ciphertext - two giants (with implied sign) and a
	 * parity byte
	 */
	finst->cipherBlockSize = (2 * finst->cp->minBytes) + 1;

	finst->xp = newGiant(finst->cp->maxDigits);
	finst->xc = newGiant(finst->cp->maxDigits);
	finst->xq = newGiant(finst->cp->maxDigits);
	finst->xm = newGiant(finst->cp->maxDigits);
	finst->xaux = newGiant(finst->cp->maxDigits);
	finst->rand = NULL;
	finst->randData = NULL;
	finst->randFcn = randFcn;
	finst->randRef = randRef;
	return finst;
}
/*
 * 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;
}
Example #3
0
/*
 * Alloc and init a feeFEED object associated with specified public and
 * private keys.
 */
feeFEED feeFEEDNewWithPubKey(feePubKey myPrivKey,
	feePubKey theirPubKey,
	int forEncrypt,			// 0 ==> decrypt   1 ==> encrypt
	feeRandFcn randFcn,		// optional 
	void *randRef)
{
	feedInst 		*finst;
	giant			privGiant;
	key				k;
	unsigned 		expPlainSize;
	unsigned 		expCipherSize;
	unsigned 		expBlocks;

	if(!curveParamsEquivalent(feePubKeyCurveParams(theirPubKey),
		    feePubKeyCurveParams(myPrivKey))) {
		dbgLog(("feeFEEDNewWithPubKey: Incompatible Keys\n"));
		return NULL;
	}
	finst = (feedInst*) fmalloc(sizeof(feedInst));
	bzero(finst, sizeof(feedInst));
	finst->forEncrypt = forEncrypt;
	finst->cp = curveParamsCopy(feePubKeyCurveParams(theirPubKey));
	finst->rsBlockCount = 0;
	finst->xp = newGiant(finst->cp->maxDigits);
	finst->xm = newGiant(finst->cp->maxDigits);
	finst->tmp1 = newGiant(finst->cp->maxDigits);
	if(forEncrypt) {
	    finst->tmp2 = newGiant(finst->cp->maxDigits);
	}

	/*
	 * cluePlus  = ourPriv * theirPub+
	 * clueMinus = ourPriv * theirPub-
	 */
	finst->cluePlus  = newGiant(finst->cp->maxDigits);
	finst->clueMinus = newGiant(finst->cp->maxDigits);
	privGiant = feePubKeyPrivData(myPrivKey);
	if(privGiant == NULL) {
		dbgLog(("feeFEEDNewWithPubKey: no private key\n"));
		goto abort;
	}
	k = feePubKeyPlusCurve(theirPubKey);
	gtog(k->x, finst->cluePlus);			// cluePlus = theirPub+
	elliptic_simple(finst->cluePlus, privGiant, finst->cp);
	k = feePubKeyMinusCurve(theirPubKey);
	gtog(k->x, finst->clueMinus);			// theirPub-
	elliptic_simple(finst->clueMinus, privGiant, finst->cp);

	/*
	 * Set up block sizes.
	 */
	if(finst->cp->primeType == FPT_General) {
	    unsigned blen = bitlen(finst->cp->basePrime);

	    finst->plainBlockSize = blen / 8;
	    if((blen & 0x7) == 0) {
	    	/*
		 * round down some more...
		 */
		finst->plainBlockSize--;
	    }
	}
	else {
	    finst->plainBlockSize = finst->cp->q / 8;
	    if(((finst->cp->q & 0x7) == 0) && (finst->cp->k > 0)) {
		/*
		 * Special case, with q mod 8 == 0. Here we have to
		 * trim back the plainBlockSize by one byte.
		 */
		finst->plainBlockSize--;
	    }
	}
	finst->cipherBlockSize = finst->cp->minBytes + 1;

	/*
	 * the size of initialRS is subject to tweaking - if we make it
	 * not a multiple of plainBlockSize, we save one FEEDExp cipherBlock
	 * in our ciphertext.
	 */
	finst->initialRSSize = finst->plainBlockSize * 2;
	if(finst->initialRSSize > RS_MIN_SIZE) {
	    unsigned minPlainBlocks;
	    unsigned maxSize;

	    /*
	     * How many plainblocks to hold RS_MIN_SIZE?
	     */
	    minPlainBlocks = (RS_MIN_SIZE + finst->plainBlockSize - 1) /
	    	finst->plainBlockSize;

	    /*
	     * Max size = that many plainblocks, less 2 bytes (to avoid
	     * extra residue block).
	     */
	    maxSize = minPlainBlocks * finst->plainBlockSize - 2;

	    /*
	     * But don't bother with more than 2 plainblocks worth
	     */
	    if(finst->initialRSSize > maxSize) {
	        finst->initialRSSize = maxSize;
	    }
	}
	/* else leave it alone, that's small enough */

	if(forEncrypt) {
		feeRand frand = NULL;

		/*
		 * Encrypt-capable FEEDExp object
		 */
		finst->feedExp = feeFEEDExpNewWithPubKey(theirPubKey,
			randFcn,
			randRef);
		if(finst->feedExp == NULL) {
			goto abort;
		}

		/*
		 * Generate initial r and s data.
		 */
		finst->initialRS = (unsigned char*) fmalloc(finst->initialRSSize);
		if(randFcn != NULL) {
			randFcn(randRef, finst->initialRS, finst->initialRSSize);
		}
		else {
			frand = feeRandAlloc();
			feeRandBytes(frand, finst->initialRS, finst->initialRSSize);
			feeRandFree(frand);
		}
		if(initFromRS(finst)) {
			goto abort;
		}
	}
	else {
		/*
		 * Decrypt-capable FEEDExp object
		 */
		finst->feedExp = feeFEEDExpNewWithPubKey(myPrivKey,
			randFcn,
			randRef);
		if(finst->feedExp == NULL) {
			goto abort;
		}

	}

	/*
	 * Figure out how many of our cipherblocks it takes to hold
	 * a FEEDExp-encrypted initialRS. If initialRSSize is an exact
	 * multiple of expPlainSize, we get an additional feedExp
	 * residue block.
	 */
	expPlainSize = feeFEEDExpPlainBlockSize(finst->feedExp);
	expCipherSize = feeFEEDExpCipherBlockSize(finst->feedExp);
	expBlocks = (finst->initialRSSize + expPlainSize - 1) /
		expPlainSize;
	if((finst->initialRSSize % expPlainSize) == 0) {
		expBlocks++;
	}

	/*
	 * Total meaningful bytes of encrypted initialRS
	 */
	finst->rsCtextSize = expBlocks * expCipherSize;

	/*
	 * Number of our cipherblocks it takes to hold rsCtextSize
	 */
	finst->rsSizeCipherBlocks = (finst->rsCtextSize +
		finst->cipherBlockSize - 1) / finst->cipherBlockSize;
	if(!forEncrypt) {
	    finst->rsCtext = (unsigned char*) fmalloc(finst->rsSizeCipherBlocks *
		finst->cipherBlockSize);
	}

	/*
	 * Sanity check...
	 */
	#if	FEED_DEBUG
	{
	    unsigned fexpBlockSize = feeFEEDExpCipherBlockSize(finst->feedExp);

	    /*
	     * FEEDExp has one more giant in ciphertext, plaintext is
	     * same size
	     */
	    if((finst->cipherBlockSize + finst->cp->minBytes) !=
			fexpBlockSize) {
		dbgLog(("feeFEEDNewWithPubKey: FEEDExp CBlock Size "
			"screwup\n"));
		goto abort;
	    }
	    fexpBlockSize = feeFEEDExpPlainBlockSize(finst->feedExp);
	    if(fexpBlockSize != finst->plainBlockSize) {
		dbgLog(("feeFEEDNewWithPubKey: FEEDExp PBlock Size "
			"screwup\n"));
		goto abort;
	    }
	}
	#endif	// FEED_DEBUG

	return finst;

abort:
	feeFEEDFree(finst);
	return NULL;
}
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;
}
Example #5
0
feeReturn feeECDSAVerify(const unsigned char *sigData,
	size_t sigDataLen,
	const unsigned char *data,
	unsigned dataLen,
	feePubKey pubKey,
    feeSigFormat  format)
{
	/* giant integers per IEEE P1363 notation */
	giant 		h;			// s^(-1)
	giant		h1;			// f h
	giant		h2;			// c times h
	giant		littleC;		// newGiant from ECDSA_decode
	giant 		littleD;		// ditto
	giant		c;			// borrowed, full size
	giant		d;			// ditto
	giant		cPrime = NULL;		// i mod r
	pointProj	h1G = NULL;		// h1 'o' G
	pointProj	h2W = NULL;		// h2 'o' W
	key		W;			// i.e., their public key

	unsigned	version;
	feeReturn	frtn;
	curveParams	*cp = feePubKeyCurveParams(pubKey);
    unsigned    groupBytesLen = ((feePubKeyBitsize(pubKey)+7) / 8);
    int		result;

	if(cp == NULL) {
		return FR_BadPubKey;
	}

	/*
	 * First decode the byteRep string.
	 */
	frtn = ECDSA_decode(
        format,
        groupBytesLen,
        sigData,
		sigDataLen,
		&littleC,
		&littleD,
		&version);
	if(frtn) {
		return frtn;
	}

	/*
	 * littleC and littleD have capacity = abs(sign), probably
	 * not big enough....
	 */
	c = borrowGiant(cp->maxDigits);
	d = borrowGiant(cp->maxDigits);
	gtog(littleC, c);
	gtog(littleD, d);
	freeGiant(littleC);
	freeGiant(littleD);

	sigDbg(("ECDSA verify:\n"));

    /*
     * Verify that c and d are within [1,group_order-1]
     */
    if((gcompg(cp->cOrderPlus, c) != 1) || (gcompg(cp->cOrderPlus, d) != 1) ||
       isZero(c) || isZero(d))
    {
        returnGiant(c);
        returnGiant(d);
        return FR_InvalidSignature;
    }

	/*
	 * W = signer's public key
	 */
	W = feePubKeyPlusCurve(pubKey);

	/*
	 * 1) Compute h = d^(-1) (mod x1OrderPlus);
	 */
	SIGPROF_START;
	h = borrowGiant(cp->maxDigits);
	gtog(d, h);
	binvg_x1OrderPlus(cp, h);
	SIGPROF_END(vfyStep1);

	/*
	 * 2) h1 = digest as giant (skips assigning to 'f' in P1363)
	 */
	if(dataLen > (cp->maxDigits * GIANT_BYTES_PER_DIGIT)) {
	    h1 = borrowGiant(BYTES_TO_GIANT_DIGITS(dataLen));
	}
	else {
	    h1 = borrowGiant(cp->maxDigits);
	}
	deserializeGiant(data, h1, dataLen);

	/* 
	 * Certicom SEC1 states that if the digest is larger than the modulus, 
	 * use the left q bits of the digest. 
	 */
	unsigned hashBits = dataLen * 8;
	if(hashBits > cp->q) {
		gshiftright(hashBits - cp->q, h1);
	}
	
	sigLogGiant("  Wx       : ", W->x);
	sigLogGiant("  f        : ", h1);
	sigLogGiant("  c        : ", c);
	sigLogGiant("  d        : ", d);
	sigLogGiant("  s^(-1)   : ", h);

	/*
	 * 3) Compute h1 = f * h mod x1OrderPlus;
	 */
	SIGPROF_START;
	mulg(h, h1);					// h1 := f * h
	x1OrderPlusMod(h1, cp);
	SIGPROF_END(vfyStep3);

	/*
	 * 4) Compute h2 = c * h (mod x1OrderPlus);
	 */
	SIGPROF_START;
	h2 = borrowGiant(cp->maxDigits);
	gtog(c, h2);
	mulg(h, h2);					// h2 := c * h
	x1OrderPlusMod(h2, cp);
	SIGPROF_END(vfyStep4);

     	/*
	 * 5) Compute h2W = h2 'o' W  (W = theirPub)
	 */
	CKASSERT((W->y != NULL) && !isZero(W->y));
	h2W = newPointProj(cp->maxDigits);
	gtog(W->x, h2W->x);
	gtog(W->y, h2W->y);
	int_to_giant(1, h2W->z);
	ellMulProjSimple(h2W, h2, cp);

	/*
	 * 6) Compute h1G = h1 'o' G   (G = {x1Plus, y1Plus, 1} )
	 */
	CKASSERT((cp->y1Plus != NULL) && !isZero(cp->y1Plus));
	h1G = newPointProj(cp->maxDigits);
	gtog(cp->x1Plus, h1G->x);
	gtog(cp->y1Plus, h1G->y);
	int_to_giant(1,  h1G->z);
	ellMulProjSimple(h1G, h1, cp);

	/*
	 * 7) h1G := (h1 'o' G) + (h2  'o' W)
	 */
	ellAddProj(h1G, h2W, cp);

	/*
	 * 8) If elliptic sum is point at infinity, signature is bad; stop.
	 */
	if(isZero(h1G->z)) {
		dbgLog(("feeECDSAVerify: h1 * G = point at infinity\n"));
		result = 1;
		goto vfyDone;
	}
	normalizeProj(h1G, cp);

	/*
	 * 9) cPrime = x coordinate of elliptic sum, mod x1OrderPlus
	 */
	cPrime = borrowGiant(cp->maxDigits);
	gtog(h1G->x, cPrime);
	x1OrderPlusMod(cPrime, cp);

	/*
	 * 10) Good sig iff cPrime == c
	 */
	result = gcompg(c, cPrime);

vfyDone:
	if(result) {
		frtn = FR_InvalidSignature;
		#if	LOG_BAD_SIG
		printf("***yup, bad sig***\n");
		#endif	// LOG_BAD_SIG
	}
	else {
		frtn = FR_Success;
	}

	returnGiant(c);
	returnGiant(d);
	returnGiant(h);
	returnGiant(h1);
	returnGiant(h2);
	if(h1G != NULL) {
		freePointProj(h1G);
	}
	if(h2W != NULL) {
		freePointProj(h2W);
	}
	if(cPrime != NULL) {
		returnGiant(cPrime);
	}
	return frtn;
}