pgpdsakey.c
来自「著名的加密软件的应用于电子邮件中」· C语言 代码 · 共 1,290 行 · 第 1/3 页
C
1,290 行
/*
* pgpDSAKey.c -- Signatures using the Digital Signature Algorithm
*
* Copyright (C) 1996,1997 Pretty Good Privacy, Inc. All rights reserved.
*
* $Id: pgpDSAKey.c,v 1.10.2.4 1997/06/13 04:15:25 hal Exp $
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "pgpDebug.h"
#include "pgpDSAKey.h"
#include "pgpKeyMisc.h"
#include "bn.h"
#include "pgpCipher.h"
#include "pgpCFB.h"
#include "pgpHash.h"
#include "pgpMem.h"
#include "pgpErr.h"
#include "pgpFixedKey.h"
#include "bnprime.h"
#include "pgpPubKey.h"
#include "pgpRndom.h"
#include "pgpStr2Key.h"
#include "pgpUsuals.h"
#ifndef NULL
#define NULL 0
#endif
#define ASSERTDSA(alg) pgpAssert((ALGMASK(alg))==PGP_PKALG_DSA)
#define MAX_DSA_PRIME_BITS 1024
struct DSApub {
struct BigNum p; /* Public prime */
struct BigNum q; /* Public order of generator */
struct BigNum g; /* Public generator */
struct BigNum y; /* Public key, g**x mod p */
};
struct DSAsec {
struct BigNum p; /* Copy of public parameters */
struct BigNum q;
struct BigNum g;
struct BigNum y;
struct BigNum x; /* Secret key, discrete log of y */
};
/* A PgpSecKey's priv points to this, an DSAsec plus the encrypted form... */
struct DSAsecPlus {
struct DSAsec s;
byte *cryptkey;
size_t ckalloc, cklen;
int locked;
};
/** Public key functions **/
static void
dsaPubDestroy(struct PgpPubKey *pubkey)
{
struct DSApub *pub = (struct DSApub *)pubkey->priv;
ASSERTDSA(pubkey->pkAlg);
bnEnd(&pub->p);
bnEnd(&pub->q);
bnEnd(&pub->g);
bnEnd(&pub->y);
memset(pub, 0, sizeof(pub));
pgpMemFree(pub);
memset(pubkey, 0, sizeof(pubkey));
pgpMemFree(pubkey);
}
/*
* This returns TRUE if the key is too big, returning the
* maximum number of bits that the library can accept.
*/
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;
}
#if 0
static void
dsaPubId8(struct PgpPubKey const *pubkey, byte *buf)
{
pgpAssert(0);
struct DSApub const *pub = (struct DSApub *)pubkey->priv;
byte *keybuf;
size_t keybuflen;
struct PgpHash const *h;
struct PgpHashContext *hc;
ASSERTDSA(pubkey->pkAlg);
/* Unfortunately we have no way of indicating failure */
h = pgpHashByNumber (PGP_HASH_SHA);
pgpAssert(h);
hc = pgpHashCreate(h);
pgpAssert(hc);
keybuflen = dsaPubBufferLength(pubkey);
keybuf = pgpMemAlloc(keybuflen);
pgpAssert(keybuf);
dsaPubToBuffer(pubkey, keybuf);
pgpHashUpdate(hc, keybuf, keybuflen);
memcpy (buf, pgpHashFinal(hc), 8);
pgpHashDestroy(hc);
}
#endif
/* Return the largest possible PgpESK size for a given key */
static size_t
dsaMaxesk(struct PgpPubKey const *pubkey, PgpVersion version)
{
(void)pubkey;
(void)version;
return PGPERR_PUBKEY_UNIMP;
}
/*
* 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(struct PgpPubKey const *pubkey, byte const *key,
size_t keylen, byte *esk, size_t *esklen,
struct PgpRandomContext const *rc, PgpVersion version)
{
(void)pubkey;
(void)key;
(void)keylen;
(void)esk;
(void)esklen;
(void)rc;
(void)version;
return PGPERR_PUBKEY_UNIMP;
}
/*
* 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(struct PgpPubKey const *pubkey, int sigtype, byte const *sig,
size_t siglen, struct PgpHash const *h, byte const *hash)
{
struct DSApub const *pub = (struct DSApub *)pubkey->priv;
struct BigNum r, s, w, u2;
int i;
size_t off;
(void)sigtype;
ASSERTDSA(pubkey->pkAlg);
if (h->type != PGP_HASH_SHA)
return 0; /* No match for sure! */
bnBegin(&r);
bnBegin(&s);
bnBegin(&w);
bnBegin(&u2);
/* sig holds two values. Get first, r, from sig. */
off = 0;
i = pgpBnGetPlain(&r, sig+off, siglen-off);
if (i <= 0)
goto fail;
/* Get 2nd value, s, from SIG */
off += i;
i = pgpBnGetPlain(&s, sig+off, siglen-off);
if (i <= 0)
goto fail;
off += i;
if (off != siglen) {
i = PGPERR_SIG_TOOLONG;
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 */
/* @@@: complicated issues re packing, 160 bits is tight... */
if (bnInsertBigBytes(&u2, hash, 0, h->hashsize) < 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 = PGPERR_SIG_TOOSHORT;
goto done;
nomem:
i = PGPERR_NOMEM;
goto done;
done:
bnEnd(&u2);
bnEnd(&w);
bnEnd(&s);
bnEnd(&r);
return i;
}
/*
* 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(struct PgpPubKey const *pubkey)
{
struct DSApub const *pub = (struct DSApub *)pubkey->priv;
return 8 + (bnBits(&pub->p)+7)/8 + (bnBits(&pub->q)+7)/8 +
(bnBits(&pub->g)+7)/8 + (bnBits(&pub->y)+7)/8;
}
static void
dsaPubToBuffer(struct PgpPubKey const *pubkey, byte *buf)
{
struct DSApub const *pub = (struct 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(struct PgpPubKey *pubkey, struct DSApub *pub)
{
pubkey->next = NULL;
pubkey->pkAlg = PGP_PKALG_DSA;
pubkey->priv = pub;
pubkey->destroy = dsaPubDestroy;
#if 0
pubkey->id8 = dsaPubId8;
#endif
pubkey->maxesk = dsaMaxesk;
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
*/
struct PgpPubKey *
dsaPubFromBuf(byte const *buf, size_t size, int *error)
{
struct PgpPubKey *pubkey;
struct DSApub *pub;
int err = PGPERR_NOMEM;
unsigned i, t, u, v;
int w;
bnInit();
w = pgpBnParse(buf, size, 4, &i, &t, &u, &v);
if (w < 0) {
*error = w;
return NULL;
}
if (t <= i+2 || (buf[t-1] & 1) == 0) { /* Too small or even prime p */
*error = PGPERR_KEY_MPI;
return NULL;
}
if (u <= t+2 || (buf[u-1] & 1) == 0) { /* Too small or even order q */
*error = PGPERR_KEY_MPI;
return NULL;
}
pub = (struct DSApub *)pgpMemAlloc(sizeof(*pub));
if (pub) {
pubkey = (struct PgpPubKey *)pgpMemAlloc(sizeof(*pubkey));
if (pubkey) {
bnBegin(&pub->p);
bnBegin(&pub->q);
bnBegin(&pub->g);
bnBegin(&pub->y);
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 = PGPERR_KEY_UNSUPP;
} 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);
pgpMemFree(pubkey);
}
pgpMemFree(pub);
}
*error = err;
return NULL;
}
/*
* Return the size of the public portion of a key buffer.
*/
int
dsaPubKeyPrefixSize(byte const *buf, size_t size)
{
return pgpBnParse(buf, size, 4, NULL, NULL, NULL, NULL);
}
/** Secret key functions **/
static void
dsaSecDestroy(struct PgpSecKey *seckey)
{
struct DSAsecPlus *sec = (struct DSAsecPlus *)seckey->priv;
ASSERTDSA(seckey->pkAlg);
bnEnd(&sec->s.p);
bnEnd(&sec->s.q);
bnEnd(&sec->s.g);
bnEnd(&sec->s.y);
bnEnd(&sec->s.x);
memset(sec->cryptkey, 0, sec->ckalloc);
pgpMemFree(sec->cryptkey);
memset(sec, 0, sizeof(sec));
pgpMemFree(sec);
memset(seckey, 0, sizeof(seckey));
pgpMemFree(seckey);
}
#if 0
static void
dsaSecId8(struct PgpSecKey const *seckey, byte *buf)
{
struct DSAsecPlus const *sec = (struct DSAsecPlus *)seckey->priv;
ASSERTDSA(seckey->pkAlg);
bnExtractBigBytes(&sec->s.p, buf, 0, 8);
}
#endif
/*
* Generate a PgpPubKey from a PgpSecKey
*/
static struct PgpPubKey *
dsaPubkey(struct PgpSecKey const *seckey)
{
struct DSAsecPlus const *sec = (struct DSAsecPlus *)seckey->priv;
struct PgpPubKey *pubkey;
struct DSApub *pub;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?