iBoot/lib/pki/libgRSA/libgRSA.c

384 lines
9.3 KiB
C

/* Copyright (c) 2005-2007 Apple Inc. All Rights Reserved. */
/*
* libgRSA.h - public API for RSA library based on libGiants
*
* Created Aug. 9 2005 by Doug Mitchell.
*/
#include <libgRSA/libgRSA.h>
#include <libgRSA/libgRSA_config.h>
#include <libgRSA/rsaPadding.h>
#include <libgRSA/libgRSA_priv.h>
#include <libGiants/giantIntegers.h>
#include <libGiants/giantExternal.h>
#include <libGiants/giantMod.h>
#include <libGiants/giantDebug.h>
#define SIG_DEBUG 0
#if SIG_DEBUG
static void showGiant(const char *label, giant g)
{
printf("%s: ", label);
printGiantHex(g);
}
#else
#define showGiant(l, g)
#endif
#if RSA_PUB_KEY_ENABLE
/* lazy evaluation RSAPubGiantKey->recip */
static void rsaEnsurePubRecip(
RSAPubGiantKey *pubKey)
{
GI_CHECK_SP("rsaEnsurePubRecip");
if(pubKey->recip.g.sign != 0) {
return;
}
GI_LOG_SP("rsaEnsurePubRecip calling make_recip");
make_recip(&pubKey->n.g, &pubKey->recip.g);
}
#endif /* RSA_PUB_KEY_ENABLE */
#if RSA_PRIV_KEY_ENABLE
/* lazy evaluation RSAPrivGiantKey->{pRecip,qRecip} */
static void rsaEnsurePrivRecip(
RSAPrivGiantKey *privKey)
{
GI_CHECK_SP("rsaEnsurePrivRecip");
if(privKey->pRecip.g.sign != 0) {
return;
}
GI_LOG_SP("rsaEnsurePrivbRecip calling make_recip");
make_recip(&privKey->p.g, &privKey->pRecip.g);
make_recip(&privKey->q.g, &privKey->qRecip.g);
}
#endif /* RSA_PRIV_KEY_ENABLE */
#if RSA_SIGN_ENABLE
RSAStatus RSA_Sign(
RSAPrivGiantKey *privKey, /* private key */
RSAPadding padding, /* RP_None or RP_PKCS1 */
const gi_uint8 *dataToSign, /* signature over this data */
gi_uint16 dataToSignLen, /* length of dataToSign */
#if RSA_SIG_SHARE_GIANT
RSASignBuffer *signBuffer, /* signature RETURNED here */
#else
gi_uint8 *sig, /* signature, RETURNED */
#endif
gi_uint16 *sigLen) /* IN/OUT if !RSA_SIG_SHARE_GIANT */
/* OUT only if RSA_SIG_SHARE_GIANT */
{
RSAStatus rtn = RSA_Success;
lgiant ptSigGiant; /* in/out for powermodCRT */
gi_uint16 modSize;
GIReturn grtn;
#if !RSA_SIG_SHARE_GIANT
/* powermodCRT needs this one way or another */
lgiant powermodScratch;
#endif
if((dataToSign == NULL) || (sigLen == NULL) || (privKey == NULL)) {
return RSA_ParamErr;
}
#if RSA_SIG_SHARE_GIANT
if(signBuffer == NULL) {
return RSA_ParamErr;
}
#else
if(sig == NULL) {
return RSA_ParamErr;
}
localGiantAlloc(&powermodScratch);
#endif /* RSA_SIG_SHARE_GIANT */
GI_CHECK_SP("RSA_Sign");
localGiantAlloc(&ptSigGiant);
rsaEnsurePrivRecip(privKey);
modSize = ((bitlen(&privKey->p.g) + bitlen(&privKey->q.g)) + 7) / 8;
switch(padding) {
case RP_None:
rtn = rsaAddNoPadding(dataToSign, dataToSignLen, &ptSigGiant.g);
break;
#if RSA_PADDING_PKCS1_ENABLE
case RP_PKCS1:
rtn = rsaAddPkcs1Padding(dataToSign, dataToSignLen,
modSize, RSA_PKCS1_PAD_SIGN,
NULL, /* no RNG for signing */
&ptSigGiant.g);
break;
#endif /* RSA_PADDING_PKCS1_ENABLE */
default:
rtn = RSA_Unimplemented;
break;
}
if(rtn) {
rsaDebug1("RSA_Sign: AddPadding returned %s\n", rsaStatusStr(rtn));
goto errOut;
}
#if RSA_SIG_SHARE_GIANT
/*
* We init this. Not caller, not powermodCRT. But not before
* we're done with the signature buffer, which could be the same
* as dataToSign.
*/
localGiantAlloc(&signBuffer->g);
#endif /* RSA_SIG_SHARE_GIANT */
/* sig := (ptext ^ d) mod n */
showGiant("sign ptGiant", &ptSigGiant.g);
powermodCRT(&ptSigGiant.g,
&privKey->p.g, &privKey->pRecip.g,
&privKey->q.g, &privKey->qRecip.g,
&privKey->dp.g, &privKey->dq.g,
&privKey->qInv.g,
#if RSA_SIG_SHARE_GIANT
&signBuffer->g.g,
#else
&powermodScratch.g,
#endif
&ptSigGiant.g);
showGiant("sign sig ", &ptSigGiant.g);
#if RSA_SIG_SHARE_GIANT
/* our sigLen is not IN/OUT, but the arg to serializeGiant is */
*sigLen = sizeof(signBuffer->signature);
grtn = serializeGiant(&ptSigGiant.g, signBuffer->signature, sigLen);
#else
grtn = serializeGiant(&ptSigGiant.g, sig, sigLen);
#endif /* RSA_SIG_SHARE_GIANT */
if(grtn) {
rtn = giantStatusToRSA(grtn);
rsaDebug1("RSA_Sign: serializeGiant returned %s\n", rsaStatusStr(rtn));
}
errOut:
clearGiant(&ptSigGiant.g);
return rtn;
}
#endif /* RSA_SIGN_ENABLE */
#if RSA_VERIFY_ENABLE
extern RSAStatus RSA_SigVerify(
RSAPubGiantKey *pubKey, /* public key */
RSAPadding padding, /* RP_None or RP_PKCS1 */
const gi_uint8 *signedData, /* signature over this data */
gi_uint16 signedDataLen, /* length of dataToSign */
const gi_uint8 *sig, /* signature */
gi_uint16 sigLen) /* length of signature */
{
RSAStatus rtn = RSA_Success;
lgiant ptSigGiant; /* plain and decrypted signature */
GIReturn grtn;
GI_CHECK_SP("RSA_SigVerify");
GI_LOG_SP("RSA_SigVerify top");
if((signedData == NULL) || (sig == NULL)) {
return RSA_ParamErr;
}
if(pubKey == NULL) {
return RSA_ParamErr;
}
localGiantAlloc(&ptSigGiant);
rsaEnsurePubRecip(pubKey);
/* signature --> giant */
grtn = deserializeGiant(&ptSigGiant.g, sig, sigLen);
if(grtn) {
rtn = giantStatusToRSA(grtn);
rsaDebug1("RSA_SigVerify: deserializeGiant (sig) returned %s\n",
rsaStatusStr(rtn));
return rtn;
}
/* decrytped sig := (sig ^ e) mod n */
/* powermodg allows base and result to reside in same giant */
GI_LOG_SP("calling powermodg");
showGiant("vfy ptGiant", &ptSigGiant.g);
powermodg(&ptSigGiant.g, &pubKey->e.g,
&pubKey->n.g, &pubKey->recip.g,
&ptSigGiant.g);
showGiant("vfy sig ", &ptSigGiant);
/* check and strip padding, verify data */
switch(padding) {
case RP_None:
rtn = rsaCheckNoPaddingForSigVfy(&ptSigGiant.g, signedData, signedDataLen);
break;
#if RSA_PADDING_PKCS1_ENABLE
case RP_PKCS1:
rtn = rsaCheckPkcs1PaddingForSigVfy(&ptSigGiant.g, signedData, signedDataLen);
break;
#endif /* RSA_PADDING_PKCS1_ENABLE */
default:
rtn = RSA_Unimplemented;
break;
}
if(rtn) {
rsaDebug1("RSA_SigVerify: CheckPadding returned %s\n", rsaStatusStr(rtn));
}
clearGiant(&ptSigGiant.g);
return rtn;
}
#endif /* RSA_VERIFY_ENABLE */
#if RSA_ENCRYPT_ENABLE
extern RSAStatus RSA_Encrypt(
RSAPubGiantKey *pubKey, /* public key */
RSAPadding padding, /* RP_None, RP_PKCS1, RP_OAEP */
RSARngCallback *rngCallback, /* required for RP_PKCS1, RP_OAEP */
const gi_uint8 *plainText,
gi_uint16 plainTextLen, /* length of plainText */
gi_uint8 *cipherText,
gi_uint16 *cipherTextLen) /* IN/OUT */
{
RSAStatus rtn = RSA_Success;
lgiant ptCtGiant;
GIReturn grtn;
gi_uint16 modSize;
if((plainText == NULL) || (cipherText == NULL) || (cipherTextLen == NULL)) {
return RSA_ParamErr;
}
if(pubKey == NULL) {
return RSA_ParamErr;
}
GI_CHECK_SP("RSA_Encrypt");
localGiantAlloc(&ptCtGiant);
rsaEnsurePubRecip(pubKey);
modSize = giantNumBytes(&pubKey->n.g);
switch(padding) {
case RP_None:
rtn = rsaAddNoPadding(plainText, plainTextLen, &ptCtGiant.g);
break;
#if RSA_PADDING_PKCS1_ENABLE
case RP_PKCS1:
rtn = rsaAddPkcs1Padding(plainText, plainTextLen,
modSize, RSA_PKCS1_PAD_ENCRYPT,
rngCallback,
&ptCtGiant.g);
break;
#endif /* RSA_PADDING_PKCS1_ENABLE */
/* OEAP goes here eventually */
default:
rtn = RSA_Unimplemented;
break;
}
if(rtn) {
rsaDebug1("RSA_Encrypt: AddPadding returned %s\n", rsaStatusStr(rtn));
goto errOut;
}
/* ctext := (ptext ^ e) mod n */
/* ptext and ctext can share the same giant */
powermodg(&ptCtGiant.g, &pubKey->e.g,
&pubKey->n.g, &pubKey->recip.g,
&ptCtGiant.g);
/* out to caller */
grtn = serializeGiant(&ptCtGiant.g, cipherText, cipherTextLen);
if(grtn) {
rtn = giantStatusToRSA(grtn);
rsaDebug1("RSA_Encrypt: serializeGiant returned %s\n", rsaStatusStr(rtn));
}
errOut:
clearGiant(&ptCtGiant.g);
return rtn;
}
#endif /* RSA_ENCRYPT_ENABLE */
#if RSA_DECRYPT_ENABLE
RSAStatus RSA_Decrypt(
RSAPrivGiantKey *privKey, /* private key */
RSAPadding padding, /* RP_None, RP_PKCS1, RP_OAEP */
const gi_uint8 *cipherText,
gi_uint16 cipherTextLen, /* length of cipherText */
gi_uint8 *plainText,
gi_uint16 *plainTextLen) /* IN/OUT */
{
RSAStatus rtn = RSA_Success;
lgiant ptCtGiant;
GIReturn grtn;
lgiant powermodScratch;
if((plainText == NULL) || (cipherText == NULL) || (plainTextLen == NULL) || (privKey == NULL)) {
return RSA_ParamErr;
}
GI_CHECK_SP("RSA_Decrypt");
localGiantAlloc(&ptCtGiant);
localGiantAlloc(&powermodScratch);
rsaEnsurePrivRecip(privKey);
/* ciphertext --> giant */
grtn = deserializeGiant(&ptCtGiant.g, cipherText, cipherTextLen);
if(grtn) {
rtn = giantStatusToRSA(grtn);
rsaDebug1("RSA_Decrypt: deserializeGiant (sig) returned %s\n",
rsaStatusStr(rtn));
goto errOut;
}
/* plaintext := (ciphertext ^ d) mod n */
powermodCRT(&ptCtGiant.g,
&privKey->p.g, &privKey->pRecip.g,
&privKey->q.g, &privKey->qRecip.g,
&privKey->dp.g, &privKey->dq.g,
&privKey->qInv.g,
&powermodScratch.g,
&ptCtGiant.g);
/* check and strip padding */
switch(padding) {
case RP_None:
rtn = rsaCheckNoPadding(&ptCtGiant.g, plainText, plainTextLen);
break;
#if RSA_PADDING_PKCS1_ENABLE
case RP_PKCS1:
rtn = rsaCheckPkcs1Padding(&ptCtGiant.g, RSA_PKCS1_PAD_ENCRYPT,
plainText, plainTextLen);
break;
#endif /* RSA_PADDING_PKCS1_ENABLE */
/* OAEP here */
default:
rtn = RSA_Unimplemented;
break;
}
if(rtn) {
rsaDebug1("RSA_Decrypt: CheckPadding returned %s\n", rsaStatusStr(rtn));
}
errOut:
clearGiant(&ptCtGiant.g);
return rtn;
}
#endif /* RSA_DECRYPT_ENABLE */