diff --git a/demos/timing.c b/demos/timing.c index cb249a5..d075958 100644 --- a/demos/timing.c +++ b/demos/timing.c @@ -646,7 +646,7 @@ static void time_prng(void) /* time various DSA operations */ static void time_dsa(void) { - dsa_key key; + dsa_key key = LTC_DSA_KEY_INITIALIZER; ulong64 t1, t2; unsigned long x, y; int err; @@ -665,7 +665,11 @@ static const struct { for (y = 0; y < 4; y++) { t_start(); t1 = t_read(); - if ((err = dsa_make_key(&yarrow_prng, find_prng("yarrow"), groups[x].group, groups[x].modulus, &key)) != CRYPT_OK) { + if ((err = dsa_generate_pqg(&yarrow_prng, find_prng("yarrow"), groups[x].group, groups[x].modulus, &key)) != CRYPT_OK) { + fprintf(stderr, "\n\ndsa_generate_pqg says %s, wait...no it should say %s...damn you!\n", error_to_string(err), error_to_string(CRYPT_OK)); + exit(EXIT_FAILURE); + } + if ((err = dsa_make_key_ex(&yarrow_prng, find_prng("yarrow"), &key)) != CRYPT_OK) { fprintf(stderr, "\n\ndsa_make_key says %s, wait...no it should say %s...damn you!\n", error_to_string(err), error_to_string(CRYPT_OK)); exit(EXIT_FAILURE); } diff --git a/src/headers/tomcrypt_pk.h b/src/headers/tomcrypt_pk.h index b73b8c0..963d0d1 100644 --- a/src/headers/tomcrypt_pk.h +++ b/src/headers/tomcrypt_pk.h @@ -442,9 +442,20 @@ typedef struct { void *y; } dsa_key; +#define LTC_DSA_KEY_INITIALIZER { PK_PUBLIC, 0, NULL, NULL, NULL, NULL, NULL } + int dsa_make_key(prng_state *prng, int wprng, int group_size, int modulus_size, dsa_key *key); -int dsa_make_key_ex(prng_state *prng, int wprng, int group_size, int modulus_size, dsa_key *key, char* p_hex, char* q_hex, char* g_hex); +int dsa_set_pqg(const unsigned char *p, unsigned long plen, + const unsigned char *q, unsigned long qlen, + const unsigned char *g, unsigned long glen, + dsa_key *key); +int dsa_generate_pqg(prng_state *prng, int wprng, int group_size, int modulus_size, dsa_key *key); + +int dsa_set_key(const unsigned char *pub, unsigned long publen, + const unsigned char *priv, unsigned long privlen, + dsa_key *key); +int dsa_make_key_ex(prng_state *prng, int wprng, dsa_key *key); void dsa_free(dsa_key *key); @@ -473,7 +484,6 @@ int dsa_decrypt_key(const unsigned char *in, unsigned long inlen, unsigned char *out, unsigned long *outlen, dsa_key *key); -int dsa_import_radix(int radix, char *p, char *q, char *g, char *x, char *y, dsa_key *key); int dsa_import(const unsigned char *in, unsigned long inlen, dsa_key *key); int dsa_export(unsigned char *out, unsigned long *outlen, int type, dsa_key *key); int dsa_verify_key(dsa_key *key, int *stat); diff --git a/src/pk/dsa/dsa_generate_pqg.c b/src/pk/dsa/dsa_generate_pqg.c new file mode 100644 index 0000000..5d8c691 --- /dev/null +++ b/src/pk/dsa/dsa_generate_pqg.c @@ -0,0 +1,248 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + */ +#include "tomcrypt.h" + +/** + @file dsa_generate_pqg.c + DSA implementation - generate DSA parameters p, q & g +*/ + +#ifdef LTC_MDSA + +/** + Create DSA parameters (INTERNAL ONLY, not part of public API) + @param prng An active PRNG state + @param wprng The index of the PRNG desired + @param group_size Size of the multiplicative group (octets) + @param modulus_size Size of the modulus (octets) + @param p [out] bignum where generated 'p' is stored (must be initialized by caller) + @param q [out] bignum where generated 'q' is stored (must be initialized by caller) + @param g [out] bignum where generated 'g' is stored (must be initialized by caller) + @return CRYPT_OK if successful, upon error this function will free all allocated memory +*/ +static int _dsa_make_params(prng_state *prng, int wprng, int group_size, int modulus_size, void *p, void *q, void *g) +{ + unsigned long L, N, n, outbytes, seedbytes, counter, j, i; + int err, res, mr_tests_q, mr_tests_p, found_p, found_q, hash; + unsigned char *wbuf, *sbuf, digest[MAXBLOCKSIZE]; + void *t2L1, *t2N1, *t2q, *t2seedlen, *U, *W, *X, *c, *h, *e, *seedinc; + + /* check size */ + if (group_size >= LTC_MDSA_MAX_GROUP || group_size < 1 || group_size >= modulus_size) { + return CRYPT_INVALID_ARG; + } + + /* FIPS-186-4 A.1.1.2 Generation of the Probable Primes p and q Using an Approved Hash Function + * + * L = The desired length of the prime p (in bits e.g. L = 1024) + * N = The desired length of the prime q (in bits e.g. N = 160) + * seedlen = The desired bit length of the domain parameter seed; seedlen shallbe equal to or greater than N + * outlen = The bit length of Hash function + * + * 1. Check that the (L, N) + * 2. If (seedlen = 2^(L-1)) { + * Test whether or not p is prime as specified in Appendix C.3. + * If p is determined to be prime, then return VALID and the values of p, qand (optionally) the values of domain_parameter_seed and counter + * } + * offset = offset + n + 1 Comment: Increment offset + * } + */ + + seedbytes = group_size; + L = modulus_size * 8; + N = group_size * 8; + + /* XXX-TODO no Lucas test */ +#ifdef LTC_MPI_HAS_LUCAS_TEST + /* M-R tests (when followed by one Lucas test) according FIPS-186-4 - Appendix C.3 - table C.1 */ + mr_tests_p = (L <= 2048) ? 3 : 2; + if (N <= 160) { mr_tests_q = 19; } + else if (N <= 224) { mr_tests_q = 24; } + else { mr_tests_q = 27; } +#else + /* M-R tests (without Lucas test) according FIPS-186-4 - Appendix C.3 - table C.1 */ + if (L <= 1024) { mr_tests_p = 40; } + else if (L <= 2048) { mr_tests_p = 56; } + else { mr_tests_p = 64; } + + if (N <= 160) { mr_tests_q = 40; } + else if (N <= 224) { mr_tests_q = 56; } + else { mr_tests_q = 64; } +#endif + + if (N <= 256) { + hash = register_hash(&sha256_desc); + } + else if (N <= 384) { + hash = register_hash(&sha384_desc); + } + else if (N <= 512) { + hash = register_hash(&sha512_desc); + } + else { + return CRYPT_INVALID_ARG; /* group_size too big */ + } + + if ((err = hash_is_valid(hash)) != CRYPT_OK) { return err; } + outbytes = hash_descriptor[hash].hashsize; + + n = ((L + outbytes*8 - 1) / (outbytes*8)) - 1; + + if ((wbuf = XMALLOC((n+1)*outbytes)) == NULL) { err = CRYPT_MEM; goto cleanup3; } + if ((sbuf = XMALLOC(seedbytes)) == NULL) { err = CRYPT_MEM; goto cleanup2; } + + err = mp_init_multi(&t2L1, &t2N1, &t2q, &t2seedlen, &U, &W, &X, &c, &h, &e, &seedinc, NULL); + if (err != CRYPT_OK) { goto cleanup1; } + + if ((err = mp_2expt(t2L1, L-1)) != CRYPT_OK) { goto cleanup; } + /* t2L1 = 2^(L-1) */ + if ((err = mp_2expt(t2N1, N-1)) != CRYPT_OK) { goto cleanup; } + /* t2N1 = 2^(N-1) */ + if ((err = mp_2expt(t2seedlen, seedbytes*8)) != CRYPT_OK) { goto cleanup; } + /* t2seedlen = 2^seedlen */ + + for(found_p=0; !found_p;) { + /* q */ + for(found_q=0; !found_q;) { + if (prng_descriptor[wprng].read(sbuf, seedbytes, prng) != seedbytes) { err = CRYPT_ERROR_READPRNG; goto cleanup; } + i = outbytes; + if ((err = hash_memory(hash, sbuf, seedbytes, digest, &i)) != CRYPT_OK) { goto cleanup; } + if ((err = mp_read_unsigned_bin(U, digest, outbytes)) != CRYPT_OK) { goto cleanup; } + if ((err = mp_mod(U, t2N1, U)) != CRYPT_OK) { goto cleanup; } + if ((err = mp_add(t2N1, U, q)) != CRYPT_OK) { goto cleanup; } + if (!mp_isodd(q)) mp_add_d(q, 1, q); + if ((err = mp_prime_is_prime(q, mr_tests_q, &res)) != CRYPT_OK) { goto cleanup; } + if (res == LTC_MP_YES) found_q = 1; + } + + /* p */ + if ((err = mp_read_unsigned_bin(seedinc, sbuf, seedbytes)) != CRYPT_OK) { goto cleanup; } + if ((err = mp_add(q, q, t2q)) != CRYPT_OK) { goto cleanup; } + for(counter=0; counter < 4*L && !found_p; counter++) { + for(j=0; j<=n; j++) { + if ((err = mp_add_d(seedinc, 1, seedinc)) != CRYPT_OK) { goto cleanup; } + if ((err = mp_mod(seedinc, t2seedlen, seedinc)) != CRYPT_OK) { goto cleanup; } + /* seedinc = (seedinc+1) % 2^seed_bitlen */ + if ((i = mp_unsigned_bin_size(seedinc)) > seedbytes) { err = CRYPT_INVALID_ARG; goto cleanup; } + zeromem(sbuf, seedbytes); + if ((err = mp_to_unsigned_bin(seedinc, sbuf + seedbytes-i)) != CRYPT_OK) { goto cleanup; } + i = outbytes; + err = hash_memory(hash, sbuf, seedbytes, wbuf+(n-j)*outbytes, &i); + if (err != CRYPT_OK) { goto cleanup; } + } + if ((err = mp_read_unsigned_bin(W, wbuf, (n+1)*outbytes)) != CRYPT_OK) { goto cleanup; } + if ((err = mp_mod(W, t2L1, W)) != CRYPT_OK) { goto cleanup; } + if ((err = mp_add(W, t2L1, X)) != CRYPT_OK) { goto cleanup; } + if ((err = mp_mod(X, t2q, c)) != CRYPT_OK) { goto cleanup; } + if ((err = mp_sub_d(c, 1, p)) != CRYPT_OK) { goto cleanup; } + if ((err = mp_sub(X, p, p)) != CRYPT_OK) { goto cleanup; } + if (mp_cmp(p, t2L1) != LTC_MP_LT) { + /* p >= 2^(L-1) */ + if ((err = mp_prime_is_prime(p, mr_tests_p, &res)) != CRYPT_OK) { goto cleanup; } + if (res == LTC_MP_YES) { + found_p = 1; + } + } + } + } + + /* FIPS-186-4 A.2.1 Unverifiable Generation of the Generator g + * 1. e = (p - 1)/q + * 2. h = any integer satisfying: 1 < h < (p - 1) + * h could be obtained from a random number generator or from a counter that changes after each use + * 3. g = h^e mod p + * 4. if (g == 1), then go to step 2. + * + */ + + if ((err = mp_sub_d(p, 1, e)) != CRYPT_OK) { goto cleanup; } + if ((err = mp_div(e, q, e, c)) != CRYPT_OK) { goto cleanup; } + /* e = (p - 1)/q */ + i = mp_count_bits(p); + do { + do { + if ((err = rand_bn_bits(h, i, prng, wprng)) != CRYPT_OK) { goto cleanup; } + } while (mp_cmp(h, p) != LTC_MP_LT || mp_cmp_d(h, 2) != LTC_MP_GT); + if ((err = mp_sub_d(h, 1, h)) != CRYPT_OK) { goto cleanup; } + /* h is randon and 1 < h < (p-1) */ + if ((err = mp_exptmod(h, e, p, g)) != CRYPT_OK) { goto cleanup; } + } while (mp_cmp_d(g, 1) == LTC_MP_EQ); + + err = CRYPT_OK; +cleanup: + mp_clear_multi(t2L1, t2N1, t2q, t2seedlen, U, W, X, c, h, e, seedinc, NULL); +cleanup1: + XFREE(sbuf); +cleanup2: + XFREE(wbuf); +cleanup3: + return err; +} + +/** + Generate DSA parameters p, q & g + @param prng An active PRNG state + @param wprng The index of the PRNG desired + @param group_size Size of the multiplicative group (octets) + @param modulus_size Size of the modulus (octets) + @param key [out] Where to store the created key + @return CRYPT_OK if successful. +*/ +int dsa_generate_pqg(prng_state *prng, int wprng, int group_size, int modulus_size, dsa_key *key) +{ + int err; + + LTC_ARGCHK(key != NULL); + LTC_ARGCHK(key->x == NULL); + LTC_ARGCHK(key->y == NULL); + LTC_ARGCHK(key->p == NULL); + LTC_ARGCHK(key->g == NULL); + LTC_ARGCHK(key->q == NULL); + LTC_ARGCHK(key->qord == 0); + LTC_ARGCHK(ltc_mp.name != NULL); + + /* init mp_ints */ + if ((err = mp_init_multi(&key->g, &key->q, &key->p, &key->x, &key->y, NULL)) != CRYPT_OK) { + return err; + } + /* generate params */ + err = _dsa_make_params(prng, wprng, group_size, modulus_size, key->p, key->q, key->g); + if (err != CRYPT_OK) { goto cleanup; } + + key->qord = group_size; + + return CRYPT_OK; + +cleanup: + dsa_free(key); + return err; +} + +#endif + +/* ref: $Format:%D$ */ +/* git commit: $Format:%H$ */ +/* commit time: $Format:%ai$ */ diff --git a/src/pk/dsa/dsa_import_radix.c b/src/pk/dsa/dsa_import_radix.c deleted file mode 100755 index 141030d..0000000 --- a/src/pk/dsa/dsa_import_radix.c +++ /dev/null @@ -1,69 +0,0 @@ -/* LibTomCrypt, modular cryptographic library -- Tom St Denis - * - * LibTomCrypt is a library that provides various cryptographic - * algorithms in a highly modular and flexible manner. - * - * The library is free for all purposes without any express - * guarantee it works. - */ -#include "tomcrypt.h" - -/** - Import DSA public or private key from raw numbers - @param radix the radix the numbers are represented in (2-64, 16 = hexadecimal) - @param p DSA's p in radix representation - @param q DSA's q in radix representation - @param g DSA's g in radix representation - @param x DSA's x in radix representation (only private key, NULL for public key) - @param y DSA's y in radix representation - @param key [out] the destination for the imported key - @return CRYPT_OK if successful, upon error allocated memory is freed -*/ - -#ifdef LTC_MDSA - -int dsa_import_radix(int radix, char *p, char *q, char *g, char *x, char *y, dsa_key *key) -{ - int err; - - LTC_ARGCHK(p != NULL); - LTC_ARGCHK(q != NULL); - LTC_ARGCHK(g != NULL); - LTC_ARGCHK(y != NULL); - LTC_ARGCHK(ltc_mp.name != NULL); - - /* init key */ - err = mp_init_multi(&key->p, &key->g, &key->q, &key->x, &key->y, NULL); - if (err != CRYPT_OK) return err; - - if ((err = mp_read_radix(key->p , p , radix)) != CRYPT_OK) { goto LBL_ERR; } - if ((err = mp_read_radix(key->q , q , radix)) != CRYPT_OK) { goto LBL_ERR; } - if ((err = mp_read_radix(key->g , g , radix)) != CRYPT_OK) { goto LBL_ERR; } - if ((err = mp_read_radix(key->y , y , radix)) != CRYPT_OK) { goto LBL_ERR; } - if (x && strlen(x) > 0) { - key->type = PK_PRIVATE; - if ((err = mp_read_radix(key->x , x , radix)) != CRYPT_OK) { goto LBL_ERR; } - } - else { - key->type = PK_PUBLIC; - } - - key->qord = mp_unsigned_bin_size(key->q); - - if (key->qord >= LTC_MDSA_MAX_GROUP || key->qord <= 15 || - (unsigned long)key->qord >= mp_unsigned_bin_size(key->p) || (mp_unsigned_bin_size(key->p) - key->qord) >= LTC_MDSA_DELTA) { - err = CRYPT_INVALID_PACKET; - goto LBL_ERR; - } - return CRYPT_OK; - -LBL_ERR: - mp_clear_multi(key->p, key->g, key->q, key->x, key->y, NULL); - return err; -} - -#endif - -/* ref: $Format:%D$ */ -/* git commit: $Format:%H$ */ -/* commit time: $Format:%ai$ */ diff --git a/src/pk/dsa/dsa_make_key.c b/src/pk/dsa/dsa_make_key.c index bec09c9..ff61ca7 100644 --- a/src/pk/dsa/dsa_make_key.c +++ b/src/pk/dsa/dsa_make_key.c @@ -10,265 +10,61 @@ /** @file dsa_make_key.c - DSA implementation, generate a DSA key, Tom St Denis + DSA implementation, generate a DSA key */ #ifdef LTC_MDSA /** - Create DSA parameters (INTERNAL ONLY, not part of public API) + Create a DSA key @param prng An active PRNG state @param wprng The index of the PRNG desired - @param group_size Size of the multiplicative group (octets) - @param modulus_size Size of the modulus (octets) - @param p [out] bignum where generated 'p' is stored (must be initialized by caller) - @param q [out] bignum where generated 'q' is stored (must be initialized by caller) - @param g [out] bignum where generated 'g' is stored (must be initialized by caller) - @return CRYPT_OK if successful, upon error this function will free all allocated memory + @param key [in/out] Where to store the created key + @return CRYPT_OK if successful. */ -static int _dsa_make_params(prng_state *prng, int wprng, int group_size, int modulus_size, void *p, void *q, void *g) -{ - unsigned long L, N, n, outbytes, seedbytes, counter, j, i; - int err, res, mr_tests_q, mr_tests_p, found_p, found_q, hash; - unsigned char *wbuf, *sbuf, digest[MAXBLOCKSIZE]; - void *t2L1, *t2N1, *t2q, *t2seedlen, *U, *W, *X, *c, *h, *e, *seedinc; - - /* check size */ - if (group_size >= LTC_MDSA_MAX_GROUP || group_size < 1 || group_size >= modulus_size) { - return CRYPT_INVALID_ARG; - } - - /* FIPS-186-4 A.1.1.2 Generation of the Probable Primes p and q Using an Approved Hash Function - * - * L = The desired length of the prime p (in bits e.g. L = 1024) - * N = The desired length of the prime q (in bits e.g. N = 160) - * seedlen = The desired bit length of the domain parameter seed; seedlen shallbe equal to or greater than N - * outlen = The bit length of Hash function - * - * 1. Check that the (L, N) - * 2. If (seedlen = 2^(L-1)) { - * Test whether or not p is prime as specified in Appendix C.3. - * If p is determined to be prime, then return VALID and the values of p, qand (optionally) the values of domain_parameter_seed and counter - * } - * offset = offset + n + 1 Comment: Increment offset - * } - */ - - seedbytes = group_size; - L = modulus_size * 8; - N = group_size * 8; - - /* XXX-TODO no Lucas test */ -#ifdef LTC_MPI_HAS_LUCAS_TEST - /* M-R tests (when followed by one Lucas test) according FIPS-186-4 - Appendix C.3 - table C.1 */ - mr_tests_p = (L <= 2048) ? 3 : 2; - if (N <= 160) { mr_tests_q = 19; } - else if (N <= 224) { mr_tests_q = 24; } - else { mr_tests_q = 27; } -#else - /* M-R tests (without Lucas test) according FIPS-186-4 - Appendix C.3 - table C.1 */ - if (L <= 1024) { mr_tests_p = 40; } - else if (L <= 2048) { mr_tests_p = 56; } - else { mr_tests_p = 64; } - - if (N <= 160) { mr_tests_q = 40; } - else if (N <= 224) { mr_tests_q = 56; } - else { mr_tests_q = 64; } -#endif - - if (N <= 256) { - hash = register_hash(&sha256_desc); - } - else if (N <= 384) { - hash = register_hash(&sha384_desc); - } - else if (N <= 512) { - hash = register_hash(&sha512_desc); - } - else { - return CRYPT_INVALID_ARG; /* group_size too big */ - } - - if ((err = hash_is_valid(hash)) != CRYPT_OK) { return err; } - outbytes = hash_descriptor[hash].hashsize; - - n = ((L + outbytes*8 - 1) / (outbytes*8)) - 1; - - if ((wbuf = XMALLOC((n+1)*outbytes)) == NULL) { err = CRYPT_MEM; goto cleanup3; } - if ((sbuf = XMALLOC(seedbytes)) == NULL) { err = CRYPT_MEM; goto cleanup2; } - - err = mp_init_multi(&t2L1, &t2N1, &t2q, &t2seedlen, &U, &W, &X, &c, &h, &e, &seedinc, NULL); - if (err != CRYPT_OK) { goto cleanup1; } - - if ((err = mp_2expt(t2L1, L-1)) != CRYPT_OK) { goto cleanup; } - /* t2L1 = 2^(L-1) */ - if ((err = mp_2expt(t2N1, N-1)) != CRYPT_OK) { goto cleanup; } - /* t2N1 = 2^(N-1) */ - if ((err = mp_2expt(t2seedlen, seedbytes*8)) != CRYPT_OK) { goto cleanup; } - /* t2seedlen = 2^seedlen */ - - for(found_p=0; !found_p;) { - /* q */ - for(found_q=0; !found_q;) { - if (prng_descriptor[wprng].read(sbuf, seedbytes, prng) != seedbytes) { err = CRYPT_ERROR_READPRNG; goto cleanup; } - i = outbytes; - if ((err = hash_memory(hash, sbuf, seedbytes, digest, &i)) != CRYPT_OK) { goto cleanup; } - if ((err = mp_read_unsigned_bin(U, digest, outbytes)) != CRYPT_OK) { goto cleanup; } - if ((err = mp_mod(U, t2N1, U)) != CRYPT_OK) { goto cleanup; } - if ((err = mp_add(t2N1, U, q)) != CRYPT_OK) { goto cleanup; } - if (!mp_isodd(q)) mp_add_d(q, 1, q); - if ((err = mp_prime_is_prime(q, mr_tests_q, &res)) != CRYPT_OK) { goto cleanup; } - if (res == LTC_MP_YES) found_q = 1; - } - - /* p */ - if ((err = mp_read_unsigned_bin(seedinc, sbuf, seedbytes)) != CRYPT_OK) { goto cleanup; } - if ((err = mp_add(q, q, t2q)) != CRYPT_OK) { goto cleanup; } - for(counter=0; counter < 4*L && !found_p; counter++) { - for(j=0; j<=n; j++) { - if ((err = mp_add_d(seedinc, 1, seedinc)) != CRYPT_OK) { goto cleanup; } - if ((err = mp_mod(seedinc, t2seedlen, seedinc)) != CRYPT_OK) { goto cleanup; } - /* seedinc = (seedinc+1) % 2^seed_bitlen */ - if ((i = mp_unsigned_bin_size(seedinc)) > seedbytes) { err = CRYPT_INVALID_ARG; goto cleanup; } - zeromem(sbuf, seedbytes); - if ((err = mp_to_unsigned_bin(seedinc, sbuf + seedbytes-i)) != CRYPT_OK) { goto cleanup; } - i = outbytes; - err = hash_memory(hash, sbuf, seedbytes, wbuf+(n-j)*outbytes, &i); - if (err != CRYPT_OK) { goto cleanup; } - } - if ((err = mp_read_unsigned_bin(W, wbuf, (n+1)*outbytes)) != CRYPT_OK) { goto cleanup; } - if ((err = mp_mod(W, t2L1, W)) != CRYPT_OK) { goto cleanup; } - if ((err = mp_add(W, t2L1, X)) != CRYPT_OK) { goto cleanup; } - if ((err = mp_mod(X, t2q, c)) != CRYPT_OK) { goto cleanup; } - if ((err = mp_sub_d(c, 1, p)) != CRYPT_OK) { goto cleanup; } - if ((err = mp_sub(X, p, p)) != CRYPT_OK) { goto cleanup; } - if (mp_cmp(p, t2L1) != LTC_MP_LT) { - /* p >= 2^(L-1) */ - if ((err = mp_prime_is_prime(p, mr_tests_p, &res)) != CRYPT_OK) { goto cleanup; } - if (res == LTC_MP_YES) { - found_p = 1; - } - } - } - } - - /* FIPS-186-4 A.2.1 Unverifiable Generation of the Generator g - * 1. e = (p - 1)/q - * 2. h = any integer satisfying: 1 < h < (p - 1) - * h could be obtained from a random number generator or from a counter that changes after each use - * 3. g = h^e mod p - * 4. if (g == 1), then go to step 2. - * - */ - - if ((err = mp_sub_d(p, 1, e)) != CRYPT_OK) { goto cleanup; } - if ((err = mp_div(e, q, e, c)) != CRYPT_OK) { goto cleanup; } - /* e = (p - 1)/q */ - i = mp_count_bits(p); - do { - do { - if ((err = rand_bn_bits(h, i, prng, wprng)) != CRYPT_OK) { goto cleanup; } - } while (mp_cmp(h, p) != LTC_MP_LT || mp_cmp_d(h, 2) != LTC_MP_GT); - if ((err = mp_sub_d(h, 1, h)) != CRYPT_OK) { goto cleanup; } - /* h is randon and 1 < h < (p-1) */ - if ((err = mp_exptmod(h, e, p, g)) != CRYPT_OK) { goto cleanup; } - } while (mp_cmp_d(g, 1) == LTC_MP_EQ); - - err = CRYPT_OK; -cleanup: - mp_clear_multi(t2L1, t2N1, t2q, t2seedlen, U, W, X, c, h, e, seedinc, NULL); -cleanup1: - XFREE(sbuf); -cleanup2: - XFREE(wbuf); -cleanup3: - return err; -} - -/** - Create a DSA key (with given params) - @param prng An active PRNG state - @param wprng The index of the PRNG desired - @param group_size Size of the multiplicative group (octets) - @param modulus_size Size of the modulus (octets) - @param key [out] Where to store the created key - @param p_hex Hexadecimal string 'p' - @param q_hex Hexadecimal string 'q' - @param g_hex Hexadecimal string 'g' - @return CRYPT_OK if successful, upon error this function will free all allocated memory -*/ -int dsa_make_key_ex(prng_state *prng, int wprng, int group_size, int modulus_size, dsa_key *key, char* p_hex, char* q_hex, char* g_hex) +int dsa_make_key_ex(prng_state *prng, int wprng, dsa_key *key) { int err, qbits; - LTC_ARGCHK(key != NULL); - - /* init mp_ints */ - if ((err = mp_init_multi(&key->g, &key->q, &key->p, &key->x, &key->y, NULL)) != CRYPT_OK) { - return err; - } - - if (p_hex == NULL || q_hex == NULL || g_hex == NULL) { - /* generate params */ - err = _dsa_make_params(prng, wprng, group_size, modulus_size, key->p, key->q, key->g); - if (err != CRYPT_OK) { goto cleanup; } - } - else { - /* read params */ - if ((err = mp_read_radix(key->p, p_hex, 16)) != CRYPT_OK) { goto cleanup; } - if ((err = mp_read_radix(key->q, q_hex, 16)) != CRYPT_OK) { goto cleanup; } - if ((err = mp_read_radix(key->g, g_hex, 16)) != CRYPT_OK) { goto cleanup; } - /* XXX-TODO maybe do some validity check for p, q, g */ - } + LTC_ARGCHK(key != NULL); + LTC_ARGCHK(key->x != NULL); + LTC_ARGCHK(key->y != NULL); + LTC_ARGCHK(key->p != NULL); + LTC_ARGCHK(key->g != NULL); + LTC_ARGCHK(key->q != NULL); + LTC_ARGCHK(ltc_mp.name != NULL); /* so now we have our DH structure, generator g, order q, modulus p Now we need a random exponent [mod q] and it's power g^x mod p */ qbits = mp_count_bits(key->q); do { - if ((err = rand_bn_bits(key->x, qbits, prng, wprng)) != CRYPT_OK) { goto cleanup; } + if ((err = rand_bn_bits(key->x, qbits, prng, wprng)) != CRYPT_OK) { return err; } /* private key x should be from range: 1 <= x <= q-1 (see FIPS 186-4 B.1.2) */ } while (mp_cmp_d(key->x, 0) != LTC_MP_GT || mp_cmp(key->x, key->q) != LTC_MP_LT); - if ((err = mp_exptmod(key->g, key->x, key->p, key->y)) != CRYPT_OK) { goto cleanup; } + if ((err = mp_exptmod(key->g, key->x, key->p, key->y)) != CRYPT_OK) { return err; } key->type = PK_PRIVATE; - key->qord = group_size; return CRYPT_OK; - -cleanup: - mp_clear_multi(key->g, key->q, key->p, key->x, key->y, NULL); - return err; } /** - Create a DSA key + Old-style creation of a DSA key @param prng An active PRNG state @param wprng The index of the PRNG desired @param group_size Size of the multiplicative group (octets) @param modulus_size Size of the modulus (octets) @param key [out] Where to store the created key - @return CRYPT_OK if successful, upon error this function will free all allocated memory + @return CRYPT_OK if successful. */ int dsa_make_key(prng_state *prng, int wprng, int group_size, int modulus_size, dsa_key *key) { - return dsa_make_key_ex(prng, wprng, group_size, modulus_size, key, NULL, NULL, NULL); + int err; + + if ((err = dsa_generate_pqg(prng, wprng, group_size, modulus_size, key)) != CRYPT_OK) { return err; } + if ((err = dsa_make_key_ex(prng, wprng, key)) != CRYPT_OK) { return err; } + + return CRYPT_OK; } #endif diff --git a/src/pk/dsa/dsa_set.c b/src/pk/dsa/dsa_set.c new file mode 100755 index 0000000..32e5d3b --- /dev/null +++ b/src/pk/dsa/dsa_set.c @@ -0,0 +1,105 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + */ +#include "tomcrypt.h" + + +#ifdef LTC_MDSA + +/** + Import DSA public or private key from raw numbers + @param p DSA's p in binary representation + @param q DSA's q in binary representation + @param g DSA's g in binary representation + @param key [out] the destination for the imported key + @return CRYPT_OK if successful, upon error allocated memory is freed +*/ +int dsa_set_pqg(const unsigned char *p, unsigned long plen, + const unsigned char *q, unsigned long qlen, + const unsigned char *g, unsigned long glen, + dsa_key *key) +{ + int err; + + LTC_ARGCHK(p != NULL); + LTC_ARGCHK(q != NULL); + LTC_ARGCHK(g != NULL); + LTC_ARGCHK(key != NULL); + LTC_ARGCHK(key->x == NULL); + LTC_ARGCHK(key->y == NULL); + LTC_ARGCHK(key->p == NULL); + LTC_ARGCHK(key->g == NULL); + LTC_ARGCHK(key->q == NULL); + LTC_ARGCHK(key->qord == 0); + LTC_ARGCHK(ltc_mp.name != NULL); + + /* init key */ + err = mp_init_multi(&key->p, &key->g, &key->q, &key->x, &key->y, NULL); + if (err != CRYPT_OK) return err; + + if ((err = mp_read_unsigned_bin(key->p , (unsigned char *)p , plen)) != CRYPT_OK) { goto LBL_ERR; } + if ((err = mp_read_unsigned_bin(key->g , (unsigned char *)g , glen)) != CRYPT_OK) { goto LBL_ERR; } + if ((err = mp_read_unsigned_bin(key->q , (unsigned char *)q , qlen)) != CRYPT_OK) { goto LBL_ERR; } + + key->qord = mp_unsigned_bin_size(key->q); + + if (key->qord >= LTC_MDSA_MAX_GROUP || key->qord <= 15 || + (unsigned long)key->qord >= mp_unsigned_bin_size(key->p) || (mp_unsigned_bin_size(key->p) - key->qord) >= LTC_MDSA_DELTA) { + err = CRYPT_INVALID_PACKET; + goto LBL_ERR; + } + return CRYPT_OK; + +LBL_ERR: + dsa_free(key); + return err; +} + + +/** + Import DSA public or private key from raw numbers + @param x DSA's x in binary representation (only private key, NULL for public key) + @param y DSA's y in binary representation + @param key [out] the destination for the imported key + @return CRYPT_OK if successful, upon error allocated memory is freed +*/ +int dsa_set_key(const unsigned char *pub, unsigned long publen, + const unsigned char *priv, unsigned long privlen, + dsa_key *key) +{ + int err; + + LTC_ARGCHK(key != NULL); + LTC_ARGCHK(key->x != NULL); + LTC_ARGCHK(key->y != NULL); + LTC_ARGCHK(key->p != NULL); + LTC_ARGCHK(key->g != NULL); + LTC_ARGCHK(key->q != NULL); + LTC_ARGCHK(ltc_mp.name != NULL); + + if ((err = mp_read_unsigned_bin(key->y , (unsigned char *)pub , publen)) != CRYPT_OK) { goto LBL_ERR; } + if (priv != NULL) { + key->type = PK_PRIVATE; + if ((err = mp_read_unsigned_bin(key->x , (unsigned char *)priv , privlen)) != CRYPT_OK) { goto LBL_ERR; } + } + else { + key->type = PK_PUBLIC; + } + + return CRYPT_OK; + +LBL_ERR: + dsa_free(key); + return err; +} + +#endif + +/* ref: $Format:%D$ */ +/* git commit: $Format:%H$ */ +/* commit time: $Format:%ai$ */ diff --git a/tests/dsa_test.c b/tests/dsa_test.c index c62c380..9cee7af 100644 --- a/tests/dsa_test.c +++ b/tests/dsa_test.c @@ -59,13 +59,6 @@ static char *hex_q = "AA5BD7F4E5062413E58835CA00C7A635716194C5"; static char *hex_x = "9936E5E4E9FB28BE91F5065FE8C935B3F5D81FC5"; static char *hex_y = "5316B0FBBF598A5E5595C14FAC43B80853E6CF0D9223FAB184595239BFCBF22D383ADD935205497E2B12C46173E36F54BD96E5A7AAA95A58A4B767D2C0BDC81EB13A124F98C005EF395D6ABAB70B3BD8B795DD796EA2D28473470388B464D9B9B84FF1C934BBF97366F57C2E11FEC331E60838596781EB6D4127D70D74AFA035"; -/* private key - raw decimal numbers */ -static char *dec_g = "41834149751984197912953436480983170533071735026506895442815002322147255782590882063707309354781506433716654796985480894012184326029507913813728323760888731712844346877576824916725534905000120412305763983626878322597033839508975868744887842375259196379140567488975525420966465471602331600963525846901216912348"; -static char *dec_p = "138366127874251453574215823372867983172559870428080754538874699342292548213873551009389476481395012375639515165022292709776266658812209612126692196557051247870332681145778007636026326219557730049370214260237710845864302921876857532769906463917243319959886290876544710558897185626634470575981605420411381006287"; -static char *dec_q = "972576611327916959546542817054443329226761409733"; -static char *dec_x = "874699854785640347852049895863914110365034094533"; -static char *dec_y = "58346825863862115220306694056113472976936045407556113559931032566376300411053620606958863235131122432665794570437845128216268156672161823000705623178942581094085367656740608001229642983928728905397237964247962716781137229394844332774819193277135681825866994604976120931444766148118918668354923664000689348661"; - /* The public part of test_dsa.key in SubjectPublicKeyInfo format */ static const unsigned char openssl_pub_dsa[] = { 0x30, 0x82, 0x01, 0xb6, 0x30, 0x82, 0x01, 0x2b, 0x06, 0x07, 0x2a, 0x86, @@ -107,11 +100,13 @@ static const unsigned char openssl_pub_dsa[] = { 0xeb, 0x6d, 0x41, 0x27, 0xd7, 0x0d, 0x74, 0xaf, 0xa0, 0x35 }; -static int dsa_compat_test(void) +static int _dsa_compat_test(void) { - dsa_key key; + dsa_key key = LTC_DSA_KEY_INITIALIZER; unsigned char tmp[1024], buf[1024]; unsigned long x, len; + unsigned char key_parts[5][256]; + unsigned long key_lens[5]; DO(dsa_import(openssl_priv_dsa, sizeof(openssl_priv_dsa), &key)); @@ -135,7 +130,22 @@ static int dsa_compat_test(void) dsa_free(&key); /* try import private key from raw hexadecimal numbers */ - DO(dsa_import_radix(16, hex_p, hex_q, hex_g, hex_x, hex_y, &key)); + for (x = 0; x < 5; ++x) { + key_lens[x] = sizeof(key_parts[x]); + } + DO(radix_to_bin(hex_p, 16, key_parts[0], &key_lens[0])); + DO(radix_to_bin(hex_q, 16, key_parts[1], &key_lens[1])); + DO(radix_to_bin(hex_g, 16, key_parts[2], &key_lens[2])); + DO(radix_to_bin(hex_y, 16, key_parts[3], &key_lens[3])); + DO(radix_to_bin(hex_x, 16, key_parts[4], &key_lens[4])); + + DO(dsa_set_pqg(key_parts[0], key_lens[0], + key_parts[1], key_lens[1], + key_parts[2], key_lens[2], + &key)); + DO(dsa_set_key(key_parts[3], key_lens[3], + key_parts[4], key_lens[4], + &key)); len = sizeof(buf); DO(dsa_export(buf, &len, PK_PRIVATE | PK_STD, &key)); if (len != sizeof(openssl_priv_dsa) || memcmp(buf, openssl_priv_dsa, len)) { @@ -144,18 +154,14 @@ static int dsa_compat_test(void) } dsa_free(&key); - /* try import private key from raw decimal numbers */ - DO(dsa_import_radix(10, dec_p, dec_q, dec_g, dec_x, dec_y, &key)); - len = sizeof(buf); - DO(dsa_export(buf, &len, PK_PRIVATE | PK_STD, &key)); - if (len != sizeof(openssl_priv_dsa) || memcmp(buf, openssl_priv_dsa, len)) { - fprintf(stderr, "DSA private export failed to match dsa_import_radix(10, ..)\n"); - return 1; - } - dsa_free(&key); - /* try import public key from raw hexadecimal numbers */ - DO(dsa_import_radix(16, hex_p, hex_q, hex_g, NULL, hex_y, &key)); + DO(dsa_set_pqg(key_parts[0], key_lens[0], + key_parts[1], key_lens[1], + key_parts[2], key_lens[2], + &key)); + DO(dsa_set_key(key_parts[3], key_lens[3], + NULL, 0, + &key)); len = sizeof(buf); DO(dsa_export(buf, &len, PK_PUBLIC | PK_STD, &key)); if (len != sizeof(openssl_pub_dsa) || memcmp(buf, openssl_pub_dsa, len)) { @@ -164,16 +170,6 @@ static int dsa_compat_test(void) } dsa_free(&key); - /* try import public key from raw decimal numbers */ - DO(dsa_import_radix(10, dec_p, dec_q, dec_g, NULL, dec_y, &key)); - len = sizeof(buf); - DO(dsa_export(buf, &len, PK_PUBLIC | PK_STD, &key)); - if (len != sizeof(openssl_pub_dsa) || memcmp(buf, openssl_pub_dsa, len)) { - fprintf(stderr, "DSA public export failed to match dsa_import_radix(10, ..)\n"); - return 1; - } - dsa_free(&key); - return 0; } @@ -182,12 +178,14 @@ int dsa_test(void) unsigned char msg[16], out[1024], out2[1024], ch; unsigned long x, y; int stat1, stat2; - dsa_key key, key2; + dsa_key key = LTC_DSA_KEY_INITIALIZER; + dsa_key key2 = LTC_DSA_KEY_INITIALIZER; - dsa_compat_test(); + _dsa_compat_test(); /* make a random key */ - DO(dsa_make_key(&yarrow_prng, find_prng("yarrow"), 20, 128, &key)); + DO(dsa_generate_pqg(&yarrow_prng, find_prng("yarrow"), 20, 128, &key)); + DO(dsa_make_key_ex(&yarrow_prng, find_prng("yarrow"), &key)); /* verify it */ DO(dsa_verify_key(&key, &stat1));