673 lines
16 KiB
C
673 lines
16 KiB
C
/*
|
|
* Copyright (c) 1995 Colin Plumb. All rights reserved.
|
|
* For licensing and other legal details, see the file legal.c.
|
|
*
|
|
* dsatest.c - DSA key generator and test driver.
|
|
*
|
|
* This generates DSA primes using a (hopefully) clearly
|
|
* defined algorithm, based on David Kravitz's "kosherizer".
|
|
* It is not, however, identical.
|
|
*/
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
#include "bn.h"
|
|
#include "prime.h"
|
|
|
|
#include "cputime.h"
|
|
#include "sha.h"
|
|
|
|
#define BNDEBUG 1
|
|
|
|
#if BNDEBUG
|
|
#include "bnprint.h"
|
|
#define bndPut(prompt, bn) bnPrint(stdout, prompt, bn, "\n")
|
|
#define bndPrintf printf
|
|
#else
|
|
#define bndPut(prompt, bn) ((void)(prompt),(void)(bn))
|
|
#define bndPrintf (void)
|
|
#endif
|
|
|
|
/*
|
|
* Generate a bignum of a specified length, with the given
|
|
* high and low 8 bits. "High" is merged into the high 8 bits of the
|
|
* number. For example, set it to 0x80 to ensure that the number is
|
|
* exactly "bits" bits long (i.e. 2^(bits-1) <= bn < 2^bits).
|
|
* "Low" is merged into the low 8 bits. For example, set it to
|
|
* 1 to ensure that you generate an odd number.
|
|
*
|
|
* Then XOR the result into the input bignum. This is to
|
|
* accomodate the kosherizer in all its generality.
|
|
*
|
|
* The bignum is generated using the given seed string. The
|
|
* technique is from David Kravitz (of the NSA)'s "kosherizer".
|
|
* The string is hashed, and that (with the low bit forced to 1)
|
|
* is used for the low 160 bits of the number. Then the string,
|
|
* considered as a big-endian array of bytes, is incremented
|
|
* and the incremented value is hashed to produce the next most
|
|
* significant 160 bits, and so on. The increment is performed
|
|
* modulo the size of the seed string.
|
|
*
|
|
* The seed is returned incremented so that it may be used to generate
|
|
* subsequent numbers.
|
|
*
|
|
* The most and least significant 8 bits of the returned number are forced
|
|
* to the values passed in "high" and "low", respectively. Typically,
|
|
* high would be set to 0x80 to force the most significant bit to 1.
|
|
*/
|
|
static int
|
|
genRandBn(struct BigNum *bn, unsigned bits, unsigned char high,
|
|
unsigned char low, unsigned char *seed, unsigned len)
|
|
{
|
|
unsigned char buf1[SHA_DIGESTSIZE];
|
|
unsigned char buf2[SHA_DIGESTSIZE];
|
|
unsigned bytes = (bits+7)/8;
|
|
unsigned l = 0; /* Current position */
|
|
unsigned i;
|
|
struct SHAContext sha;
|
|
|
|
if (!bits)
|
|
return 0;
|
|
|
|
/* Generate the first bunch of hashed data */
|
|
shaInit(&sha);
|
|
shaUpdate(&sha, seed, len);
|
|
shaFinal(&sha, buf1);
|
|
/* Increment the seed, ignoring carry out. */
|
|
i = len;
|
|
while (i-- && (++seed[i] & 255) == 0)
|
|
;
|
|
/* XOR in the existing bytes */
|
|
bnExtractBigBytes(bn, buf2, l, SHA_DIGESTSIZE);
|
|
for (i = 0; i < SHA_DIGESTSIZE; i++)
|
|
buf1[i] ^= buf2[i];
|
|
buf1[SHA_DIGESTSIZE-1] |= low;
|
|
|
|
while (bytes > SHA_DIGESTSIZE) {
|
|
bytes -= SHA_DIGESTSIZE;
|
|
/* Merge in low half of high bits, if necessary */
|
|
if (bytes == 1 && (bits & 7))
|
|
buf1[0] |= high << (bits & 7);
|
|
if (bnInsertBigBytes(bn, buf1, l, SHA_DIGESTSIZE) < 0)
|
|
return -1;
|
|
l += SHA_DIGESTSIZE;
|
|
|
|
/* Compute the next hash we need */
|
|
shaInit(&sha);
|
|
shaUpdate(&sha, seed, len);
|
|
shaFinal(&sha, buf1);
|
|
/* Increment the seed, ignoring carry out. */
|
|
i = len;
|
|
while (i-- && (++seed[i] & 255) == 0)
|
|
;
|
|
/* XOR in the existing bytes */
|
|
bnExtractBigBytes(bn, buf2, l, SHA_DIGESTSIZE);
|
|
for (i = 0; i < SHA_DIGESTSIZE; i++)
|
|
buf1[i] ^= buf2[i];
|
|
}
|
|
|
|
/* Do the final "bytes"-long section, using the tail bytes in buf1 */
|
|
/* Mask off excess high bits */
|
|
buf1[SHA_DIGESTSIZE-bytes] &= 255 >> (-bits & 7);
|
|
/* Merge in specified high bits */
|
|
buf1[SHA_DIGESTSIZE-bytes] |= high >> (-bits & 7);
|
|
if (bytes > 1 && (bits & 7))
|
|
buf1[SHA_DIGESTSIZE-bytes+1] |= high << (bits & 7);
|
|
/* Merge in the appropriate bytes of the buffer */
|
|
if (bnInsertBigBytes(bn, buf1+SHA_DIGESTSIZE-bytes, l, bytes) < 0)
|
|
return -1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
struct Progress {
|
|
FILE *f;
|
|
unsigned column;
|
|
unsigned wrap;
|
|
};
|
|
|
|
static int
|
|
genProgress(void *arg, int c)
|
|
{
|
|
struct Progress *p = arg;
|
|
if (++p->column > p->wrap) {
|
|
putc('\n', p->f);
|
|
p->column = 1;
|
|
}
|
|
putc(c, p->f);
|
|
fflush(p->f);
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
dsaGen(struct BigNum *p, unsigned pbits, struct BigNum *q, unsigned qbits,
|
|
struct BigNum *g, struct BigNum *x, struct BigNum *y,
|
|
unsigned char *seed, unsigned len, FILE *f)
|
|
{
|
|
struct BigNum h, e;
|
|
int i;
|
|
#if CLOCK_AVAIL
|
|
timetype start, stop;
|
|
unsigned long s;
|
|
#endif
|
|
struct Progress progress;
|
|
|
|
if (f)
|
|
fprintf(f,
|
|
"Generating a DSA key pair with %u-bit p and %u-bit q,\n"
|
|
"seed = \"%.*s\"\n", pbits, qbits, (int)len, (char *)seed);
|
|
progress.f = f;
|
|
progress.column = 0;
|
|
progress.wrap = 78;
|
|
|
|
#if CLOCK_AVAIL
|
|
gettime(&start);
|
|
#endif
|
|
|
|
/*
|
|
* Choose a random starting place for q
|
|
* Starting place is SHA(seed) XOR SHA(seed+1),
|
|
* With the high *8* bits set to 1.
|
|
*/
|
|
(void)bnSetQ(q, 0);
|
|
if (genRandBn(q, qbits, 0xFF, 0, seed, len) < 0)
|
|
return -1;
|
|
bndPut("q1 = ", q);
|
|
if (genRandBn(q, qbits, 0xFF, 1, seed, len) < 0)
|
|
return -1;
|
|
bndPut("q2 = ", q);
|
|
/* And search for a prime */
|
|
i = primeGen(q, (unsigned (*)(unsigned))0, f ? genProgress : 0,
|
|
(void *)&progress, 0);
|
|
bndPut("q = ", q);
|
|
if (i < 0)
|
|
return -1;
|
|
|
|
/* ...and for p */
|
|
(void)bnSetQ(p, 0);
|
|
if (genRandBn(p, pbits, 0xC0, 1, seed, len) < 0)
|
|
return -1;
|
|
bndPut("p1 = ", p);
|
|
|
|
/* Temporarily double q */
|
|
if (bnLShift(q, 1) < 0)
|
|
return -1;
|
|
|
|
bnBegin(&h);
|
|
bnBegin(&e);
|
|
|
|
/* Set p = p - (p mod q) + 1, i.e. congruent to 1 mod 2*q */
|
|
if (bnMod(&e, p, q) < 0)
|
|
goto failed;
|
|
if (bnSub(p, &e) < 0 || bnAddQ(p, 1) < 0)
|
|
goto failed;
|
|
bndPut("p2 = ", p);
|
|
|
|
if (f)
|
|
genProgress(&progress, ' ');
|
|
|
|
/* And search for a prime */
|
|
i = primeGenStrong(p, q, f ? genProgress : 0, (void *)&progress);
|
|
if (i < 0)
|
|
return -1;
|
|
bndPut("p = ", p);
|
|
|
|
/* Reduce q again */
|
|
bnRShift(q, 1);
|
|
|
|
/* Now hunt for a suitable g - first, find (p-1)/q */
|
|
if (bnDivMod(&e, &h, p, q) < 0)
|
|
goto failed;
|
|
/* e is now the exponent (p-1)/q, and h is the remainder (one!) */
|
|
if (bnBits(&h) != 1) {
|
|
bndPut("Huh? p % q = ", &h);
|
|
goto failed;
|
|
}
|
|
|
|
if (f)
|
|
genProgress(&progress, ' ');
|
|
|
|
/* Search for a suitable h */
|
|
if (bnSetQ(&h, 2) < 0 || bnTwoExpMod(g, &e, p) < 0)
|
|
goto failed;
|
|
i++;
|
|
while (bnBits(g) < 2) {
|
|
if (f)
|
|
genProgress(&progress, '.');
|
|
if (bnAddQ(&h, 1) < 0 || bnExpMod(g, &h, &e, p) < 0)
|
|
goto failed;
|
|
i++;
|
|
}
|
|
if (f)
|
|
genProgress(&progress, '*');
|
|
#if CLOCK_AVAIL
|
|
gettime(&stop);
|
|
#endif
|
|
|
|
/*
|
|
* Now pick the secret, x. Choose it a bit larger than q and do
|
|
* modular reduction to make it uniformly distributed.
|
|
*/
|
|
bnSetQ(x, 0);
|
|
/* XXX SECURITY ALERT Replace with a real RNG! SECURITY ALERT XXX */
|
|
if (genRandBn(x, qbits+8, 0, 0, seed, len) < 0)
|
|
goto failed;
|
|
if (bnMod(x, x, q) < 0 || bnExpMod(y, g, x, p) < 0)
|
|
goto failed;
|
|
i++;
|
|
if (f)
|
|
putc('\n', f);
|
|
|
|
printf("%d modular exponentiations performed.\n", i);
|
|
|
|
#if CLOCK_AVAIL
|
|
subtime(stop, start);
|
|
s = sec(stop);
|
|
bndPrintf("%u/%u-bit time = %lu.%03u sec.", pbits, qbits,
|
|
s, msec(stop));
|
|
if (s > 60) {
|
|
putchar(' ');
|
|
putchar('(');
|
|
if (s > 3600)
|
|
printf("%u:%02u", (unsigned)(s/3600),
|
|
(unsigned)(s/60%60));
|
|
else
|
|
printf("%u", (unsigned)(s/60));
|
|
printf(":%02u)", (unsigned)(s%60));
|
|
}
|
|
putchar('\n');
|
|
#endif
|
|
|
|
bndPut("q = ", q);
|
|
bndPut("p = ", p);
|
|
bndPut("h = ", &h);
|
|
bndPut("g = ", g);
|
|
bndPut("x = ", x);
|
|
bndPut("y = ", y);
|
|
|
|
bnEnd(&h);
|
|
bnEnd(&e);
|
|
|
|
return 0;
|
|
|
|
failed:
|
|
bnEnd(&h);
|
|
bnEnd(&e);
|
|
return -1;
|
|
}
|
|
|
|
static int
|
|
dsaSign(struct BigNum const *p, struct BigNum const *q, struct BigNum const *g,
|
|
struct BigNum const *x, struct BigNum const *y,
|
|
struct BigNum const *hash, struct BigNum const *k,
|
|
struct BigNum *r, struct BigNum *s)
|
|
{
|
|
int retval = -1;
|
|
struct BigNum t;
|
|
|
|
(void)y;
|
|
|
|
bnBegin(&t);
|
|
/* Make the signature... first the precomputation */
|
|
|
|
/* Compute r = (g^k mod p) mod q */
|
|
if (bnExpMod(r, g, k, p) < 0 || bnMod(r, r, q) < 0)
|
|
goto failed;
|
|
|
|
/* Compute s = k^-1 * (hash + x*r) mod q */
|
|
if (bnInv(&t, k, q) < 0)
|
|
goto failed;
|
|
if (bnMul(s, x, r) < 0 || bnMod(s, s, q) < 0)
|
|
goto failed;
|
|
|
|
/* End of precomputation. Steps after this require the hash. */
|
|
|
|
if (bnAdd(s, hash) < 0)
|
|
goto failed;
|
|
if (bnCmp(s, q) > 0 && bnSub(s, q) < 0)
|
|
goto failed;
|
|
if (bnMul(s, s, &t) < 0 || bnMod(s, s, q) < 0)
|
|
goto failed;
|
|
/* Okay, r and s are the signature! */
|
|
|
|
retval = 0;
|
|
|
|
failed:
|
|
bnEnd(&t);
|
|
return retval;
|
|
}
|
|
|
|
/* Faster version, using precomputed tables */
|
|
static int
|
|
dsaSignFast(struct BigNum const *p, struct BigNum const *q,
|
|
struct BnBasePrecomp const *pre,
|
|
struct BigNum const *x, struct BigNum const *y,
|
|
struct BigNum const *hash, struct BigNum const *k,
|
|
struct BigNum *r, struct BigNum *s)
|
|
{
|
|
int retval = -1;
|
|
struct BigNum t;
|
|
|
|
(void)y;
|
|
|
|
bnBegin(&t);
|
|
/* Make the signature... first the precomputation */
|
|
|
|
/* Compute r = (g^k mod p) mod q */
|
|
if (bnBasePrecompExpMod(r, pre, k, p) < 0 || bnMod(r, r, q) < 0)
|
|
goto failed;
|
|
|
|
/* Compute s = k^-1 * (hash + x*r) mod q */
|
|
if (bnInv(&t, k, q) < 0)
|
|
goto failed;
|
|
if (bnMul(s, x, r) < 0 || bnMod(s, s, q) < 0)
|
|
goto failed;
|
|
|
|
/* End of precomputation. Steps after this require the hash. */
|
|
|
|
if (bnAdd(s, hash) < 0)
|
|
goto failed;
|
|
if (bnCmp(s, q) > 0 && bnSub(s, q) < 0)
|
|
goto failed;
|
|
if (bnMul(s, s, &t) < 0 || bnMod(s, s, q) < 0)
|
|
goto failed;
|
|
/* Okay, r and s are the signature! */
|
|
|
|
retval = 0;
|
|
|
|
failed:
|
|
bnEnd(&t);
|
|
return retval;
|
|
}
|
|
|
|
/*
|
|
* Returns 1 for a good signature, 0 for bad, and -1 on error.
|
|
*/
|
|
static int
|
|
dsaVerify(struct BigNum const *p, struct BigNum const *q,
|
|
struct BigNum const *g, struct BigNum const *y,
|
|
struct BigNum const *r, struct BigNum const *s,
|
|
struct BigNum const *hash)
|
|
{
|
|
struct BigNum w, u1, u2;
|
|
int retval = -1;
|
|
|
|
bnBegin(&w);
|
|
bnBegin(&u1);
|
|
bnBegin(&u2);
|
|
|
|
if (bnInv(&w, s, q) < 0)
|
|
goto failed;
|
|
|
|
if (bnMul(&u1, hash, &w) < 0 || bnMod(&u1, &u1, q) < 0)
|
|
goto failed;
|
|
if (bnMul(&u2, r, &w) < 0 || bnMod(&u2, &u2, q) < 0)
|
|
goto failed;
|
|
|
|
/* Now for the expensive part... */
|
|
|
|
if (bnDoubleExpMod(&w, g, &u1, y, &u2, p) < 0)
|
|
goto failed;
|
|
if (bnMod(&w, &w, q) < 0)
|
|
goto failed;
|
|
retval = (bnCmp(r, &w) == 0);
|
|
failed:
|
|
bnEnd(&u2);
|
|
bnEnd(&u1);
|
|
bnEnd(&w);
|
|
return retval;
|
|
}
|
|
|
|
#define divide_by_n(sec, msec, n) \
|
|
( msec += 1000 * (sec % n), \
|
|
sec /= n, msec /= n, \
|
|
sec += msec / 1000, \
|
|
msec %= 1000 )
|
|
|
|
static int
|
|
dsaTest(struct BigNum const *p, struct BigNum const *q, struct BigNum const *g,
|
|
struct BigNum const *x, struct BigNum const *y)
|
|
{
|
|
struct BigNum hash, r, s, k;
|
|
struct BigNum r1, s1;
|
|
struct BnBasePrecomp pre;
|
|
unsigned bits;
|
|
unsigned i;
|
|
int verified;
|
|
int retval = -1;
|
|
unsigned char foo[4], bar[4];
|
|
#if CLOCK_AVAIL
|
|
timetype start, stop;
|
|
unsigned long cursec, sigsec = 0, sig1sec = 0, versec = 0;
|
|
unsigned curms, sigms = 0, sig1ms = 0, verms = 0;
|
|
unsigned j, n, m = 0;
|
|
#endif
|
|
|
|
bnBegin(&hash);
|
|
bnBegin(&r); bnBegin(&r1);
|
|
bnBegin(&s); bnBegin(&s1);
|
|
bnBegin(&k);
|
|
|
|
bits = bnBits(q);
|
|
strcpy((char *)foo, "foo");
|
|
strcpy((char *)bar, "bar");
|
|
|
|
/* Precompute powers of g */
|
|
if (bnBasePrecompBegin(&pre, g, p, bits) < 0)
|
|
goto failed;
|
|
|
|
bndPrintf(" N\tSigning \tSigning1\tVerifying\tStatus\n");
|
|
for (i = 0; i < 25; i++) {
|
|
/* Pick a random hash, the right length. */
|
|
(void)bnSetQ(&k, 0);
|
|
if (genRandBn(&hash, bits, 0, 0, foo, 4) < 0)
|
|
goto failed;
|
|
|
|
/* Make the signature... */
|
|
|
|
/*
|
|
* XXX SECURITY ALERT XXX
|
|
* XXX Replace with a real RNG! XXX
|
|
* XXX SECURITY ALERT XXX
|
|
*/
|
|
(void)bnSetQ(&k, 0);
|
|
if (genRandBn(&k, bnBits(q)+8, 0, 0, bar, 4) < 0)
|
|
goto failed;
|
|
/* Reduce k to the correct range */
|
|
if (bnMod(&k, &k, q) < 0)
|
|
goto failed;
|
|
#if CLOCK_AVAIL
|
|
/* Decide on a number of iterations to perform... */
|
|
m += n = i+1; /* This goes from 1 to 325 */
|
|
bndPrintf("%3d", n);
|
|
gettime(&start);
|
|
for (j = 0; j < n; j++)
|
|
#endif
|
|
if (dsaSign(p, q, g, x, y, &hash, &k, &r, &s) < 0)
|
|
goto failed;
|
|
#if CLOCK_AVAIL
|
|
gettime(&stop);
|
|
subtime(stop, start);
|
|
sigsec += cursec = sec(stop);
|
|
sigms += curms = msec(stop);
|
|
divide_by_n(cursec, curms, n);
|
|
bndPrintf("\t%lu.%03u\t\t", cursec, curms);
|
|
#else
|
|
bndPrintf("\t*\t\t");
|
|
#endif
|
|
fflush(stdout);
|
|
|
|
#if CLOCK_AVAIL
|
|
gettime(&start);
|
|
for (j = 0; j < n; j++)
|
|
#endif
|
|
if (dsaSignFast(p, q, &pre, x, y, &hash, &k, &r1, &s1) < 0)
|
|
goto failed;
|
|
#if CLOCK_AVAIL
|
|
gettime(&stop);
|
|
subtime(stop, start);
|
|
sig1sec += cursec = sec(stop);
|
|
sig1ms += curms = msec(stop);
|
|
divide_by_n(cursec, curms, n);
|
|
bndPrintf("%lu.%03u\t\t", cursec, curms);
|
|
#else
|
|
bndPrintf("*\t\t");
|
|
#endif
|
|
fflush(stdout);
|
|
if (bnCmp(&r, &r1) != 0) {
|
|
printf("\a** Error r != r1");
|
|
bndPut("g = ", g);
|
|
bndPut("k = ", &k);
|
|
bndPut("r = ", &r);
|
|
bndPut("r1= ", &r1);
|
|
}
|
|
if (bnCmp(&s, &s1) != 0) {
|
|
printf("\a** Error r != r1");
|
|
bndPut("g = ", g);
|
|
bndPut("k = ", &k);
|
|
bndPut("s = ", &s);
|
|
bndPut("s1= ", &s1);
|
|
}
|
|
|
|
/* Okay, r and s are the signature! Now, verify it. */
|
|
|
|
#if CLOCK_AVAIL
|
|
gettime(&start);
|
|
verified = 0; /* To silence warning */
|
|
for (j = 0; j < n; j++) {
|
|
#endif
|
|
verified = dsaVerify(p, q, g, y, &r, &s, &hash);
|
|
if (verified <= 0)
|
|
break;
|
|
}
|
|
#if CLOCK_AVAIL
|
|
gettime(&stop);
|
|
subtime(stop, start);
|
|
versec += cursec = sec(stop);
|
|
verms += curms = msec(stop);
|
|
divide_by_n(cursec, curms, j);
|
|
bndPrintf("%lu.%03u\t\t", cursec, curms);
|
|
#else
|
|
bndPrintf("*\t\t");
|
|
#endif
|
|
if (verified > 0) {
|
|
printf("Test successful.\n");
|
|
} else if (verified == 0) {
|
|
printf("\aSignature did NOT check!.\n");
|
|
bndPut("hash = ", &hash);
|
|
bndPut("k = ", &k);
|
|
bndPut("r = ", &r);
|
|
bndPut("s = ", &s);
|
|
getchar();
|
|
} else {
|
|
printf("\a** Error while verifying");
|
|
bndPut("hash = ", &hash);
|
|
bndPut("k = ", &k);
|
|
bndPut("r = ", &r);
|
|
bndPut("s = ", &s);
|
|
getchar();
|
|
goto failed;
|
|
}
|
|
}
|
|
#if CLOCK_AVAIL
|
|
divide_by_n(sigsec, sigms, m);
|
|
divide_by_n(sig1sec, sig1ms, m);
|
|
divide_by_n(versec, verms, m);
|
|
|
|
bndPrintf("%3u\t%lu.%03u\t\t%lu.%03u\t\t%lu.%03u\t\tAVERAGE %u/%u\n",
|
|
m, sigsec, sigms, sig1sec, sig1ms, versec, verms,
|
|
bnBits(p), bnBits(q));
|
|
#endif
|
|
/* Success */
|
|
retval = 0;
|
|
|
|
failed:
|
|
bnBasePrecompEnd(&pre);
|
|
bnEnd(&k);
|
|
bnEnd(&s1); bnEnd(&s);
|
|
bnEnd(&r1); bnEnd(&r);
|
|
bnEnd(&hash);
|
|
|
|
return retval;
|
|
}
|
|
|
|
/* Copy the command line to the buffer. */
|
|
static unsigned
|
|
copy(unsigned char *buf, int argc, char **argv)
|
|
{
|
|
unsigned pos, len;
|
|
|
|
pos = 0;
|
|
while (--argc) {
|
|
len = strlen(*++argv);
|
|
memcpy(buf, *argv, len);
|
|
buf += len;
|
|
pos += len;
|
|
if (argc > 1) {
|
|
*buf++ = ' ';
|
|
pos++;
|
|
}
|
|
}
|
|
return pos;
|
|
}
|
|
|
|
int
|
|
main(int argc, char **argv)
|
|
{
|
|
unsigned len;
|
|
struct BigNum p, q, g, x, y;
|
|
unsigned char buf[1024];
|
|
|
|
if (argc < 2) {
|
|
fprintf(stderr, "Usage: %s <seed>\n", argv[0]);
|
|
fputs("\
|
|
<seed> should be a a string of bytes to be hashed to seed the prime\n\
|
|
generator. Note that unquoted whitespace between words will be counted\n\
|
|
as a single space. To include multiple spaces, quote them.\n", stderr);
|
|
return 1;
|
|
}
|
|
|
|
bnInit();
|
|
bnBegin(&p);
|
|
bnBegin(&q);
|
|
bnBegin(&g);
|
|
bnBegin(&x);
|
|
bnBegin(&y);
|
|
|
|
len = copy(buf, argc, argv);
|
|
dsaGen(&p, 512, &q, 160, &g, &x, &y, buf, len, stdout);
|
|
dsaTest(&p, &q, &g, &x, &y);
|
|
|
|
len = copy(buf, argc, argv);
|
|
dsaGen(&p, 768, &q, 160, &g, &x, &y, buf, len, stdout);
|
|
dsaTest(&p, &q, &g, &x, &y);
|
|
|
|
len = copy(buf, argc, argv);
|
|
dsaGen(&p, 1024, &q, 160, &g, &x, &y, buf, len, stdout);
|
|
dsaTest(&p, &q, &g, &x, &y);
|
|
|
|
len = copy(buf, argc, argv);
|
|
dsaGen(&p, 1536, &q, 192, &g, &x, &y, buf, len, stdout);
|
|
dsaTest(&p, &q, &g, &x, &y);
|
|
|
|
len = copy(buf, argc, argv);
|
|
dsaGen(&p, 2048, &q, 224, &g, &x, &y, buf, len, stdout);
|
|
dsaTest(&p, &q, &g, &x, &y);
|
|
|
|
len = copy(buf, argc, argv);
|
|
dsaGen(&p, 3072, &q, 256, &g, &x, &y, buf, len, stdout);
|
|
dsaTest(&p, &q, &g, &x, &y);
|
|
|
|
len = copy(buf, argc, argv);
|
|
dsaGen(&p, 4096, &q, 288, &g, &x, &y, buf, len, stdout);
|
|
dsaTest(&p, &q, &g, &x, &y);
|
|
|
|
bnEnd(&y);
|
|
bnEnd(&x);
|
|
bnEnd(&g);
|
|
bnEnd(&q);
|
|
bnEnd(&p);
|
|
|
|
return 0;
|
|
}
|