📄 pgprsakey.c
字号:
/*____________________________________________________________________________
Copyright (C) 1997 Network Associates Inc. and affiliated companies.
All rights reserved.
$Id: pgpRSAKey.c,v 1.65 1999/04/22 00:37:43 hal Exp $
____________________________________________________________________________*/
#include "pgpSDKBuildFlags.h"
#ifndef PGP_RSA
#error "PGP_RSA requires a value"
#endif
#ifndef PGP_RSA_KEYGEN
#error "PGP_RSA_KEYGEN requires a value"
#endif
/* This entire module is dependent on RSA being enabled */
#if PGP_RSA
#include "pgpConfig.h"
#include <string.h>
#include <stddef.h>
#include "pgpDebug.h"
#include "pgpKeyMisc.h"
#include "pgpRSAGlue.h"
#include "pgpRSAKey.h"
#include "bn.h"
#include "pgpCFBPriv.h"
#include "pgpSymmetricCipherPriv.h"
#include "pgpHashPriv.h"
#include "pgpMem.h"
#include "pgpErrors.h"
#include "bnprime.h"
#include "pgpPubKey.h"
#include "pgpRandomX9_17.h"
#include "pgpStr2Key.h"
#include "pgpContext.h"
#include "pgpEnv.h"
#define RSA_DEFAULT_EXPONENT 17
#define ASSERTRSA(alg) pgpAssert((ALGMASK(alg))==kPGPPublicKeyAlgorithm_RSA || \
(ALGMASK(alg))==kPGPPublicKeyAlgorithm_RSAEncryptOnly || \
(ALGMASK(alg))==kPGPPublicKeyAlgorithm_RSASignOnly)
#define ASSERTRSASIG(alg) \
pgpAssert((ALGMASK(alg))==kPGPPublicKeyAlgorithm_RSA || \
(ALGMASK(alg))==kPGPPublicKeyAlgorithm_RSASignOnly)
#define ASSERTRSAENC(alg) \
pgpAssert((ALGMASK(alg))==kPGPPublicKeyAlgorithm_RSA || \
(ALGMASK(alg))==kPGPPublicKeyAlgorithm_RSAEncryptOnly)
/* A PGPSecKey's priv points to this, an RSAsec plus the encrypted form... */
/* This struct is always allocated using PGPNewSecureData */
typedef struct RSAsecPlus
{
PGPContextRef context;
RSAsec s;
PGPByte * cryptkey;
size_t ckalloc;
size_t cklen;
int locked;
PGPBoolean v3; /* True if key is in a pre PGPVERSION_4 packet */
DEBUG_STRUCT_CONSTRUCTOR( RSAsecPlus )
} RSAsecPlus ;
/** Public key functions **/
static void
rsaPubDestroy(PGPPubKey *pubkey)
{
RSApub *pub = (RSApub *)pubkey->priv;
PGPContextRef context;
pgpAssertAddrValid( pubkey, PGPPubKey );
context = pubkey->context;
ASSERTRSA(pubkey->pkAlg);
bnEnd(&pub->n);
bnEnd(&pub->e);
pgpClearMemory( pub, sizeof(pub));
pgpContextMemFree( context, pub);
pgpClearMemory( pubkey, sizeof(pubkey));
pgpContextMemFree(context, pubkey);
}
/* Return the largest possible PGPESK size for a given key */
static size_t
rsaPubMaxesk(PGPPubKey const *pubkey, PGPPublicKeyMessageFormat format)
{
RSApub const *pub = (RSApub *)pubkey->priv;
ASSERTRSAENC(pubkey->pkAlg);
if (format == kPGPPublicKeyMessageFormat_PGP)
return 2 + bnBytes(&pub->n);
else if (format == kPGPPublicKeyMessageFormat_PKCS1 ||
format == kPGPPublicKeyMessageFormat_X509 ||
format == kPGPPublicKeyMessageFormat_IKE)
return bnBytes(&pub->n);
pgpAssert(0);
return 0;
}
/* Return the largest possible input size for rsaEncrypt */
static size_t
rsaPubMaxdecrypted(PGPPubKey const *pubkey, PGPPublicKeyMessageFormat format)
{
RSApub const *pub = (RSApub *)pubkey->priv;
(void) format;
ASSERTRSAENC(pubkey->pkAlg);
/* Minimum padding could be just 0 2 0 */
return bnBytes(&pub->n) - 3;
}
/* Return the largest possible signature input to rsaVerify */
static size_t
rsaPubMaxsig(PGPPubKey const *pubkey, PGPPublicKeyMessageFormat format)
{
RSApub const *pub = (RSApub *)pubkey->priv;
ASSERTRSASIG(pubkey->pkAlg);
if (format == kPGPPublicKeyMessageFormat_PGP)
return 2 + bnBytes(&pub->n);
else if (format == kPGPPublicKeyMessageFormat_PKCS1 ||
format == kPGPPublicKeyMessageFormat_IKE ||
format == kPGPPublicKeyMessageFormat_X509)
return bnBytes(&pub->n);
pgpAssert(0);
return 0;
}
/*
* Given a buffer of at least "maxesk" bytes, make an PGPESK
* into it and return the size of the PGPESK, or <0.
*/
static int
rsaEncrypt(PGPPubKey const *pubkey, PGPByte const *key,
size_t keylen, PGPByte *esk, size_t *esklen,
PGPRandomContext const *rc, PGPPublicKeyMessageFormat format)
{
#if PGP_ENCRYPT_DISABLE /* [ */
(void)pubkey;
(void)key;
(void)keylen;
(void)esk;
(void)esklen;
(void)rc;
(void)format;
return kPGPError_FeatureNotAvailable;
#else /* PGP_ENCRYPT_DISABLE */ /* ] [ */
RSApub const *pub = (RSApub *)pubkey->priv;
BigNum bn;
unsigned t;
int i;
PGPMemoryMgrRef mgr = NULL;
/* We don't need these arguments, although other algorithms may... */
(void)rc;
mgr = PGPGetContextMemoryMgr( pubkey->context );
ASSERTRSAENC(pubkey->pkAlg);
t = bnBits(&pub->n);
if (t > 0xffff)
return kPGPError_PublicKeyTooLarge;
if (keylen > t)
return kPGPError_PublicKeyTooSmall; /* data too big for pubkey */
if( format == kPGPPublicKeyMessageFormat_PGP ) {
/* Add checksum to key, place temporarily in esk buffer */
t = 0;
esk[0] = key[0];
for (i = 1; i < (int)keylen; i++)
t += esk[i] = key[i];
esk[keylen] = (PGPByte)(t >> 8 & 255);
esk[keylen+1] = (PGPByte)(t & 255);
keylen += 2;
key = esk;
}
bnBegin(&bn, mgr, TRUE);
i = rsaPublicEncrypt(&bn, key, keylen, pub, rc);
if (i < 0) {
bnEnd(&bn);
return i;
}
t = pgpBnPutFormatted(&bn, esk, bnBytes(&pub->n), format);
bnEnd(&bn);
if (esklen)
*esklen = (size_t)t;
return 0;
#endif /* PGP_ENCRYPT_DISABLE */ /* ] */
}
/*
* Return 1 if (sig,siglen) is a valid MPI which signs
* hash, of type h. Check the DER-encoded prefix and the
* hash itself.
*/
static int
rsaVerify(PGPPubKey const *pubkey, PGPByte const *sig,
size_t siglen, PGPHashVTBL const *h, PGPByte const *hash,
PGPPublicKeyMessageFormat format)
{
#if PGP_VERIFY_DISABLE /* [ */
(void)pubkey;
(void)sig;
(void)siglen;
(void)h;
(void)hash;
(void)format;
return kPGPError_FeatureNotAvailable;
#else /* PGP_VERIFY_DISABLE */ /* ] [ */
RSApub const *pub = (RSApub *)pubkey->priv;
BigNum bn;
PGPByte buf[64]; /* largest hash size + DER prefix */
int i;
size_t off = 0;
PGPMemoryMgrRef mgr = PGPGetContextMemoryMgr( pubkey->context );
ASSERTRSASIG(pubkey->pkAlg);
bnBegin(&bn, mgr, FALSE);
if (format == kPGPPublicKeyMessageFormat_X509) {
/* Unformatted data, taking up whole length of buffer */
format = kPGPPublicKeyMessageFormat_PKCS1;
i = pgpBnGetFormatted(&bn, sig+off, siglen-off, siglen-off, format);
} else {
i = pgpBnGetFormatted(&bn, sig+off, siglen-off, bnBytes(&pub->n),
format);
}
if (i <= 0)
return kPGPError_BadSignatureSize;
#if PGP_USECAPIFORRSA
i = rsaVerifyHashSignature(&bn, pub, h, hash);
#else
i = rsaPublicDecrypt(buf, sizeof(buf), &bn, pub);
if (i >= 0) {
/* Check that the returned data is correct */
unsigned t = h->DERprefixsize;
/* IKE does not put in hash OID */
if (format == kPGPPublicKeyMessageFormat_IKE)
t = 0;
i = (size_t)i <= sizeof(buf)
&& (unsigned)i == h->hashsize + t
&& memcmp(buf, h->DERprefix, t) == 0
&& memcmp(buf+t, hash, h->hashsize) == 0;
}
#endif
bnEnd(&bn);
pgpClearMemory( buf, sizeof(buf));
return i;
#endif /* PGP_VERIFY_DISABLE */ /* ] */
}
/*
* Turn a PGPPubKey into the algorithm-specific parts of a public key.
* A public key's RSA-specific part is:
*
* 0 2+i MPI for modulus
* 2+i 2+t MPI for exponent
* 4+i+t
*/
static size_t
rsaPubBufferLength(PGPPubKey const *pubkey)
{
RSApub const *pub = (RSApub *)pubkey->priv;
return 4 + bnBytes(&pub->n) + bnBytes(&pub->e);
}
static void
rsaPubToBuffer(PGPPubKey const *pubkey, PGPByte *buf)
{
RSApub const *pub = (RSApub *)pubkey->priv;
unsigned i, t;
i = bnBits(&pub->n);
pgpAssert(i <= 0xffff);
buf[0] = (PGPByte)(i >> 8);
buf[1] = (PGPByte)i;
i = (i+7)/8;
bnExtractBigBytes(&pub->n, buf+2, 0, i);
t = bnBits(&pub->e);
pgpAssert(t <= 0xffff);
buf[2+i] = (PGPByte)(t >> 8);
buf[3+i] = (PGPByte)t;
t = (t+7)/8;
bnExtractBigBytes(&pub->e, buf+4+i, 0, t);
}
/* A little helper function that's used twice */
static void
rsaFillPubkey(PGPPubKey *pubkey, RSApub *pub)
{
pubkey->next = NULL;
pubkey->pkAlg = kPGPPublicKeyAlgorithm_RSA;
pubkey->priv = pub;
pubkey->destroy = rsaPubDestroy;
pubkey->maxesk = rsaPubMaxesk;
pubkey->maxdecrypted = rsaPubMaxdecrypted;
pubkey->maxsig = rsaPubMaxsig;
pubkey->encrypt = rsaEncrypt;
pubkey->verify = rsaVerify;
pubkey->bufferLength = rsaPubBufferLength;
pubkey->toBuffer = rsaPubToBuffer;
}
/*
* Turn the algorithm-specific parts of a public key into a PGPPubKey
* structure. A public key's RSA-specific part is:
*
* 0 2+i MPI for modulus
* 2+i 2+t MPI for exponent
* 4+i+t
*/
PGPPubKey *
rsaPubFromBuf(
PGPContextRef context,
PGPByte const * buf,
size_t size,
PGPError * error)
{
PGPPubKey *pubkey;
RSApub *pub;
unsigned i, t;
PGPError err = kPGPError_OutOfMemory;
PGPMemoryMgrRef mgr = PGPGetContextMemoryMgr( context );
bnInit();
if (size < 4)
return NULL;
i = ((unsigned)buf[0] << 8) + buf[1];
if (!i || buf[2] >> ((i-1) & 7) != 1) {
*error = kPGPError_MalformedKeyModulus;
return NULL; /* Bad bit length */
}
i = (i+7)/8;
if (size < 4+i) {
*error = kPGPError_KeyPacketTruncated;
return NULL;
}
if ((buf[1+i] & 1) == 0) { /* Too small or even modulus */
*error = kPGPError_RSAPublicModulusIsEven;
return NULL;
}
t = ((unsigned)buf[2+i] << 8) + buf[3+i];
if (!t || buf[4+i] >> ((t-1) & 7) != 1) {
*error = kPGPError_MalformedKeyExponent;
return NULL; /* Bad bit length */
}
t = (t+7)/8;
if (size < 4+i+t) {
*error = kPGPError_KeyPacketTruncated;
return NULL;
}
pub = (RSApub *)pgpContextMemAlloc( context,
sizeof(*pub), kPGPMemoryMgrFlags_Clear );
if (pub) {
pubkey = (PGPPubKey *)pgpContextMemAlloc( context,
sizeof(*pubkey), kPGPMemoryMgrFlags_Clear);
if (pubkey) {
pubkey->context = context;
bnBegin(&pub->n, mgr, FALSE);
bnBegin(&pub->e, mgr, FALSE);
if (bnInsertBigBytes(&pub->n, buf+2, 0, i) >= 0
&& bnInsertBigBytes(&pub->e, buf+4+i, 0, t) >= 0)
{
if (rsaKeyTooBig (pub, NULL) ||
bnBits(&pub->n) > 2048 ) {
err = kPGPError_KeyTooLarge;
} else {
rsaFillPubkey(pubkey, pub);
*error = 0;
return pubkey;
}
}
/* Failed = clean up and return NULL */
bnEnd(&pub->n);
bnEnd(&pub->e);
pgpContextMemFree( context, pubkey);
}
pgpContextMemFree( context, pub);
}
*error = err;
return NULL;
}
/*
* Return the size of the public portion of a key buffer.
*/
int
rsaPubKeyPrefixSize(PGPByte const *buf, size_t size)
{
return pgpBnParse(buf, size, 2, NULL, NULL);
}
/** Secret key functions **/
static void
rsaSecDestroy(PGPSecKey *seckey)
{
RSAsecPlus *sec = (RSAsecPlus *)seckey->priv;
PGPContextRef context;
pgpAssertAddrValid( seckey, PGPPubKey );
context = seckey->context;
ASSERTRSA(seckey->pkAlg);
bnEnd(&sec->s.n);
bnEnd(&sec->s.e);
bnEnd(&sec->s.d);
bnEnd(&sec->s.p);
bnEnd(&sec->s.q);
bnEnd(&sec->s.u);
pgpClearMemory(sec->cryptkey, sec->ckalloc);
pgpContextMemFree( context, sec->cryptkey);
PGPFreeData( sec ); /* Wipes as it frees */
pgpClearMemory( seckey, sizeof(seckey));
pgpContextMemFree( context, seckey);
}
/*
* Generate a PGPPubKey from a PGPSecKey
*/
static PGPPubKey *
rsaPubkey(PGPSecKey const *seckey)
{
RSAsecPlus const *sec = (RSAsecPlus *)seckey->priv;
PGPPubKey *pubkey;
RSApub *pub;
PGPContextRef context;
PGPMemoryMgrRef mgr = NULL;
pgpAssertAddrValid( seckey, PGPSecKey );
context = seckey->context;
mgr = PGPGetContextMemoryMgr( context );
ASSERTRSA(seckey->pkAlg);
pub = (RSApub *)pgpContextMemAlloc( context,
sizeof(*pub), kPGPMemoryMgrFlags_Clear);
if (pub) {
pubkey = (PGPPubKey *)pgpContextMemAlloc( context,
sizeof(*pubkey), kPGPMemoryMgrFlags_Clear );
if (pubkey) {
pubkey->context = seckey->context;
bnBegin(&pub->n, mgr, FALSE);
bnBegin(&pub->e, mgr, FALSE);
if (bnCopy(&pub->n, &sec->s.n) >= 0
&& bnCopy(&pub->e, &sec->s.e) >= 0)
{
rsaFillPubkey(pubkey, pub);
pubkey->pkAlg = seckey->pkAlg;
memcpy(pubkey->keyID, seckey->keyID,
sizeof(pubkey->keyID));
return pubkey;
}
/* Failed = clean up and return NULL */
bnEnd(&pub->n);
bnEnd(&pub->e);
pgpContextMemFree( context, pubkey);
}
pgpContextMemFree(context, pub);
}
return NULL;
}
/*
* Yes, there *is* a reason that this is a function and no a variable.
* On a hardware device with an automatic timeout,
* it actually might need to do some work to find out.
*/
static int
rsaIslocked(PGPSecKey const *seckey)
{
RSAsecPlus const *sec = (RSAsecPlus *)seckey->priv;
ASSERTRSA(seckey->pkAlg);
return sec->locked;
}
/*
* Return the algorithm and (symmetric) key size used for locking/unlocking
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -