tomcrypt/dsa.c
2010-06-16 12:37:52 +02:00

399 lines
11 KiB
C

/* Implementation of the Digital Signature Algorithm (DSA) by Tom St Denis */
#ifdef MDSA
#include <mycrypt.h>
static const struct {
int size, osize;
char *order,
*prime,
*base;
} sets[] = {
#ifdef DSA1024
{
1024, 160,
"PE6GbKzFwpeAAMtC3PUsqsRQMWl",
"PyhJv87GTec3fBvC8BQT4yQ8gSYB8rk6DfLRfeirnZsQaQBVwh8PZ7V1hKfD"
"SGGUgr1cAb3YrnZw97HvyaKmypY2dM19OxeNWNI4f6IyYwj/mcAiJpkjxMmZ"
"mYVrTbGxBG8OaKBD9vFd9/Jif8djJ18GnaRsdRoCBDec+W++x6D",
"3uYLnHhrVRR6hATv30lj/XX5AecEE2tJVgtWcHkbwKuR3WEqqvP8xBUG70Ve"
"p6kUchz/E/kZaGIJ0mrqme6bNDIxoNqtshyDfska/Zfm/QHuDZWljVGbPx68"
"eSBw1vzkRKFCmR8QgpT+R887JufEgQRRIQOuLK8c1ND61efJH2t"
},
#endif
#ifdef DSA2048
{
2048, 256,
"TZLgPgD7D46uoATLyNSgKsgh6LglcVDwlPFvT6dcOdN",
"EUlAFvO8lXjhXn/6BobNq4bo0st12+zwgpshNJgoUap/LFCQcGeVGt/s/ocD"
"M+4v+bU3dNKjFJEYzb+sxmy5dbzQsa15+Ud4v1UJ/7D4p0IyA+h9aeU9i/C9"
"tJQC824mQhmL5cxx7SbQPMD/2+P04hLyeDOir1L1vmvE1tWZg43Jbza2LTQJ"
"52wi/Sguai3vFZVMObEPBfbXzg9b8pH1i75Q1os9w0LtfJ4pYQJD3Xn66jYF"
"mpLVqK4yuMXOOq07bkM5Nx+jQvFpGuRiD5e4a2FB1NjXbCGMtRxu6eurPAIY"
"F5dw3QWXkZm74SFmLTi0GW+3pipDWiBSUu9pUpp6rr",
"79PG50FKgZgffOnFiUuuZLhWicqFZ6EwvWXQi7uBmvMQUoXNEBschAhRtLQE"
"ev5iHrR2g41rEEundwwFTbRdyq2txBS2bClkFjGlojPwayWvXLAaDltfkhws"
"TjS/gNKch4qD1nPu+Kd1RmjWp1B1JzBXnlcj/z5qMaF8oL4bk9qGGEmaeOLs"
"90vW0Z/7QWBC8h+65SohFBmydUWwXhs4rAa7NwHbPltnXdF6kZHpQOtT5h+4"
"hYA83eYzdeOl5rYrFDiyJ+nfOptgLiLIHB9L0wkOhFrb52+S7qKpgYe1+oof"
"K1/Rd4D8fL5qvGyXWz1dB8W2iqAXeXKlkWZrvHQdMM"
},
#endif
#ifdef DSA4096
{
4096, 512,
"4GO4hUY+2MqiwNBYFx/JqRejRKXXJfcaY7mIBYksn2Dwn6JQZp9Qpg3bbnOJ"
"kt5ZqH2dtEjbV9B/AXF51jOkW/",
"Jddrq1iN+f03IKVqcDSOz7IquBVxzb34Cwzmc7rHpIOW3DqW7IjMz47ETtWu"
"KvG3JxFdYaiv69lAE+X38DEqQSTE8Ba9jfNYs9PYeH4RfsT5op/u3r41anRW"
"jJTHMhnvwwQ0eQrZ+9d7LQePnQSUs3eXb8ZdNsh8/h30b3gIMk+08bZoJejF"
"6Y2vMtMQUHmmoM/+IlrMz7TZ4tu0jkYWBp1y74WLGemXkYvU6pqH8dTQX1MM"
"oG93eBKQ87jHbtBJ+L6EbcqO/jVa6lwUivEbBs9UtKf4lC0pe3SZqfFhrJde"
"2b5LfbPBLk2pNdC5MJCsIVz7TUL28SWYwx7Nx7ybxtKd76L8kgbLfoOYiJRx"
"WIFGRE40Q9/0zuqzz6D1WHKQE4wg5oy6WQeO3Q5BN1UC6O4EUSkD7mC3KmWA"
"MgxNDZYMA+BSCTirVL2eS90WCA4LkTsHhoLgafwZT5xanUKGY/cZix29sy21"
"J1Ut4cbPFjxg76OVu9obONitMLg+63dz3Ho8LMhXaKN43yl5Kc4PxeUCQWVU"
"gHXg8RSldQMOvhwohHFibiMUrRkkCs2//Ts6hVdS3cEFgfYhpnzeEiGBCuat"
"ZZYpaWKZlmrlcUYH7Rg9SyHH1h4DLrki5ySIjGxozT6JhIrMme8uQcN9YOiq"
"GwRhjR3AM1QiOUfolENTYCn",
"3VIJLic34uyamh2TbNHEjECeH289m938S2wvHYe/3xPNiCjVhBxl6RAgom+Q"
"3X7+r8EII4QQKXXdqR3Ad/nXzJkgMUJVvt5d5lIwwKM7+ffbLmhJWldO0Jkc"
"7oZQr7t81khBUG4wgPVZO8OwjB66v9npPCcBLNLO6DAWE82CM8YfPJzQt0tr"
"JSHwcgixvkFft25SdI0V9zg2H6sj2Q/yAYUEAPzyDfQVvLzqEN2tmIhturnR"
"wUW4WLy8PSls/tt5eWjdI++ofdGHNJmKaZjHgym52GhNQmWZYWzK/hcllWtC"
"U8vCw7GY3nE4uF74YuTYC6LGx7wXS5ivj531KTPe4EarZ4j+aVw9ZJhfy/h+"
"K0esj9ALQP9jSz3OMDKeYaJKjj/scC5NrPdSjeJf7EvlVf41ufZHNGrFVmVW"
"kqaEuNZr+SmC6/2buPEmL4UO94H1z4QItK+rHqNWEQP6ptST0lcFwHO4uESR"
"qp8scA2/Fh+G0TfJ/rg8wImqbWsgrUwGnmDmKtFLRiX4aMPIsyFIsJvPQECT"
"EIR6yd6QIRVGZbCRiVsCqMrHsn0KZWSeKdtW9TRt/yNu+VKcgRZFfU991Nab"
"OBxkAS1kw9kyj/HZYxPG4NrqL0j5bnb1VjqQZKEEQMSBAyMMfDuMyWhrmsxV"
"ffmF/sYGxFHCbacGeu06C3U"
},
#endif
{
0, 0,
NULL,
NULL,
NULL
}
};
int dsa_test(void)
{
mp_int q, p, g, t;
int errno, i, res, primality;
/* init memory */
if (mp_init_multi(&q, &p, &g, &t, NULL) != MP_OKAY) {
return CRYPT_MEM;
}
res = CRYPT_MEM;
for (i = 0; i < sets[i].size; i++) {
#if 0
printf("Testing size: %d\n", sets[i].size);
#endif
/* read in order, prime, generator */
if (mp_read_radix(&q, sets[i].order, 64) != MP_OKAY) { goto error; }
if (mp_read_radix(&p, sets[i].prime, 64) != MP_OKAY) { goto error; }
if (mp_read_radix(&g, sets[i].base, 64) != MP_OKAY) { goto error; }
/* now see if the order and modulus are prime */
if ((errno = is_prime(&q, &primality)) != CRYPT_OK) {
res = errno;
goto error;
}
if (primality == 0) {
res = CRYPT_FAIL_TESTVECTOR;
goto error;
}
if ((errno = is_prime(&p, &primality)) != CRYPT_OK) {
res = errno;
goto error;
}
if (primality == 0) {
res = CRYPT_FAIL_TESTVECTOR;
goto error;
}
/* now see what g^q mod p is (should be 1) */
if (mp_exptmod(&g, &q, &p, &t) != MP_OKAY) { goto error; }
if (mp_cmp_d(&t, 1)) {
res = CRYPT_FAIL_TESTVECTOR;
goto error;
}
}
res = CRYPT_OK;
error:
mp_clear_multi(&t, &g, &p, &q, NULL);
return res;
}
int dsa_make_key(prng_state *prng, int wprng, int keysize, dsa_key *key)
{
mp_int g, p, q;
unsigned char buf[64];
int errno, idx, x;
_ARGCHK(prng != NULL);
_ARGCHK(key != NULL);
/* good prng? */
if ((errno = prng_is_valid(wprng)) != CRYPT_OK) {
return errno;
}
/* find key size */
for (x = 0; (keysize > sets[x].size) && (sets[x].size); x++);
if (sets[x].size == 0) {
return CRYPT_INVALID_KEYSIZE;
}
key->idx = x;
keysize = sets[x].osize;
/* read prng */
if (prng_descriptor[wprng].read(buf, keysize, prng) != (unsigned long)keysize) {
return CRYPT_ERROR_READPRNG;
}
/* init parameters */
if (mp_init_multi(&g, &p, &q, &key->x, &key->y, NULL) != MP_OKAY) {
return CRYPT_MEM;
}
if (mp_read_radix(&q, sets[x].order, 64) != MP_OKAY) { goto error; }
if (mp_read_radix(&g, sets[x].base, 64) != MP_OKAY) { goto error; }
if (mp_read_radix(&p, sets[x].prime, 64) != MP_OKAY) { goto error; }
/* load exponent */
if (mp_read_unsigned_bin(&key->x, buf, keysize) != MP_OKAY) { goto error; }
if (mp_mod(&key->x, &q, &key->x) != MP_OKAY) { goto error; }
/* calc public key */
if (mp_exptmod(&g, &key->x, &p, &key->y) != MP_OKAY) { goto error; }
key->type = PK_PRIVATE;
/* shrink values */
if (mp_shrink(&key->x) != MP_OKAY) { goto error; }
if (mp_shrink(&key->y) != MP_OKAY) { goto error; }
/* free temps */
mp_clear_multi(&g, &q, &p, NULL);
#ifdef CLEAN_STACK
zeromem(buf, sizeof(buf));
#endif
return CRYPT_OK;
error:
mp_clear_multi(&g, &q, &p, &key->x, &key->y, NULL);
return CRYPT_MEM;
}
void dsa_free(dsa_key *key)
{
_ARGCHK(key != NULL);
mp_clear_multi(&key->x, &key->y, NULL);
}
static int is_valid_idx(int n)
{
int x;
for (x = 0; sets[x].size; x++);
if ((n < 0) || (n >= x)) {
return 0;
}
return 1;
}
int dsa_export(unsigned char *out, unsigned long *outlen, int type, dsa_key *key)
{
unsigned char buf[4096];
unsigned long x, y;
_ARGCHK(out != NULL);
_ARGCHK(outlen != NULL);
_ARGCHK(key != NULL);
if (is_valid_idx(key->idx) == 0) {
return CRYPT_PK_INVALID_TYPE;
}
if (type == PK_PRIVATE && key->type != PK_PRIVATE) {
return CRYPT_PK_NOT_PRIVATE;
}
y = PACKET_SIZE;
buf[y++] = type;
buf[y++] = sets[key->idx].osize/8;
x = mp_unsigned_bin_size(&key->y);
STORE32L(x, &buf[y]);
y += 4;
mp_to_unsigned_bin(&key->y, &buf[y]);
y += x;
if (type == PK_PRIVATE) {
x = mp_unsigned_bin_size(&key->x);
STORE32L(x, &buf[y]);
y += 4;
mp_to_unsigned_bin(&key->x, &buf[y]);
y += x;
}
/* check for overflow */
if (*outlen < y) {
#ifdef CLEAN_STACK
zeromem(buf, sizeof(buf));
#endif
return CRYPT_BUFFER_OVERFLOW;
}
/* store header */
packet_store_header(buf, PACKET_SECT_DSA, PACKET_SUB_KEY);
/* output it */
*outlen = y;
memcpy(out, buf, y);
/* clear mem */
#ifdef CLEAN_STACK
zeromem(buf, sizeof(buf));
#endif
return CRYPT_OK;
}
#define INPUT_BIGNUM(num, in, x, y) \
{ \
/* load value */ \
if (y + 4 > inlen) { \
errno = CRYPT_INVALID_PACKET; \
goto error; \
} \
LOAD32L(x, in+y); \
y += 4; \
\
/* sanity check... */ \
if (x+y > inlen) { \
errno = CRYPT_INVALID_PACKET; \
goto error; \
} \
\
/* load it */ \
if (mp_read_unsigned_bin(num, (unsigned char *)in+y, x) != MP_OKAY) {\
errno = CRYPT_MEM; \
goto error; \
} \
y += x; \
if (mp_shrink(num) != MP_OKAY) { \
errno = CRYPT_MEM; \
goto error; \
} \
}
int dsa_import(const unsigned char *in, unsigned long inlen, dsa_key *key)
{
unsigned long x, y, s;
int errno;
_ARGCHK(in != NULL);
_ARGCHK(key != NULL);
/* check type byte */
if ((errno = packet_valid_header((unsigned char *)in, PACKET_SECT_DSA, PACKET_SUB_KEY)) != CRYPT_OK) {
return errno;
}
if (2+PACKET_SIZE > inlen) {
return CRYPT_INVALID_PACKET;
}
/* init */
if (mp_init_multi(&key->x, &key->y, NULL) != MP_OKAY) {
return CRYPT_MEM;
}
y = PACKET_SIZE;
key->type = in[y++];
s = (long)in[y++] * 8;
for (x = 0; (s > (unsigned long)sets[x].osize) && (sets[x].osize); x++);
if (sets[x].osize == 0) {
errno = CRYPT_INVALID_KEYSIZE;
goto error;
}
key->idx = x;
/* type check both values */
if ((key->type != PK_PUBLIC) && (key->type != PK_PRIVATE)) {
errno = CRYPT_PK_TYPE_MISMATCH;
goto error;
}
/* is the key idx valid? */
if (!is_valid_idx(key->idx)) {
errno = CRYPT_PK_TYPE_MISMATCH;
goto error;
}
/* load public value g^x mod p*/
INPUT_BIGNUM(&key->y, in, x, y);
if (key->type == PK_PRIVATE) {
INPUT_BIGNUM(&key->x, in, x, y);
}
/* eliminate private key if public */
if (key->type == PK_PUBLIC) {
mp_clear(&key->x);
}
return CRYPT_OK;
error:
mp_clear_multi(&key->y, &key->x, NULL);
return errno;
}
int dsa_sign_hash(const unsigned char *in, unsigned long inlen,
unsigned char *out, unsigned long *outlen,
prng_state *prng, int wprng, dsa_key *key)
{
mp_int g, q, p, k, tmp;
unsigned char buf[4096];
int x, y, errno;
_ARGCHK(in != NULL);
_ARGCHK(out != NULL);
_ARGCHK(outlen != NULL);
_ARGCHK(prng != NULL);
_ARGCHK(key != NULL);
if ((errno = prng_is_valid(wprng)) != CRYPT_OK) {
return errno;
}
if (is_valid_idx(key->idx) == 0) {
return CRYPT_PK_INVALID_TYPE;
}
return 0;
}
#endif /* MDSA */