#include "ckconfig.h"
#include "feePublicKey.h"
#include "feePublicKeyPrivate.h"
#include "ckutilities.h"
#include "giantIntegers.h"
#include "elliptic.h"
#include "curveParams.h"
#include "falloc.h"
#include "feeTypes.h"
#include "feeDebug.h"
#include "feeHash.h"
#include "ckSHA1.h"
#include "feeDigitalSignature.h"
#include "feeECDSA.h"
#include "platform.h"
#include "enc64.h"
#include "feeDES.h"
#include "byteRep.h"
#if CRYPTKIT_DER_ENABLE
#include "CryptKitDER.h"
#endif
#include <stdio.h>
#ifndef NULL
#define NULL ((void *)0)
#endif // NULL
#define PUBLIC_KEY_BLOB_MAGIC_PUB 0xfeeddeef
#define PUBLIC_KEY_BLOB_MAGIC_PRIV 0xfeeddeed
#define PUBLIC_KEY_BLOB_VERSION 6
#define PUBLIC_KEY_BLOB_MINVERSION 6
#if CRYPTKIT_DER_ENABLE
#define PUBLIC_DER_KEY_BLOB_VERSION 1
#endif
typedef struct {
key plus;
key minus; curveParams *cp; giant privGiant; } pubKeyInst;
static feeReturn feeGenPrivate(pubKeyInst *pkinst,
const unsigned char *passwd,
unsigned passwdLen,
char hashPasswd);
static pubKeyInst *pubKeyInstAlloc(void);
static void pubKeyInstFree(pubKeyInst *pkinst);
#if GIANTS_VIA_STACK
static void feePubKeyInitGiants(void);
#endif
static feeReturn createKeyBlob(pubKeyInst *pkinst,
int isPrivate, unsigned char **keyBlob, unsigned *keyBlobLen); static feeReturn feePubKeyInitFromKeyBlob(feePubKey pubKey,
unsigned char *keyBlob,
unsigned keyBlobLen);
#pragma mark --- General public API function ---
feePubKey feePubKeyAlloc(void)
{
pubKeyInst *pkinst = pubKeyInstAlloc();
#if GIANTS_VIA_STACK
feePubKeyInitGiants();
#endif
return pkinst;
}
void feePubKeyFree(feePubKey pubKey)
{
pubKeyInstFree((pubKeyInst*) pubKey);
}
#ifndef ECDSA_VERIFY_ONLY
feeReturn feePubKeyInitFromPrivDataKeyBits(feePubKey pubKey,
const unsigned char *privData,
unsigned privDataLen,
unsigned keyBits,
feePrimeType primeType,
feeCurveType curveType,
char hashPrivData)
{
feeReturn frtn;
feeDepth depth;
frtn = feeKeyBitsToDepth(keyBits, primeType, curveType, &depth);
if(frtn) {
return frtn;
}
return feePubKeyInitFromPrivDataDepth(pubKey,
privData,
privDataLen,
depth,
hashPrivData);
}
feeReturn feePubKeyInitFromPrivDataDepth(feePubKey pubKey,
const unsigned char *privData,
unsigned privDataLen,
feeDepth depth,
char hashPrivData)
{
pubKeyInst *pkinst = (pubKeyInst *) pubKey;
feeReturn frtn;
#if ENGINE_127_BITS
if(depth != FEE_DEPTH_127_1) {
dbgLog(("Illegal Depth\n"));
return FR_IllegalDepth;
}
#endif if(depth > FEE_DEPTH_MAX) {
dbgLog(("Illegal Depth\n"));
return FR_IllegalDepth;
}
pkinst->cp = curveParamsForDepth(depth);
pkinst->plus = new_public(pkinst->cp, CURVE_PLUS);
if(pkinst->cp->x1Minus != NULL) {
pkinst->minus = new_public(pkinst->cp, CURVE_MINUS);
}
frtn = feeGenPrivate(pkinst, privData, privDataLen, hashPrivData);
if(frtn) {
return frtn;
}
set_priv_key_giant(pkinst->plus, pkinst->privGiant);
if(pkinst->cp->x1Minus != NULL) {
set_priv_key_giant(pkinst->minus, pkinst->privGiant);
}
return FR_Success;
}
#endif
feeReturn feePubKeyInitFromKey(feePubKey pubKey,
const unsigned char *privData,
unsigned privDataLen,
feePubKey oldKey,
char hashPrivData)
{
pubKeyInst *pkinst = (pubKeyInst *) pubKey;
pubKeyInst *oldInst = (pubKeyInst *) oldKey;
feeReturn frtn;
if(oldKey == NULL) {
dbgLog(("NULL existing key\n"));
return FR_BadPubKey;
}
pkinst->cp = curveParamsCopy(oldInst->cp);
if(pkinst->cp->x1Minus != NULL) {
pkinst->minus = new_public(pkinst->cp, CURVE_MINUS);
if(pkinst->minus == NULL) {
goto abort;
}
}
pkinst->plus = new_public(pkinst->cp, CURVE_PLUS);
if(pkinst->plus == NULL) {
goto abort;
}
frtn = feeGenPrivate(pkinst, privData, privDataLen, hashPrivData);
if(frtn) {
return frtn;
}
set_priv_key_giant(pkinst->plus, pkinst->privGiant);
if(pkinst->cp->x1Minus != NULL) {
set_priv_key_giant(pkinst->minus, pkinst->privGiant);
}
return FR_Success;
abort:
dbgLog(("Bad Existing Public Key\n"));
return FR_BadPubKey;
}
feeReturn feePubKeyInitFromKeyString(feePubKey pubKey,
const char *keyStr,
unsigned keyStrLen)
{
unsigned char *blob = NULL;
unsigned blobLen;
feeReturn frtn;
blob = dec64((unsigned char *)keyStr, keyStrLen, &blobLen);
if(blob == NULL) {
dbgLog(("Bad Public Key String (not enc64)\n"));
return FR_BadPubKeyString;
}
frtn = feePubKeyInitFromKeyBlob(pubKey, blob, blobLen);
ffree(blob);
return frtn;
}
feeReturn feePubKeyCreateKeyString(feePubKey pubKey,
char **pubKeyString,
unsigned *pubKeyStringLen)
{
unsigned char *blob;
unsigned blobLen;
feeReturn frtn;
pubKeyInst *pkinst = (pubKeyInst *)pubKey;
frtn = createKeyBlob(pkinst,
0, &blob,
&blobLen);
if(frtn) {
return frtn;
}
*pubKeyString = (char *)enc64(blob, blobLen, pubKeyStringLen);
ffree(blob);
return FR_Success;
}
#ifndef ECDSA_VERIFY_ONLY
feeReturn feePubKeyCreatePubBlob(feePubKey pubKey,
unsigned char **keyBlob, unsigned *keyBlobLen) {
pubKeyInst *pkinst = (pubKeyInst *)pubKey;
return createKeyBlob(pkinst,
0,
keyBlob,
keyBlobLen);
}
feeReturn feePubKeyCreatePrivBlob(feePubKey pubKey,
unsigned char **keyBlob, unsigned *keyBlobLen) {
pubKeyInst *pkinst = (pubKeyInst *)pubKey;
if(pkinst->privGiant == NULL) {
return FR_IncompatibleKey;
}
return createKeyBlob(pkinst,
1,
keyBlob,
keyBlobLen);
}
feeReturn feePubKeyInitPubKeyFromPriv(feePubKey privKey,
feePubKey pubKey)
{
pubKeyInst *privInst = (pubKeyInst *)privKey;
pubKeyInst *pubInst = (pubKeyInst *)pubKey;
if((privInst == NULL) || (pubInst == NULL)) {
return FR_BadPubKey;
}
if(privInst->privGiant == NULL) {
return FR_IncompatibleKey;
}
pubInst->cp = curveParamsCopy(privInst->cp);
if(pubInst == NULL) {
return FR_Memory;
}
pubInst->plus = new_public_with_key(privInst->plus, pubInst->cp);
if(pubInst->plus == NULL) {
return FR_Memory;
}
if(pubInst->cp->x1Minus != NULL) {
pubInst->minus = new_public_with_key(privInst->minus, pubInst->cp);
if(pubInst->minus == NULL) {
return FR_Memory;
}
}
return FR_Success;
}
#endif
int feePubKeyIsEqual(feePubKey key1, feePubKey key2)
{
pubKeyInst *pkinst1 = (pubKeyInst *) key1;
pubKeyInst *pkinst2 = (pubKeyInst *) key2;
if ((pkinst1 == NULL) || (pkinst2 == NULL)) {
return 0;
}
if((pkinst1->minus != NULL) && (pkinst2->minus != NULL)) {
if(key_equal(pkinst1->minus, pkinst2->minus) == 0) {
return 0;
}
}
if(key_equal(pkinst1->plus, pkinst2->plus) == 0) {
return 0;
}
return 1;
}
int feePubKeyIsPrivate(feePubKey key)
{
pubKeyInst *myPkinst = (pubKeyInst *)key;
return ((myPkinst->privGiant != NULL) ? 1 : 0);
}
#ifndef ECDSA_VERIFY_ONLY
#if CRYPTKIT_KEY_EXCHANGE
feeReturn feePubKeyCreatePad(feePubKey myKey,
feePubKey theirKey,
unsigned char **padData,
unsigned *padDataLen)
{
pubKeyInst *myPkinst = (pubKeyInst *) myKey;
pubKeyInst *theirPkinst = (pubKeyInst *) theirKey;
giant pad;
unsigned char *result;
unsigned padLen;
key pkey;
if(DEFAULT_CURVE == CURVE_PLUS) {
pkey = theirPkinst->plus;
}
else {
pkey = theirPkinst->minus;
}
pad = make_pad(myPkinst->privGiant, pkey);
result = mem_from_giant(pad, &padLen);
freeGiant(pad);
if(padLen >= FEE_DES_MIN_STATE_SIZE) {
*padData = result;
*padDataLen = padLen;
}
else {
*padData = (unsigned char*) fmalloc(FEE_DES_MIN_STATE_SIZE);
*padDataLen = FEE_DES_MIN_STATE_SIZE;
bzero(*padData, FEE_DES_MIN_STATE_SIZE);
bcopy(result, *padData, padLen);
ffree(result);
}
return FR_Success;
}
#endif
#if CRYPTKIT_HIGH_LEVEL_SIG
feeReturn feePubKeyCreateSignature(feePubKey pubKey,
const unsigned char *data,
unsigned dataLen,
unsigned char **signature,
unsigned *signatureLen)
{
pubKeyInst *pkinst = (pubKeyInst *) pubKey;
feeHash hash;
feeSig sig;
unsigned char *Pm = NULL;
unsigned PmLen;
feeReturn frtn;
if(pkinst->privGiant == NULL) {
dbgLog(("feePubKeyCreateSignature: Attempt to Sign without"
" private data\n"));
return FR_BadPubKey;
}
hash = feeHashAlloc();
sig = feeSigNewWithKey(pubKey, NULL, NULL);
if(sig == NULL) {
feeHashFree(hash);
return FR_BadPubKey;
}
Pm = feeSigPm(sig, &PmLen);
feeHashAddData(hash, Pm, PmLen);
feeHashAddData(hash, data, dataLen);
frtn = feeSigSign(sig,
feeHashDigest(hash),
feeHashDigestLen(),
pubKey);
if(frtn == FR_Success) {
frtn = feeSigData(sig, signature, signatureLen);
}
feeHashFree(hash);
feeSigFree(sig);
ffree(Pm);
return frtn;
}
feeReturn feePubKeyVerifySignature(feePubKey pubKey,
const unsigned char *data,
unsigned dataLen,
const unsigned char *signature,
unsigned signatureLen)
{
feeHash hash;
feeSig sig;
unsigned char *Pm = NULL;
unsigned PmLen;
feeReturn frtn;
hash = feeHashAlloc();
frtn = feeSigParse(signature, signatureLen, &sig);
if(frtn) {
feeHashFree(hash);
#if CRYPTKIT_ECDSA_ENABLE
if(frtn == FR_WrongSignatureType) {
return feePubKeyVerifyECDSASignature(pubKey,
data,
dataLen,
signature,
signatureLen);
}
#endif
return frtn;
}
Pm = feeSigPm(sig, &PmLen);
feeHashAddData(hash, Pm, PmLen);
feeHashAddData(hash, data, dataLen);
frtn = feeSigVerify(sig,
feeHashDigest(hash),
feeHashDigestLen(),
pubKey);
feeHashFree(hash);
feeSigFree(sig);
ffree(Pm);
return frtn;
}
#pragma mark --- ECDSA signature: high level routines ---
#if CRYPTKIT_ECDSA_ENABLE
feeReturn feePubKeyCreateECDSASignature(feePubKey pubKey,
const unsigned char *data,
unsigned dataLen,
unsigned char **signature,
unsigned *signatureLen)
{
pubKeyInst *pkinst = (pubKeyInst *) pubKey;
sha1Obj sha1;
feeReturn frtn;
if(pkinst->privGiant == NULL) {
dbgLog(("feePubKeyCreateECDSASignature: Attempt to Sign "
"without private data\n"));
return FR_BadPubKey;
}
sha1 = sha1Alloc();
sha1AddData(sha1, data, dataLen);
frtn = feeECDSASign(pubKey,
sha1Digest(sha1),
sha1DigestLen(),
NULL, NULL,
signature,
signatureLen);
sha1Free(sha1);
return frtn;
}
#endif
#endif
#if CRYPTKIT_ECDSA_ENABLE
feeReturn feePubKeyVerifyECDSASignature(feePubKey pubKey,
const unsigned char *data,
unsigned dataLen,
const unsigned char *signature,
unsigned signatureLen)
{
sha1Obj sha1;
feeReturn frtn;
sha1 = sha1Alloc();
sha1AddData(sha1, data, dataLen);
frtn = feeECDSAVerify(signature,
signatureLen,
sha1Digest(sha1),
sha1DigestLen(),
pubKey);
sha1Free(sha1);
return frtn;
}
#endif
#endif
#pragma mark --- ECDH ---
feeReturn feePubKeyECDH(
feePubKey privKey,
feePubKey pubKey,
const unsigned char *pubKeyStr,
unsigned pubKeyStrLen,
unsigned char **output,
unsigned *outputLen)
{
feePubKey theirPub = pubKey;
feeReturn frtn = FR_Success;
pubKeyInst *privInst = (pubKeyInst *) privKey;
if(privInst->privGiant == NULL) {
dbgLog(("feePubKeyECDH: privKey not a private key\n"));
return FR_IncompatibleKey;
}
if(theirPub == NULL) {
if(pubKeyStr == NULL) {
return FR_IllegalArg;
}
feeDepth depth;
frtn = curveParamsDepth(privInst->cp, &depth);
if(frtn) {
return frtn;
}
theirPub = feePubKeyAlloc();
if(theirPub == NULL) {
return FR_Memory;
}
frtn = feePubKeyInitFromECDSAPubBlob(theirPub, pubKeyStr, pubKeyStrLen, depth);
if(frtn) {
goto errOut;
}
}
pubKeyInst *pubInst = (pubKeyInst *) theirPub;
giant outputGiant = make_pad(privInst->privGiant, pubInst->plus);
if(outputGiant == NULL) {
dbgLog(("feePubKeyECDH: make_pad error\n"));
frtn = FR_Internal;
}
else {
*outputLen = (privInst->cp->q + 7) / 8;
*output = (unsigned char *)fmalloc(*outputLen);
if(*output == NULL) {
frtn = FR_Memory;
goto errOut;
}
serializeGiant(outputGiant, *output, *outputLen);
freeGiant(outputGiant);
}
errOut:
if((pubKey == NULL) && (theirPub != NULL)) {
feePubKeyFree(theirPub);
}
return frtn;
}
#pragma mark --- feePubKey data accessors ---
unsigned feePubKeyBitsize(feePubKey pubKey)
{
pubKeyInst *pkinst = (pubKeyInst *) pubKey;
switch(pkinst->cp->primeType) {
case FPT_General:
case FPT_Mersenne:
return pkinst->cp->q;
case FPT_FEE:
default:
return bitlen(pkinst->cp->basePrime);
}
return 0;
}
key feePubKeyPlusCurve(feePubKey pubKey)
{
pubKeyInst *pkinst = (pubKeyInst *) pubKey;
return pkinst->plus;
}
key feePubKeyMinusCurve(feePubKey pubKey)
{
pubKeyInst *pkinst = (pubKeyInst *) pubKey;
return pkinst->minus;
}
curveParams *feePubKeyCurveParams(feePubKey pubKey)
{
pubKeyInst *pkinst = (pubKeyInst *) pubKey;
return pkinst->cp;
}
giant feePubKeyPrivData(feePubKey pubKey)
{
pubKeyInst *pkinst = (pubKeyInst *) pubKey;
return pkinst->privGiant;
}
const char *feePubKeyAlgorithmName(void)
{
return "Elliptic Curve - FEE by Apple Computer";
}
#pragma mark --- Private functions ---
static pubKeyInst *pubKeyInstAlloc(void)
{
pubKeyInst *pkinst = (pubKeyInst *) fmalloc(sizeof(pubKeyInst));
bzero(pkinst, sizeof(pubKeyInst));
return pkinst;
}
static void pubKeyInstFree(pubKeyInst *pkinst)
{
if(pkinst->minus) {
free_key(pkinst->minus);
}
if(pkinst->plus) {
free_key(pkinst->plus);
}
if(pkinst->cp) {
freeCurveParams(pkinst->cp);
}
if(pkinst->privGiant) {
clearGiant(pkinst->privGiant);
freeGiant(pkinst->privGiant);
}
ffree(pkinst);
}
#ifndef ECDSA_VERIFY_ONLY
#define NO_PRIV_MUNGE 0
static feeReturn feeGenPrivate(pubKeyInst *pkinst,
const unsigned char *passwd,
unsigned passwdLen,
char hashPasswd)
{
unsigned privLen; feeHash *hash = NULL; unsigned digestLen; unsigned dataSize; unsigned numDigests = 0;
unsigned i;
unsigned char *cp;
unsigned toMove; unsigned moved; unsigned char *digest = NULL;
unsigned char *privData = NULL; giant corder;
corder = lesserX1Order(pkinst->cp);
CKASSERT(!isZero(corder));
privLen = (bitlen(corder) / 8) + 1;
if(!hashPasswd) {
if(passwdLen < privLen) {
return FR_ShortPrivData;
}
privLen = passwdLen;
privData = (unsigned char *)passwd;
goto finishUp;
}
if(passwdLen < 2) {
return FR_IllegalArg;
}
if(privLen > passwdLen) {
dataSize = passwdLen;
}
else {
dataSize = privLen;
}
digestLen = feeHashDigestLen();
numDigests = (dataSize + digestLen - 1) / digestLen;
hash = (void**) fmalloc(numDigests * sizeof(feeHash));
for(i=0; i<numDigests; i++) {
hash[i] = feeHashAlloc();
}
cp = (unsigned char *)passwd;
moved = 0;
for(i=0; i<numDigests; i++) {
if(i == (numDigests - 1)) { toMove = passwdLen - moved;
}
else {
toMove = digestLen;
}
feeHashAddData(hash[i], cp, toMove);
cp += toMove;
moved += toMove;
}
privData = (unsigned char*) fmalloc(privLen);
cp = privData;
moved = 0;
i = 0; for(moved=0; moved<privLen; ) {
if((moved + digestLen) > privLen) {
toMove = privLen - moved;
}
else {
toMove = digestLen;
}
digest = feeHashDigest(hash[i++]);
bcopy(digest, cp, toMove);
cp += toMove;
moved += toMove;
if(i == numDigests) {
i = 0; }
}
finishUp:
pkinst->privGiant = giant_with_data(privData, privLen);
#if FEE_DEBUG
if(isZero(pkinst->privGiant)) {
printf("feeGenPrivate: privData = 0!\n");
}
#endif
lesserX1OrderJustify(pkinst->privGiant, pkinst->cp);
if(hashPasswd) {
memset(privData, 0, privLen);
ffree(privData);
for(i=0; i<numDigests; i++) {
feeHashFree(hash[i]);
}
ffree(hash);
}
return FR_Success;
}
#endif
#if FEE_DEBUG
void printPubKey(feePubKey pubKey)
{
pubKeyInst *pkinst = pubKey;
printf("\ncurveParams:\n");
printCurveParams(pkinst->cp);
printf("plus:\n");
printKey(pkinst->plus);
printf("minus:\n");
printKey(pkinst->minus);
if(pkinst->privGiant != NULL) {
printf("privGiant : ");
printGiant(pkinst->privGiant);
}
}
#else // FEE_DEBUG
void printPubKey(feePubKey pubKey) {}
#endif // FEE_DEBUG
#if GIANTS_VIA_STACK
static int giantsInitd = 0;
static void feePubKeyInitGiants(void)
{
if(giantsInitd) {
return;
}
curveParamsInitGiants();
giantsInitd = 1;
}
#endif
#pragma mark --- Native (custom) key blob formatting ---
#ifndef ECDSA_VERIFY_ONLY
static feeReturn createKeyBlob(pubKeyInst *pkinst,
int isPrivate, unsigned char **keyBlob, unsigned *keyBlobLen) {
unsigned char *s; unsigned sLen;
int magic;
sLen = (4 * sizeof(int)) + lengthOfByteRepCurveParams(pkinst->cp);
if(isPrivate) {
sLen += lengthOfByteRepGiant(pkinst->privGiant);
magic = PUBLIC_KEY_BLOB_MAGIC_PRIV;
}
else {
sLen += (lengthOfByteRepKey(pkinst->plus) +
lengthOfByteRepKey(pkinst->minus));
magic = PUBLIC_KEY_BLOB_MAGIC_PUB;
}
*keyBlob = s = (unsigned char*) fmalloc(sLen);
s += intToByteRep(magic, s);
s += intToByteRep(PUBLIC_KEY_BLOB_VERSION, s);
s += intToByteRep(PUBLIC_KEY_BLOB_MINVERSION, s);
s += intToByteRep(0, s); s += curveParamsToByteRep(pkinst->cp, s);
if(isPrivate) {
s += giantToByteRep(pkinst->privGiant, s);
}
else {
s += keyToByteRep(pkinst->plus, s);
if(pkinst->minus != NULL) {
s += keyToByteRep(pkinst->minus, s);
}
else {
dbgLog(("work needed here for blobs with no minus key\n"));
}
}
*keyBlobLen = sLen;
return FR_Success;
}
#endif
static feeReturn feePubKeyInitFromKeyBlob(feePubKey pubKey,
unsigned char *keyBlob,
unsigned keyBlobLen)
{
pubKeyInst *pkinst = (pubKeyInst *) pubKey;
unsigned char *s; unsigned sLen; int magic;
unsigned len; int minVersion;
int version;
int isPrivate;
s = keyBlob;
sLen = keyBlobLen;
if(sLen < (4 * sizeof(int))) {
dbgLog(("feePublicKey: key blob (1)\n"));
return FR_BadKeyBlob;
}
magic = byteRepToInt(s);
s += sizeof(int);
sLen -= sizeof(int);
switch(magic) {
case PUBLIC_KEY_BLOB_MAGIC_PUB:
isPrivate = 0;
break;
case PUBLIC_KEY_BLOB_MAGIC_PRIV:
isPrivate = 1;
break;
default:
dbgLog(("feePublicKey: Bad Public Key Magic Number\n"));
return FR_BadKeyBlob;
}
version = byteRepToInt(s);
s += sizeof(int);
sLen -= sizeof(int);
minVersion = byteRepToInt(s);
s += sizeof(int);
sLen -= sizeof(int);
if(minVersion > PUBLIC_KEY_BLOB_VERSION) {
dbgLog(("feePublicKey: Incompatible Public Key (1)\n"));
return FR_BadKeyBlob;
}
s += sizeof(int); sLen -= sizeof(int);
pkinst->cp = byteRepToCurveParams(s, sLen, &len);
if(pkinst->cp == NULL) {
dbgLog(("feePublicKey: Bad Key Blob(2)\n"));
return FR_BadKeyBlob;
}
s += len;
sLen -= len;
if(isPrivate) {
pkinst->privGiant = byteRepToGiant(s, sLen, &len);
if(pkinst->privGiant == NULL) {
dbgLog(("feePublicKey: Bad Key Blob(3)\n"));
return FR_BadKeyBlob;
}
s += len;
sLen -= len;
}
else {
pkinst->plus = byteRepToKey(s,
sLen,
CURVE_PLUS, pkinst->cp,
&len);
if(pkinst->plus == NULL) {
dbgLog(("feePublicKey: Bad Key Blob(4)\n"));
return FR_BadKeyBlob;
}
s += len;
sLen -= len;
pkinst->minus = byteRepToKey(s,
sLen,
CURVE_MINUS, pkinst->cp,
&len);
if(pkinst->minus == NULL) {
dbgLog(("feePublicKey: Bad Key Blob(5)\n"));
return FR_BadKeyBlob;
}
s += len;
sLen -= len;
}
if(isPrivate) {
pkinst->plus = new_public(pkinst->cp, CURVE_PLUS);
pkinst->minus = new_public(pkinst->cp, CURVE_MINUS);
set_priv_key_giant(pkinst->plus, pkinst->privGiant);
set_priv_key_giant(pkinst->minus, pkinst->privGiant);
}
return FR_Success;
}
feeReturn feePubKeyInitFromPubBlob(feePubKey pubKey,
unsigned char *keyBlob,
unsigned keyBlobLen)
{
return feePubKeyInitFromKeyBlob(pubKey, keyBlob, keyBlobLen);
}
#ifndef ECDSA_VERIFY_ONLY
feeReturn feePubKeyInitFromPrivBlob(feePubKey pubKey,
unsigned char *keyBlob,
unsigned keyBlobLen)
{
return feePubKeyInitFromKeyBlob(pubKey, keyBlob, keyBlobLen);
}
#endif
#if CRYPTKIT_DER_ENABLE
#ifndef ECDSA_VERIFY_ONLY
feeReturn feePubKeyCreateDERPubBlob(feePubKey pubKey,
unsigned char **keyBlob, unsigned *keyBlobLen) {
pubKeyInst *pkinst = (pubKeyInst *)pubKey;
if(pkinst == NULL) {
return FR_BadPubKey;
}
if(pkinst->minus == NULL) {
return FR_IncompatibleKey;
}
return feeDEREncodePublicKey(PUBLIC_DER_KEY_BLOB_VERSION,
pkinst->cp,
pkinst->plus->x,
pkinst->minus->x,
isZero(pkinst->plus->y) ? NULL : pkinst->plus->y,
keyBlob,
keyBlobLen);
}
feeReturn feePubKeyCreateDERPrivBlob(feePubKey pubKey,
unsigned char **keyBlob, unsigned *keyBlobLen) {
pubKeyInst *pkinst = (pubKeyInst *)pubKey;
if(pkinst == NULL) {
return FR_BadPubKey;
}
if(pkinst->privGiant == NULL) {
return FR_IncompatibleKey;
}
if(pkinst->minus == NULL) {
return FR_IncompatibleKey;
}
return feeDEREncodePrivateKey(PUBLIC_DER_KEY_BLOB_VERSION,
pkinst->cp,
pkinst->privGiant,
keyBlob,
keyBlobLen);
}
#endif
feeReturn feePubKeyInitFromDERPubBlob(feePubKey pubKey,
unsigned char *keyBlob,
size_t keyBlobLen)
{
pubKeyInst *pkinst = (pubKeyInst *) pubKey;
feeReturn frtn;
int version;
if(pkinst == NULL) {
return FR_BadPubKey;
}
memset(pkinst, 0, sizeof(pubKeyInst));
pkinst->plus = (key) fmalloc(sizeof(keystruct));
pkinst->minus = (key) fmalloc(sizeof(keystruct));
if((pkinst->plus == NULL) || (pkinst->minus == NULL)) {
return FR_Memory;
}
memset(pkinst->plus, 0, sizeof(keystruct));
memset(pkinst->minus, 0, sizeof(keystruct));
pkinst->cp = NULL;
pkinst->privGiant = NULL;
pkinst->plus->twist = CURVE_PLUS;
pkinst->minus->twist = CURVE_MINUS;
frtn = feeDERDecodePublicKey(keyBlob,
keyBlobLen,
&version, &pkinst->cp,
&pkinst->plus->x,
&pkinst->minus->x,
&pkinst->plus->y);
if(frtn) {
return frtn;
}
pkinst->minus->y = newGiant(1);
int_to_giant(0, pkinst->minus->y);
pkinst->plus->cp = pkinst->minus->cp = pkinst->cp;
return FR_Success;
}
#ifndef ECDSA_VERIFY_ONLY
feeReturn feePubKeyInitFromDERPrivBlob(feePubKey pubKey,
unsigned char *keyBlob,
size_t keyBlobLen)
{
pubKeyInst *pkinst = (pubKeyInst *) pubKey;
int version;
feeReturn frtn;
if(pkinst == NULL) {
return FR_BadPubKey;
}
memset(pkinst, 0, sizeof(pubKeyInst));
frtn = feeDERDecodePrivateKey(keyBlob,
keyBlobLen,
&version, &pkinst->cp,
&pkinst->privGiant);
if(frtn) {
return frtn;
}
pkinst->plus = new_public(pkinst->cp, CURVE_PLUS);
pkinst->minus = new_public(pkinst->cp, CURVE_MINUS);
set_priv_key_giant(pkinst->plus, pkinst->privGiant);
set_priv_key_giant(pkinst->minus, pkinst->privGiant);
return FR_Success;
}
#endif
#pragma mark --- X509 (public) and PKCS8 (private) key formatting ---
feeReturn feePubKeyCreateX509Blob(
feePubKey pubKey, unsigned char **keyBlob, unsigned *keyBlobLen) {
pubKeyInst *pkinst = (pubKeyInst *) pubKey;
unsigned char *xyStr = NULL;
unsigned xyStrLen = 0;
feeReturn frtn = feeCreateECDSAPubBlob(pubKey, &xyStr, &xyStrLen);
if(frtn) {
return frtn;
}
frtn = feeDEREncodeX509PublicKey(xyStr, xyStrLen, pkinst->cp, keyBlob, keyBlobLen);
ffree(xyStr);
return frtn;
}
feeReturn feePubKeyCreatePKCS8Blob(
feePubKey pubKey, unsigned char **keyBlob, unsigned *keyBlobLen) {
pubKeyInst *pkinst = (pubKeyInst *) pubKey;
unsigned char *privStr = NULL;
unsigned privStrLen = 0;
feeReturn frtn = feeCreateECDSAPrivBlob(pubKey, &privStr, &privStrLen);
if(frtn) {
return frtn;
}
unsigned char *pubStr = NULL;
unsigned pubStrLen = 0;
frtn = feeCreateECDSAPubBlob(pubKey, &pubStr, &pubStrLen);
if(frtn) {
goto errOut;
}
frtn = feeDEREncodePKCS8PrivateKey(privStr, privStrLen,
pubStr, pubStrLen,
pkinst->cp, keyBlob, keyBlobLen);
errOut:
if(privStr) {
ffree(privStr);
}
if(pubStr) {
ffree(pubStr);
}
return frtn;
}
feeReturn feePubKeyInitFromX509Blob(
feePubKey pubKey, unsigned char *keyBlob,
size_t keyBlobLen)
{
feeDepth depth;
unsigned char *xyStr = NULL;
unsigned xyStrLen = 0;
feeReturn frtn = feeDERDecodeX509PublicKey(keyBlob, keyBlobLen, &depth,
&xyStr, &xyStrLen);
if(frtn) {
return frtn;
}
frtn = feePubKeyInitFromECDSAPubBlob(pubKey, xyStr, xyStrLen, depth);
ffree(xyStr);
return frtn;
}
feeReturn feePubKeyInitFromPKCS8Blob(
feePubKey pubKey, unsigned char *keyBlob,
size_t keyBlobLen)
{
feeDepth depth;
unsigned char *privStr = NULL;
unsigned privStrLen = 0;
feeReturn frtn = feeDERDecodePKCS8PrivateKey(keyBlob, keyBlobLen, &depth,
&privStr, &privStrLen, NULL, NULL);
if(frtn) {
return frtn;
}
frtn = feePubKeyInitFromECDSAPrivBlob(pubKey, privStr, privStrLen, depth);
ffree(privStr);
return frtn;
}
#pragma mark --- OpenSSL key formatting ---
feeReturn feePubKeyCreateOpenSSLBlob(
feePubKey pubKey, unsigned char **keyBlob, unsigned *keyBlobLen) {
pubKeyInst *pkinst = (pubKeyInst *) pubKey;
unsigned char *privStr = NULL;
unsigned privStrLen = 0;
feeReturn frtn = feeCreateECDSAPrivBlob(pubKey, &privStr, &privStrLen);
if(frtn) {
return frtn;
}
unsigned char *pubStr = NULL;
unsigned pubStrLen = 0;
frtn = feeCreateECDSAPubBlob(pubKey, &pubStr, &pubStrLen);
if(frtn) {
goto errOut;
}
frtn = feeDEREncodeOpenSSLPrivateKey(privStr, privStrLen,
pubStr, pubStrLen,
pkinst->cp, keyBlob, keyBlobLen);
errOut:
if(privStr) {
ffree(privStr);
}
if(pubStr) {
ffree(pubStr);
}
return frtn;
}
feeReturn feePubKeyInitFromOpenSSLBlob(
feePubKey pubKey, int pubOnly,
unsigned char *keyBlob,
size_t keyBlobLen)
{
feeDepth depth;
unsigned char *privStr = NULL;
unsigned privStrLen = 0;
unsigned char *pubStr = NULL;
unsigned pubStrLen = 0;
feeReturn frtn = feeDERDecodeOpenSSLKey(keyBlob, keyBlobLen, &depth,
&privStr, &privStrLen, &pubStr, &pubStrLen);
if(frtn) {
return frtn;
}
if(pubOnly) {
frtn = feePubKeyInitFromECDSAPubBlob(pubKey, pubStr, pubStrLen, depth);
}
else {
frtn = feePubKeyInitFromECDSAPrivBlob(pubKey, privStr, privStrLen, depth);
}
if(privStr) {
ffree(privStr);
}
if(pubStr) {
ffree(pubStr);
}
return frtn;
}
#endif
feeReturn feeCreateECDSAPubBlob(feePubKey pubKey,
unsigned char **keyBlob,
unsigned *keyBlobLen)
{
pubKeyInst *pkinst = (pubKeyInst *)pubKey;
if(pkinst == NULL) {
return FR_BadPubKey;
}
unsigned giantBytes = (pkinst->cp->q + 7) / 8;
unsigned blobSize = 1 + (2 * giantBytes);
unsigned char *blob = fmalloc(blobSize);
if(blob == NULL) {
return FR_Memory;
}
*blob = 0x04;
serializeGiant(pkinst->plus->x, blob+1, giantBytes);
serializeGiant(pkinst->plus->y, blob+1+giantBytes, giantBytes);
*keyBlob = blob;
*keyBlobLen = blobSize;
return FR_Success;
}
feeReturn feeCreateECDSAPrivBlob(feePubKey pubKey,
unsigned char **keyBlob,
unsigned *keyBlobLen)
{
pubKeyInst *pkinst = (pubKeyInst *)pubKey;
if(pkinst == NULL) {
return FR_BadPubKey;
}
if(pkinst->privGiant == NULL) {
return FR_IncompatibleKey;
}
unsigned giantBytes = (pkinst->cp->q + 7) / 8;
unsigned char *blob = fmalloc(giantBytes);
if(blob == NULL) {
return FR_Memory;
}
serializeGiant(pkinst->privGiant, blob, giantBytes);
*keyBlob = blob;
*keyBlobLen = giantBytes;
return FR_Success;
}
feeReturn feePubKeyInitFromECDSAPubBlob(feePubKey pubKey,
const unsigned char *keyBlob,
unsigned keyBlobLen,
feeDepth depth)
{
pubKeyInst *pkinst = (pubKeyInst *)pubKey;
if(pkinst == NULL) {
return FR_BadPubKey;
}
curveParams *cp = curveParamsForDepth(depth);
if(cp == NULL) {
return FR_IllegalDepth;
}
unsigned giantBytes = (cp->q + 7) / 8;
unsigned blobSize = 1 + (2 * giantBytes);
if(keyBlobLen != blobSize) {
dbgLog(("feePubKeyInitFromECDSAPubBlob: bad blobLen\n"));
return FR_BadKeyBlob;
}
if(*keyBlob != 0x04) {
dbgLog(("feePubKeyInitFromECDSAPubBlob: bad blob leader\n"));
return FR_BadKeyBlob;
}
pkinst->cp = cp;
pkinst->plus = new_public(cp, CURVE_PLUS);
deserializeGiant(keyBlob+1, pkinst->plus->x, giantBytes);
deserializeGiant(keyBlob+1+giantBytes, pkinst->plus->y, giantBytes);
return FR_Success;
}
feeReturn feePubKeyInitFromECDSAPrivBlob(feePubKey pubKey,
const unsigned char *keyBlob,
unsigned keyBlobLen,
feeDepth depth)
{
pubKeyInst *pkinst = (pubKeyInst *)pubKey;
if(pkinst == NULL) {
return FR_BadPubKey;
}
curveParams *cp = curveParamsForDepth(depth);
if(cp == NULL) {
return FR_IllegalDepth;
}
unsigned giantDigits = cp->basePrime->sign;
unsigned giantBytes = (cp->q + 7) / 8;
if((keyBlobLen > giantBytes) || (keyBlobLen < (giantBytes - 1))) {
dbgLog(("feePubKeyInitFromECDSAPrivBlob: bad blobLen\n"));
return FR_BadKeyBlob;
}
pkinst->cp = cp;
pkinst->privGiant = newGiant(giantDigits);
if(pkinst->privGiant == NULL) {
return FR_Memory;
}
deserializeGiant(keyBlob, pkinst->privGiant, keyBlobLen);
pkinst->plus = new_public(pkinst->cp, CURVE_PLUS);
set_priv_key_giant(pkinst->plus, pkinst->privGiant);
return FR_Success;
}