📄 pgpdsakey.c
字号:
/*
* pgpDSAKey.c
* Signatures using the Digital Signature Algorithm
*
* $Id: pgpDSAKey.c,v 1.58.6.1 1999/06/04 00:28:51 heller Exp $
*/
#include <string.h>
#include "pgpConfig.h"
#include "pgpMemoryMgr.h"
#include "pgpDebug.h"
#include "pgpDSAKey.h"
#include "pgpKeyMisc.h"
#include "bn.h"
#include "pgpSymmetricCipherPriv.h"
#include "pgpCFBPriv.h"
#include "pgpHashPriv.h"
#include "pgpMem.h"
#include "pgpErrors.h"
#include "pgpFixedKey.h"
#include "bnprime.h"
#include "pgpPubKey.h"
#include "pgpRandomPool.h"
#include "pgpRandomContext.h"
#include "pgpRandomX9_17.h"
#include "pgpStr2Key.h"
#include "pgpContext.h"
#include "pgpEnv.h"
#ifndef NULL
#define NULL 0
#endif
#define ASSERTDSA(alg) pgpAssert((ALGMASK(alg))==kPGPPublicKeyAlgorithm_DSA)
#define MAX_DSA_PRIME_BITS 1024
typedef struct DSApub {
BigNum p; /* Public prime */
BigNum q; /* Public order of generator */
BigNum g; /* Public generator */
BigNum y; /* Public key, g**x mod p */
} DSApub;
typedef struct DSAsec {
BigNum p; /* Copy of public parameters */
BigNum q;
BigNum g;
BigNum y;
BigNum x; /* Secret key, discrete log of y */
} DSAsec;
/* A PGPSecKey's priv points to this, an DSAsec plus the encrypted form... */
/* This struct is always allocated using PGPNewSecureData */
typedef struct DSAsecPlus
{
PGPContextRef context;
DSAsec s;
PGPByte *cryptkey;
size_t ckalloc, cklen;
int locked;
} DSAsecPlus;
/** Public key functions **/
static void
dsaPubDestroy(PGPPubKey *pubkey)
{
DSApub *pub = (DSApub *)pubkey->priv;
PGPContextRef context;
pgpAssertAddrValid( pubkey, PGPPubKey );
context = pubkey->context;
pgpAssert( pgpContextIsValid( context ) );
ASSERTDSA(pubkey->pkAlg);
bnEnd(&pub->p);
bnEnd(&pub->q);
bnEnd(&pub->g);
bnEnd(&pub->y);
pgpClearMemory( pub, sizeof(pub));
pgpContextMemFree( context, pub);
pgpClearMemory( pubkey, sizeof(pubkey));
pgpContextMemFree( context, pubkey);
}
static int
dsaKeyTooBig(struct DSApub const *pub, struct DSAsec const *sec)
{
unsigned maxsize = MAX_DSA_PRIME_BITS;
if (pub) {
if (bnBits(&pub->p) > maxsize)
return maxsize;
}
if (sec) {
if (bnBits(&sec->p) > maxsize)
return maxsize;
}
/* Else OK */
return 0;
}
/* Return the largest possible PGPESK size for a given key */
static size_t
dsaPubMaxesk(PGPPubKey const *pubkey, PGPPublicKeyMessageFormat format)
{
(void)pubkey;
(void)format;
return kPGPError_PublicKeyUnimplemented;
}
static size_t
dsaPubMaxdecrypted(PGPPubKey const *pubkey, PGPPublicKeyMessageFormat format)
{
(void)pubkey;
(void)format;
return kPGPError_PublicKeyUnimplemented;
}
static size_t
dsaPubMaxsig(PGPPubKey const *pubkey, PGPPublicKeyMessageFormat format)
{
DSApub const *pub = (DSApub *)pubkey->priv;
ASSERTDSA(pubkey->pkAlg);
if (format == kPGPPublicKeyMessageFormat_PGP)
return 2*( 2 + bnBytes(&pub->q) );
else if (format == kPGPPublicKeyMessageFormat_PKCS1 ||
format == kPGPPublicKeyMessageFormat_IKE)
return 2*( bnBytes(&pub->q) );
else if (format == kPGPPublicKeyMessageFormat_X509) {
/* SEQUENCE, length, INT, INT */
PGPUInt32 len;
PGPUInt32 qbytes = bnBytes(&pub->q);
len = 2*(pgpBnX509LenLen(qbytes+1) + 1 + qbytes+1);
return 1 + pgpBnX509LenLen(len) + len;
}
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
dsaEncrypt(PGPPubKey const *pubkey, PGPByte const *key,
size_t keylen, PGPByte *esk, size_t *esklen,
PGPRandomContext const *rc, PGPPublicKeyMessageFormat format)
{
(void)pubkey;
(void)key;
(void)keylen;
(void)esk;
(void)esklen;
(void)rc;
(void)format;
return kPGPError_PublicKeyUnimplemented;
}
/*
* Return 1 if (sig,siglen) is a valid MPI which signs
* hash, of type h. Verify that the type is SHA.1 and
* the hash itself matches.
*/
static int
dsaVerify(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 */ /* ] [ */
DSApub const *pub = (DSApub *)pubkey->priv;
BigNum r, s, w, u2;
int i;
unsigned qbytes;
size_t off;
PGPMemoryMgrRef mgr = PGPGetContextMemoryMgr( pubkey->context );
ASSERTDSA(pubkey->pkAlg);
/* Hashsize must be at least as big as size of q for legal sig */
if (h->hashsize*8 < bnBits(&pub->q)) {
return 0;
}
#if 0
/* Allow generalizations of SHA, as long as they are big enough */
if (h->algorithm != kPGPHashAlgorithm_SHA)
return 0; /* No match for sure! */
#endif
bnBegin(&r, mgr, FALSE );
bnBegin(&s, mgr, FALSE );
bnBegin(&w, mgr, FALSE );
bnBegin(&u2, mgr, FALSE );
qbytes = bnBytes(&pub->q);
/* sig holds two values. Get first, r, from sig. */
off = 0;
if (format == kPGPPublicKeyMessageFormat_X509) {
/* Parse SEQUENCE header for 509 sig data */
PGPByte const *sigp = sig + off;
PGPUInt32 len;
if (pgpBnX509TagLen(&sigp, &len) != X509_TAG_SEQUENCE) {
i = kPGPError_MalformedKeyComponent;
goto done;
}
off += sigp - sig;
if (len != siglen - off) {
i = kPGPError_MalformedKeyComponent;
goto done;
}
}
i = pgpBnGetFormatted(&r, sig+off, siglen-off, qbytes, format);
if (i <= 0)
goto fail;
/* Get 2nd value, s, from SIG */
off += i;
i = pgpBnGetFormatted(&s, sig+off, siglen-off, qbytes, format);
if (i <= 0)
goto fail;
off += i;
if (off != siglen) {
i = kPGPError_BadSignatureSize;
goto done;
}
/*
* Sanity-check r and s against the subprime q. Both should
* be less than q. If not, the signature is clearly bad.
*/
if (bnCmp(&r, &pub->q) >= 0 || bnCmp(&s, &pub->q) >= 0) {
i = 0; /* FAIL */
goto done;
}
/* Reconstruct hash as u2 */
if (bnInsertBigBytes(&u2, hash, 0, bnBytes(&pub->q)) < 0)
goto nomem;
/*
* Calculate DSS check function....
* Given signature (r,s) and hash H (in bn), compute:
* w = s^-1 mod q
* u1 = H * w mod q
* u2 = r * w mod q
* v = g^u1 * y^u2 mod p
* if v == r mod q, the signature checks.
*
* To save space, we put u1 into s, H into u2, and v into w.
*/
if (bnInv(&w, &s, &pub->q) < 0)
goto nomem;
if (bnMul(&s, &u2, &w) < 0 || bnMod(&s, &s, &pub->q) < 0)
goto nomem;
if (bnMul(&u2, &r, &w) < 0 || bnMod(&u2, &u2, &pub->q) < 0)
goto nomem;
/* Now for the expensive part... */
if (bnDoubleExpMod(&w, &pub->g, &s, &pub->y, &u2, &pub->p) < 0)
goto nomem;
if (bnMod(&w, &w, &pub->q) < 0)
goto nomem;
/* Compare result with r, should be equal */
i = bnCmp(&w, &r) == 0;
goto done;
fail:
if (!i)
i = kPGPError_BadSignatureSize;
goto done;
nomem:
i = kPGPError_OutOfMemory;
goto done;
done:
bnEnd(&u2);
bnEnd(&w);
bnEnd(&s);
bnEnd(&r);
return i;
#endif /* PGP_VERIFY_DISABLE */ /* ] */
}
/*
* Turn a PGPPubKey into the algorithm-specific parts of a public key.
* A public key's DSA-specific part is:
*
* 0 2+i MPI for prime
* 2+i 2+t MPI for order
* 4+i+t 2+u MPI for generator
* 6+i+t+u 2+v MPI for public key
* 8+i+t+u+v
*/
static size_t
dsaPubBufferLength(PGPPubKey const *pubkey)
{
DSApub const *pub = (DSApub *)pubkey->priv;
return 8 + bnBytes(&pub->p) + bnBytes(&pub->q) +
bnBytes(&pub->g) + bnBytes(&pub->y);
}
static void
dsaPubToBuffer(PGPPubKey const *pubkey, PGPByte *buf)
{
DSApub const *pub = (DSApub *)pubkey->priv;
unsigned off;
off = 0;
off += pgpBnPutPlain(&pub->p, buf+off);
off += pgpBnPutPlain(&pub->q, buf+off);
off += pgpBnPutPlain(&pub->g, buf+off);
off += pgpBnPutPlain(&pub->y, buf+off);
}
/* A little helper function that's used twice */
static void
dsaFillPubkey(PGPPubKey *pubkey, DSApub *pub)
{
pubkey->next = NULL;
pubkey->pkAlg = kPGPPublicKeyAlgorithm_DSA;
pubkey->priv = pub;
pubkey->destroy = dsaPubDestroy;
pubkey->maxesk = dsaPubMaxesk;
pubkey->maxsig = dsaPubMaxsig;
pubkey->maxdecrypted = dsaPubMaxdecrypted;
pubkey->encrypt = dsaEncrypt;
pubkey->verify = dsaVerify;
pubkey->bufferLength = dsaPubBufferLength;
pubkey->toBuffer = dsaPubToBuffer;
}
/*
* Turn the algorithm-specific parts of a public key into a PGPPubKey
* structure. A public key's DSA-specific part is:
*
* 0 2+i MPI for prime
* 2+i 2+t MPI for order
* 4+i+t 2+u MPI for generator
* 6+i+t+u 2+v MPI for public key
* 8+i+t+u+v
*/
PGPPubKey *
dsaPubFromBuf(
PGPContextRef context,
PGPByte const * buf,
size_t size,
PGPError * error)
{
PGPPubKey *pubkey;
DSApub *pub;
unsigned i, t, u, v;
int w;
PGPError err = kPGPError_OutOfMemory;
PGPMemoryMgrRef mgr = PGPGetContextMemoryMgr( context );
bnInit();
w = pgpBnParse(buf, size, 4, &i, &t, &u, &v);
if (w < 0) {
*error = (PGPError)w;
return NULL;
}
if (t <= i+2 || (buf[t-1] & 1) == 0) { /* Too small or even prime p */
*error = kPGPError_MalformedKeyComponent;
return NULL;
}
if (u <= t+2 || (buf[u-1] & 1) == 0) { /* Too small or even order q */
*error = kPGPError_MalformedKeyComponent;
return NULL;
}
pub = (DSApub *)pgpContextMemAlloc( context,
sizeof(*pub), kPGPMemoryMgrFlags_Clear);
if (pub) {
pubkey = (PGPPubKey *)pgpContextMemAlloc( context,
sizeof(*pubkey), kPGPMemoryMgrFlags_Clear);
if (pubkey) {
pubkey->context = context;
bnBegin(&pub->p, mgr, FALSE );
bnBegin(&pub->q, mgr, FALSE );
bnBegin(&pub->g, mgr, FALSE );
bnBegin(&pub->y, mgr, FALSE );
if (bnInsertBigBytes(&pub->p, buf+i+2, 0, t-i-2) >= 0
&& bnInsertBigBytes(&pub->q, buf+t+2, 0, u-t-2) >= 0
&& bnInsertBigBytes(&pub->g, buf+u+2, 0, v-u-2) >= 0
&& bnInsertBigBytes(&pub->y, buf+v+2, 0, w-v-2) >= 0)
{
if (dsaKeyTooBig (pub, NULL)) {
err = kPGPError_KeyTooLarge;
} else {
dsaFillPubkey(pubkey, pub);
*error = 0;
return pubkey;
}
}
/* Failed = clean up and return NULL */
bnEnd(&pub->p);
bnEnd(&pub->q);
bnEnd(&pub->g);
bnEnd(&pub->y);
pgpContextMemFree( context, pubkey);
}
pgpContextMemFree( context, pub);
}
*error = err;
return NULL;
}
/*
* Return the size of the public portion of a key buffer.
*/
int
dsaPubKeyPrefixSize(PGPByte const *buf, size_t size)
{
return pgpBnParse(buf, size, 4, NULL, NULL, NULL, NULL);
}
/** Secret key functions **/
static void
dsaSecDestroy(PGPSecKey *seckey)
{
DSAsecPlus *sec = (DSAsecPlus *)seckey->priv;
PGPContextRef context;
pgpAssertAddrValid( seckey, PGPSecKey );
context = seckey->context;
ASSERTDSA(seckey->pkAlg);
bnEnd(&sec->s.p);
bnEnd(&sec->s.q);
bnEnd(&sec->s.g);
bnEnd(&sec->s.y);
bnEnd(&sec->s.x);
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 *
dsaPubkey(PGPSecKey const *seckey)
{
DSAsecPlus const *sec = (DSAsecPlus *)seckey->priv;
PGPPubKey *pubkey;
DSApub *pub;
PGPContextRef context;
PGPMemoryMgrRef mgr = NULL;
pgpAssertAddrValid( seckey, PGPSecKey );
context = seckey->context;
mgr = PGPGetContextMemoryMgr( context );
ASSERTDSA(seckey->pkAlg);
pub = (DSApub *)pgpContextMemAlloc( context,
sizeof(*pub), kPGPMemoryMgrFlags_Clear);
if (pub) {
pubkey = (PGPPubKey *)pgpContextMemAlloc( context,
sizeof(*pubkey), kPGPMemoryMgrFlags_Clear);
if (pubkey) {
pubkey->context = context;
bnBegin(&pub->p, mgr, FALSE );
bnBegin(&pub->q, mgr, FALSE );
bnBegin(&pub->g, mgr, FALSE );
bnBegin(&pub->y, mgr, FALSE );
if (bnCopy(&pub->p, &sec->s.p) >= 0
&& bnCopy(&pub->q, &sec->s.q) >= 0
&& bnCopy(&pub->g, &sec->s.g) >= 0
&& bnCopy(&pub->y, &sec->s.y) >= 0)
{
dsaFillPubkey(pubkey, pub);
pubkey->pkAlg = seckey->pkAlg;
memcpy(pubkey->keyID, seckey->keyID,
sizeof(pubkey->keyID));
return pubkey;
}
/* Failed = clean up and return NULL */
bnEnd(&pub->p);
bnEnd(&pub->q);
bnEnd(&pub->g);
bnEnd(&pub->y);
pgpContextMemFree( context, pubkey);
}
pgpContextMemFree( context, pub);
}
return NULL;
}
/*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -