From 4f2eb1914bdac3ed3ee504ad86061281dbe0d074 Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Fri, 9 Feb 2018 21:44:05 +0800 Subject: Update to libtomcrypt 1.18.1, merged with Dropbear changes --- libtomcrypt/src/pk/dsa/dsa_decrypt_key.c | 32 ++-- libtomcrypt/src/pk/dsa/dsa_encrypt_key.c | 45 ++--- libtomcrypt/src/pk/dsa/dsa_export.c | 90 +++++++--- libtomcrypt/src/pk/dsa/dsa_free.c | 11 +- libtomcrypt/src/pk/dsa/dsa_generate_key.c | 47 +++++ libtomcrypt/src/pk/dsa/dsa_generate_pqg.c | 244 ++++++++++++++++++++++++++ libtomcrypt/src/pk/dsa/dsa_import.c | 138 +++++++++++---- libtomcrypt/src/pk/dsa/dsa_make_key.c | 116 ++---------- libtomcrypt/src/pk/dsa/dsa_set.c | 112 ++++++++++++ libtomcrypt/src/pk/dsa/dsa_set_pqg_dsaparam.c | 67 +++++++ libtomcrypt/src/pk/dsa/dsa_shared_secret.c | 14 +- libtomcrypt/src/pk/dsa/dsa_sign_hash.c | 34 ++-- libtomcrypt/src/pk/dsa/dsa_verify_hash.c | 47 +++-- libtomcrypt/src/pk/dsa/dsa_verify_key.c | 187 +++++++++++++++----- 14 files changed, 880 insertions(+), 304 deletions(-) create mode 100644 libtomcrypt/src/pk/dsa/dsa_generate_key.c create mode 100644 libtomcrypt/src/pk/dsa/dsa_generate_pqg.c create mode 100644 libtomcrypt/src/pk/dsa/dsa_set.c create mode 100644 libtomcrypt/src/pk/dsa/dsa_set_pqg_dsaparam.c (limited to 'libtomcrypt/src/pk/dsa') diff --git a/libtomcrypt/src/pk/dsa/dsa_decrypt_key.c b/libtomcrypt/src/pk/dsa/dsa_decrypt_key.c index c622c78..ef4e1dd 100644 --- a/libtomcrypt/src/pk/dsa/dsa_decrypt_key.c +++ b/libtomcrypt/src/pk/dsa/dsa_decrypt_key.c @@ -5,15 +5,13 @@ * * The library is free for all purposes without any express * guarantee it works. - * - * Tom St Denis, tomstdenis@gmail.com, http://libtom.org */ #include "tomcrypt.h" /** @file dsa_decrypt_key.c DSA Crypto, Tom St Denis -*/ +*/ #ifdef LTC_MDSA @@ -27,12 +25,13 @@ @return CRYPT_OK if successful */ int dsa_decrypt_key(const unsigned char *in, unsigned long inlen, - unsigned char *out, unsigned long *outlen, + unsigned char *out, unsigned long *outlen, dsa_key *key) { unsigned char *skey, *expt; void *g_pub; - unsigned long x, y, hashOID[32]; + unsigned long x, y; + unsigned long hashOID[32] = { 0 }; int hash, err; ltc_asn1_list decode[3]; @@ -45,21 +44,21 @@ int dsa_decrypt_key(const unsigned char *in, unsigned long inlen, if (key->type != PK_PRIVATE) { return CRYPT_PK_NOT_PRIVATE; } - + /* decode to find out hash */ LTC_SET_ASN1(decode, 0, LTC_ASN1_OBJECT_IDENTIFIER, hashOID, sizeof(hashOID)/sizeof(hashOID[0])); - - if ((err = der_decode_sequence(in, inlen, decode, 1)) != CRYPT_OK) { + err = der_decode_sequence(in, inlen, decode, 1); + if (err != CRYPT_OK && err != CRYPT_INPUT_TOO_LONG) { return err; } - hash = find_hash_oid(hashOID, decode[0].size); + hash = find_hash_oid(hashOID, decode[0].size); if (hash_is_valid(hash) != CRYPT_OK) { return CRYPT_INVALID_PACKET; } /* we now have the hash! */ - + if ((err = mp_init(&g_pub)) != CRYPT_OK) { return err; } @@ -77,7 +76,7 @@ int dsa_decrypt_key(const unsigned char *in, unsigned long inlen, mp_clear(g_pub); return CRYPT_MEM; } - + LTC_SET_ASN1(decode, 1, LTC_ASN1_INTEGER, g_pub, 1UL); LTC_SET_ASN1(decode, 2, LTC_ASN1_OCTET_STRING, skey, MAXBLOCKSIZE); @@ -92,7 +91,8 @@ int dsa_decrypt_key(const unsigned char *in, unsigned long inlen, goto LBL_ERR; } - y = MIN(mp_unsigned_bin_size(key->p) + 1, MAXBLOCKSIZE); + y = mp_unsigned_bin_size(key->p) + 1; + y = MIN(y, MAXBLOCKSIZE); if ((err = hash_memory(hash, expt, x, expt, &y)) != CRYPT_OK) { goto LBL_ERR; } @@ -125,7 +125,7 @@ LBL_ERR: XFREE(expt); XFREE(skey); - + mp_clear(g_pub); return err; @@ -133,7 +133,7 @@ LBL_ERR: #endif -/* $Source$ */ -/* $Revision$ */ -/* $Date$ */ +/* ref: $Format:%D$ */ +/* git commit: $Format:%H$ */ +/* commit time: $Format:%ai$ */ diff --git a/libtomcrypt/src/pk/dsa/dsa_encrypt_key.c b/libtomcrypt/src/pk/dsa/dsa_encrypt_key.c index a082969..c854367 100644 --- a/libtomcrypt/src/pk/dsa/dsa_encrypt_key.c +++ b/libtomcrypt/src/pk/dsa/dsa_encrypt_key.c @@ -5,15 +5,13 @@ * * The library is free for all purposes without any express * guarantee it works. - * - * Tom St Denis, tomstdenis@gmail.com, http://libtom.org */ #include "tomcrypt.h" /** @file dsa_encrypt_key.c DSA Crypto, Tom St Denis -*/ +*/ #ifdef LTC_MDSA @@ -24,14 +22,14 @@ @param out [out] The destination for the ciphertext @param outlen [in/out] The max size and resulting size of the ciphertext @param prng An active PRNG state - @param wprng The index of the PRNG you wish to use - @param hash The index of the hash you want to use + @param wprng The index of the PRNG you wish to use + @param hash The index of the hash you want to use @param key The DSA key you want to encrypt to @return CRYPT_OK if successful */ int dsa_encrypt_key(const unsigned char *in, unsigned long inlen, - unsigned char *out, unsigned long *outlen, - prng_state *prng, int wprng, int hash, + unsigned char *out, unsigned long *outlen, + prng_state *prng, int wprng, int hash, dsa_key *key) { unsigned char *expt, *skey; @@ -61,7 +59,7 @@ int dsa_encrypt_key(const unsigned char *in, unsigned long inlen, if ((err = mp_init_multi(&g_pub, &g_priv, NULL)) != CRYPT_OK) { return err; } - + expt = XMALLOC(mp_unsigned_bin_size(key->p) + 1); skey = XMALLOC(MAXBLOCKSIZE); if (expt == NULL || skey == NULL) { @@ -74,24 +72,19 @@ int dsa_encrypt_key(const unsigned char *in, unsigned long inlen, mp_clear_multi(g_pub, g_priv, NULL); return CRYPT_MEM; } - - /* make a random x, g^x pair */ - x = mp_unsigned_bin_size(key->q); - if (prng_descriptor[wprng].read(expt, x, prng) != x) { - err = CRYPT_ERROR_READPRNG; - goto LBL_ERR; - } - - /* load x */ - if ((err = mp_read_unsigned_bin(g_priv, expt, x)) != CRYPT_OK) { - goto LBL_ERR; + + /* make a random g_priv, g_pub = g^x pair + private key x should be in range: 1 <= x <= q-1 (see FIPS 186-4 B.1.2) + */ + if ((err = rand_bn_upto(g_priv, key->q, prng, wprng)) != CRYPT_OK) { + goto LBL_ERR; } - + /* compute y */ if ((err = mp_exptmod(key->g, g_priv, key->p, g_pub)) != CRYPT_OK) { goto LBL_ERR; } - + /* make random key */ x = mp_unsigned_bin_size(key->p) + 1; if ((err = dsa_shared_secret(g_priv, key->y, key, expt, &x)) != CRYPT_OK) { @@ -102,7 +95,7 @@ int dsa_encrypt_key(const unsigned char *in, unsigned long inlen, if ((err = hash_memory(hash, expt, x, skey, &y)) != CRYPT_OK) { goto LBL_ERR; } - + /* Encrypt key */ for (x = 0; x < inlen; x++) { skey[x] ^= in[x]; @@ -123,13 +116,13 @@ LBL_ERR: XFREE(skey); XFREE(expt); - + mp_clear_multi(g_pub, g_priv, NULL); return err; } #endif -/* $Source$ */ -/* $Revision$ */ -/* $Date$ */ +/* ref: $Format:%D$ */ +/* git commit: $Format:%H$ */ +/* commit time: $Format:%ai$ */ diff --git a/libtomcrypt/src/pk/dsa/dsa_export.c b/libtomcrypt/src/pk/dsa/dsa_export.c index e4c4508..1f6bb5a 100644 --- a/libtomcrypt/src/pk/dsa/dsa_export.c +++ b/libtomcrypt/src/pk/dsa/dsa_export.c @@ -5,8 +5,6 @@ * * The library is free for all purposes without any express * guarantee it works. - * - * Tom St Denis, tomstdenis@gmail.com, http://libtom.org */ #include "tomcrypt.h" @@ -27,12 +25,16 @@ */ int dsa_export(unsigned char *out, unsigned long *outlen, int type, dsa_key *key) { - unsigned char flags[1]; + unsigned long zero=0; + int err, std; LTC_ARGCHK(out != NULL); LTC_ARGCHK(outlen != NULL); LTC_ARGCHK(key != NULL); + std = type & PK_STD; + type &= ~PK_STD; + /* can we store the static header? */ if (type == PK_PRIVATE && key->type != PK_PRIVATE) { return CRYPT_PK_TYPE_MISMATCH; @@ -42,31 +44,73 @@ int dsa_export(unsigned char *out, unsigned long *outlen, int type, dsa_key *key return CRYPT_INVALID_ARG; } - flags[0] = (type != PK_PUBLIC) ? 1 : 0; - if (type == PK_PRIVATE) { - return der_encode_sequence_multi(out, outlen, - LTC_ASN1_BIT_STRING, 1UL, flags, - LTC_ASN1_INTEGER, 1UL, key->g, - LTC_ASN1_INTEGER, 1UL, key->p, - LTC_ASN1_INTEGER, 1UL, key->q, - LTC_ASN1_INTEGER, 1UL, key->y, - LTC_ASN1_INTEGER, 1UL, key->x, - LTC_ASN1_EOL, 0UL, NULL); + if (std) { + return der_encode_sequence_multi(out, outlen, + LTC_ASN1_SHORT_INTEGER, 1UL, &zero, + LTC_ASN1_INTEGER, 1UL, key->p, + LTC_ASN1_INTEGER, 1UL, key->q, + LTC_ASN1_INTEGER, 1UL, key->g, + LTC_ASN1_INTEGER, 1UL, key->y, + LTC_ASN1_INTEGER, 1UL, key->x, + LTC_ASN1_EOL, 0UL, NULL); + } + else { + unsigned char flags[1]; + flags[0] = 1; + return der_encode_sequence_multi(out, outlen, + LTC_ASN1_BIT_STRING, 1UL, flags, + LTC_ASN1_INTEGER, 1UL, key->g, + LTC_ASN1_INTEGER, 1UL, key->p, + LTC_ASN1_INTEGER, 1UL, key->q, + LTC_ASN1_INTEGER, 1UL, key->y, + LTC_ASN1_INTEGER, 1UL, key->x, + LTC_ASN1_EOL, 0UL, NULL); + } } else { - return der_encode_sequence_multi(out, outlen, - LTC_ASN1_BIT_STRING, 1UL, flags, - LTC_ASN1_INTEGER, 1UL, key->g, - LTC_ASN1_INTEGER, 1UL, key->p, - LTC_ASN1_INTEGER, 1UL, key->q, - LTC_ASN1_INTEGER, 1UL, key->y, - LTC_ASN1_EOL, 0UL, NULL); + if (std) { + unsigned long tmplen = (mp_count_bits(key->y) / 8) + 8; + unsigned char* tmp = XMALLOC(tmplen); + ltc_asn1_list int_list[3]; + + if (tmp == NULL) { + return CRYPT_MEM; + } + + err = der_encode_integer(key->y, tmp, &tmplen); + if (err != CRYPT_OK) { + goto error; + } + + LTC_SET_ASN1(int_list, 0, LTC_ASN1_INTEGER, key->p, 1UL); + LTC_SET_ASN1(int_list, 1, LTC_ASN1_INTEGER, key->q, 1UL); + LTC_SET_ASN1(int_list, 2, LTC_ASN1_INTEGER, key->g, 1UL); + + err = der_encode_subject_public_key_info(out, outlen, PKA_DSA, tmp, + tmplen, LTC_ASN1_SEQUENCE, int_list, + sizeof(int_list) / sizeof(int_list[0])); + +error: + XFREE(tmp); + return err; + } + else { + unsigned char flags[1]; + flags[0] = 0; + return der_encode_sequence_multi(out, outlen, + LTC_ASN1_BIT_STRING, 1UL, flags, + LTC_ASN1_INTEGER, 1UL, key->g, + LTC_ASN1_INTEGER, 1UL, key->p, + LTC_ASN1_INTEGER, 1UL, key->q, + LTC_ASN1_INTEGER, 1UL, key->y, + LTC_ASN1_EOL, 0UL, NULL); + } } } #endif -/* $Source$ */ -/* $Revision$ */ -/* $Date$ */ +/* ref: $Format:%D$ */ +/* git commit: $Format:%H$ */ +/* commit time: $Format:%ai$ */ diff --git a/libtomcrypt/src/pk/dsa/dsa_free.c b/libtomcrypt/src/pk/dsa/dsa_free.c index 5f5ce72..5cac656 100644 --- a/libtomcrypt/src/pk/dsa/dsa_free.c +++ b/libtomcrypt/src/pk/dsa/dsa_free.c @@ -5,8 +5,6 @@ * * The library is free for all purposes without any express * guarantee it works. - * - * Tom St Denis, tomstdenis@gmail.com, http://libtom.org */ #include "tomcrypt.h" @@ -24,11 +22,12 @@ void dsa_free(dsa_key *key) { LTC_ARGCHKVD(key != NULL); - mp_clear_multi(key->g, key->q, key->p, key->x, key->y, NULL); + mp_cleanup_multi(&key->y, &key->x, &key->q, &key->g, &key->p, NULL); + key->type = key->qord = 0; } #endif -/* $Source$ */ -/* $Revision$ */ -/* $Date$ */ +/* ref: $Format:%D$ */ +/* git commit: $Format:%H$ */ +/* commit time: $Format:%ai$ */ diff --git a/libtomcrypt/src/pk/dsa/dsa_generate_key.c b/libtomcrypt/src/pk/dsa/dsa_generate_key.c new file mode 100644 index 0000000..18b2df6 --- /dev/null +++ b/libtomcrypt/src/pk/dsa/dsa_generate_key.c @@ -0,0 +1,47 @@ +/* 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_make_key.c + DSA implementation, generate a DSA key +*/ + +#ifdef LTC_MDSA + +/** + Create a DSA key + @param prng An active PRNG state + @param wprng The index of the PRNG desired + @param key [in/out] Where to store the created key + @return CRYPT_OK if successful. +*/ +int dsa_generate_key(prng_state *prng, int wprng, dsa_key *key) +{ + int err; + + LTC_ARGCHK(key != 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 + */ + /* private key x should be from range: 1 <= x <= q-1 (see FIPS 186-4 B.1.2) */ + if ((err = rand_bn_upto(key->x, key->q, prng, wprng)) != CRYPT_OK) { return err; } + if ((err = mp_exptmod(key->g, key->x, key->p, key->y)) != CRYPT_OK) { return err; } + key->type = PK_PRIVATE; + + return CRYPT_OK; +} + +#endif + +/* ref: $Format:%D$ */ +/* git commit: $Format:%H$ */ +/* commit time: $Format:%ai$ */ diff --git a/libtomcrypt/src/pk/dsa/dsa_generate_pqg.c b/libtomcrypt/src/pk/dsa/dsa_generate_pqg.c new file mode 100644 index 0000000..91c7ef7 --- /dev/null +++ b/libtomcrypt/src/pk/dsa/dsa_generate_pqg.c @@ -0,0 +1,244 @@ +/* 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(ltc_mp.name != NULL); + + /* init mp_ints */ + if ((err = mp_init_multi(&key->p, &key->g, &key->q, &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/libtomcrypt/src/pk/dsa/dsa_import.c b/libtomcrypt/src/pk/dsa/dsa_import.c index 47a68ca..e6a7560 100644 --- a/libtomcrypt/src/pk/dsa/dsa_import.c +++ b/libtomcrypt/src/pk/dsa/dsa_import.c @@ -5,8 +5,6 @@ * * The library is free for all purposes without any express * guarantee it works. - * - * Tom St Denis, tomstdenis@gmail.com, http://libtom.org */ #include "tomcrypt.h" @@ -18,7 +16,7 @@ #ifdef LTC_MDSA /** - Import a DSA key + Import a DSA key @param in The binary packet to import from @param inlen The length of the binary packet @param key [out] Where to store the imported key @@ -26,8 +24,10 @@ */ int dsa_import(const unsigned char *in, unsigned long inlen, dsa_key *key) { + int err, stat; + unsigned long zero = 0; + unsigned char* tmpbuf = NULL; unsigned char flags[1]; - int err; LTC_ARGCHK(in != NULL); LTC_ARGCHK(key != NULL); @@ -38,53 +38,115 @@ int dsa_import(const unsigned char *in, unsigned long inlen, dsa_key *key) return CRYPT_MEM; } + /* try to match the old libtomcrypt format */ + err = der_decode_sequence_multi(in, inlen, LTC_ASN1_BIT_STRING, 1UL, flags, + LTC_ASN1_EOL, 0UL, NULL); + + if (err == CRYPT_OK || err == CRYPT_INPUT_TOO_LONG) { + /* private key */ + if (flags[0] == 1) { + if ((err = der_decode_sequence_multi(in, inlen, + LTC_ASN1_BIT_STRING, 1UL, flags, + LTC_ASN1_INTEGER, 1UL, key->g, + LTC_ASN1_INTEGER, 1UL, key->p, + LTC_ASN1_INTEGER, 1UL, key->q, + LTC_ASN1_INTEGER, 1UL, key->y, + LTC_ASN1_INTEGER, 1UL, key->x, + LTC_ASN1_EOL, 0UL, NULL)) != CRYPT_OK) { + goto LBL_ERR; + } + key->type = PK_PRIVATE; + goto LBL_OK; + } + /* public key */ + else if (flags[0] == 0) { + if ((err = der_decode_sequence_multi(in, inlen, + LTC_ASN1_BIT_STRING, 1UL, flags, + LTC_ASN1_INTEGER, 1UL, key->g, + LTC_ASN1_INTEGER, 1UL, key->p, + LTC_ASN1_INTEGER, 1UL, key->q, + LTC_ASN1_INTEGER, 1UL, key->y, + LTC_ASN1_EOL, 0UL, NULL)) != CRYPT_OK) { + goto LBL_ERR; + } + key->type = PK_PUBLIC; + goto LBL_OK; + } + else { + err = CRYPT_INVALID_PACKET; + goto LBL_ERR; + } + } /* get key type */ if ((err = der_decode_sequence_multi(in, inlen, - LTC_ASN1_BIT_STRING, 1UL, flags, - LTC_ASN1_EOL, 0UL, NULL)) != CRYPT_OK) { - goto error; - } + LTC_ASN1_SHORT_INTEGER, 1UL, &zero, + LTC_ASN1_INTEGER, 1UL, key->p, + LTC_ASN1_INTEGER, 1UL, key->q, + LTC_ASN1_INTEGER, 1UL, key->g, + LTC_ASN1_INTEGER, 1UL, key->y, + LTC_ASN1_INTEGER, 1UL, key->x, + LTC_ASN1_EOL, 0UL, NULL)) == CRYPT_OK) { + + key->type = PK_PRIVATE; + } else { /* public */ + ltc_asn1_list params[3]; + unsigned long tmpbuf_len = inlen; + + LTC_SET_ASN1(params, 0, LTC_ASN1_INTEGER, key->p, 1UL); + LTC_SET_ASN1(params, 1, LTC_ASN1_INTEGER, key->q, 1UL); + LTC_SET_ASN1(params, 2, LTC_ASN1_INTEGER, key->g, 1UL); + + tmpbuf = XCALLOC(1, tmpbuf_len); + if (tmpbuf == NULL) { + err = CRYPT_MEM; + goto LBL_ERR; + } - if (flags[0] == 1) { - if ((err = der_decode_sequence_multi(in, inlen, - LTC_ASN1_BIT_STRING, 1UL, flags, - LTC_ASN1_INTEGER, 1UL, key->g, - LTC_ASN1_INTEGER, 1UL, key->p, - LTC_ASN1_INTEGER, 1UL, key->q, - LTC_ASN1_INTEGER, 1UL, key->y, - LTC_ASN1_INTEGER, 1UL, key->x, - LTC_ASN1_EOL, 0UL, NULL)) != CRYPT_OK) { - goto error; + err = der_decode_subject_public_key_info(in, inlen, PKA_DSA, + tmpbuf, &tmpbuf_len, + LTC_ASN1_SEQUENCE, params, 3); + if (err != CRYPT_OK) { + XFREE(tmpbuf); + goto LBL_ERR; } - key->type = PK_PRIVATE; - } else { - if ((err = der_decode_sequence_multi(in, inlen, - LTC_ASN1_BIT_STRING, 1UL, flags, - LTC_ASN1_INTEGER, 1UL, key->g, - LTC_ASN1_INTEGER, 1UL, key->p, - LTC_ASN1_INTEGER, 1UL, key->q, - LTC_ASN1_INTEGER, 1UL, key->y, - LTC_ASN1_EOL, 0UL, NULL)) != CRYPT_OK) { - goto error; + + if ((err=der_decode_integer(tmpbuf, tmpbuf_len, key->y)) != CRYPT_OK) { + XFREE(tmpbuf); + goto LBL_ERR; } + + XFREE(tmpbuf); key->type = PK_PUBLIC; - } - key->qord = mp_unsigned_bin_size(key->q); + } + +LBL_OK: + 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) { + /* quick p, q, g validation, without primality testing */ + if ((err = dsa_int_validate_pqg(key, &stat)) != CRYPT_OK) { + goto LBL_ERR; + } + if (stat == 0) { + err = CRYPT_INVALID_PACKET; + goto LBL_ERR; + } + /* validate x, y */ + if ((err = dsa_int_validate_xy(key, &stat)) != CRYPT_OK) { + goto LBL_ERR; + } + if (stat == 0) { err = CRYPT_INVALID_PACKET; - goto error; + goto LBL_ERR; } return CRYPT_OK; -error: - mp_clear_multi(key->p, key->g, key->q, key->x, key->y, NULL); +LBL_ERR: + dsa_free(key); return err; } #endif -/* $Source$ */ -/* $Revision$ */ -/* $Date$ */ +/* ref: $Format:%D$ */ +/* git commit: $Format:%H$ */ +/* commit time: $Format:%ai$ */ diff --git a/libtomcrypt/src/pk/dsa/dsa_make_key.c b/libtomcrypt/src/pk/dsa/dsa_make_key.c index 1c16d03..8ac08f8 100644 --- a/libtomcrypt/src/pk/dsa/dsa_make_key.c +++ b/libtomcrypt/src/pk/dsa/dsa_make_key.c @@ -5,133 +5,37 @@ * * The library is free for all purposes without any express * guarantee it works. - * - * Tom St Denis, tomstdenis@gmail.com, http://libtom.org */ #include "tomcrypt.h" /** @file dsa_make_key.c - DSA implementation, generate a DSA key, Tom St Denis + DSA implementation, generate a DSA key */ #ifdef LTC_MDSA /** - 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) { - void *tmp, *tmp2; - int err, res; - unsigned char *buf; - - LTC_ARGCHK(key != NULL); - LTC_ARGCHK(ltc_mp.name != NULL); - - /* check prng */ - if ((err = prng_is_valid(wprng)) != CRYPT_OK) { - return err; - } - - /* check size */ - if (group_size >= LTC_MDSA_MAX_GROUP || group_size <= 15 || - group_size >= modulus_size || (modulus_size - group_size) >= LTC_MDSA_DELTA) { - return CRYPT_INVALID_ARG; - } - - /* allocate ram */ - buf = XMALLOC(LTC_MDSA_DELTA); - if (buf == NULL) { - return CRYPT_MEM; - } - - /* init mp_ints */ - if ((err = mp_init_multi(&tmp, &tmp2, &key->g, &key->q, &key->p, &key->x, &key->y, NULL)) != CRYPT_OK) { - XFREE(buf); - return err; - } - - /* make our prime q */ - if ((err = rand_prime(key->q, group_size, prng, wprng)) != CRYPT_OK) { goto error; } - - /* double q */ - if ((err = mp_add(key->q, key->q, tmp)) != CRYPT_OK) { goto error; } - - /* now make a random string and multply it against q */ - if (prng_descriptor[wprng].read(buf+1, modulus_size - group_size, prng) != (unsigned long)(modulus_size - group_size)) { - err = CRYPT_ERROR_READPRNG; - goto error; - } - - /* force magnitude */ - buf[0] |= 0xC0; + int err; - /* force even */ - buf[modulus_size - group_size - 1] &= ~1; - - if ((err = mp_read_unsigned_bin(tmp2, buf, modulus_size - group_size)) != CRYPT_OK) { goto error; } - if ((err = mp_mul(key->q, tmp2, key->p)) != CRYPT_OK) { goto error; } - if ((err = mp_add_d(key->p, 1, key->p)) != CRYPT_OK) { goto error; } - - /* now loop until p is prime */ - for (;;) { - if ((err = mp_prime_is_prime(key->p, 8, &res)) != CRYPT_OK) { goto error; } - if (res == LTC_MP_YES) break; - - /* add 2q to p and 2 to tmp2 */ - if ((err = mp_add(tmp, key->p, key->p)) != CRYPT_OK) { goto error; } - if ((err = mp_add_d(tmp2, 2, tmp2)) != CRYPT_OK) { goto error; } - } - - /* now p = (q * tmp2) + 1 is prime, find a value g for which g^tmp2 != 1 */ - mp_set(key->g, 1); - - do { - if ((err = mp_add_d(key->g, 1, key->g)) != CRYPT_OK) { goto error; } - if ((err = mp_exptmod(key->g, tmp2, key->p, tmp)) != CRYPT_OK) { goto error; } - } while (mp_cmp_d(tmp, 1) == LTC_MP_EQ); - - /* at this point tmp generates a group of order q mod p */ - mp_exch(tmp, key->g); - - /* 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 - */ - do { - if (prng_descriptor[wprng].read(buf, group_size, prng) != (unsigned long)group_size) { - err = CRYPT_ERROR_READPRNG; - goto error; - } - if ((err = mp_read_unsigned_bin(key->x, buf, group_size)) != CRYPT_OK) { goto error; } - } while (mp_cmp_d(key->x, 1) != LTC_MP_GT); - if ((err = mp_exptmod(key->g, key->x, key->p, key->y)) != CRYPT_OK) { goto error; } - - key->type = PK_PRIVATE; - key->qord = group_size; - -#ifdef LTC_CLEAN_STACK - zeromem(buf, LTC_MDSA_DELTA); -#endif + if ((err = dsa_generate_pqg(prng, wprng, group_size, modulus_size, key)) != CRYPT_OK) { return err; } + if ((err = dsa_generate_key(prng, wprng, key)) != CRYPT_OK) { return err; } - err = CRYPT_OK; - goto done; -error: - mp_clear_multi(key->g, key->q, key->p, key->x, key->y, NULL); -done: - mp_clear_multi(tmp, tmp2, NULL); - XFREE(buf); - return err; + return CRYPT_OK; } #endif -/* $Source$ */ -/* $Revision$ */ -/* $Date$ */ +/* ref: $Format:%D$ */ +/* git commit: $Format:%H$ */ +/* commit time: $Format:%ai$ */ diff --git a/libtomcrypt/src/pk/dsa/dsa_set.c b/libtomcrypt/src/pk/dsa/dsa_set.c new file mode 100644 index 0000000..a4d4042 --- /dev/null +++ b/libtomcrypt/src/pk/dsa/dsa_set.c @@ -0,0 +1,112 @@ +/* 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's p, q & g from raw numbers + @param p DSA's p in binary representation + @param plen The length of p + @param q DSA's q in binary representation + @param qlen The length of q + @param g DSA's g in binary representation + @param glen The length of g + @param key [out] the destination for the imported key + @return CRYPT_OK if successful. +*/ +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, stat; + + LTC_ARGCHK(p != NULL); + LTC_ARGCHK(q != NULL); + LTC_ARGCHK(g != NULL); + LTC_ARGCHK(key != 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_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); + + /* do only a quick validation, without primality testing */ + if ((err = dsa_int_validate_pqg(key, &stat)) != CRYPT_OK) { goto LBL_ERR; } + if (stat == 0) { + err = CRYPT_INVALID_PACKET; + goto LBL_ERR; + } + + return CRYPT_OK; + +LBL_ERR: + dsa_free(key); + return err; +} + +/** + Import DSA public or private key-part from raw numbers + + NB: The p, q & g parts must be set beforehand + + @param in The key-part to import, either public or private. + @param inlen The key-part's length + @param type Which type of key (PK_PRIVATE or PK_PUBLIC) + @param key [out] the destination for the imported key + @return CRYPT_OK if successful. +*/ +int dsa_set_key(const unsigned char *in, unsigned long inlen, int type, dsa_key *key) +{ + int err, stat = 0; + + 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 (type == PK_PRIVATE) { + key->type = PK_PRIVATE; + if ((err = mp_read_unsigned_bin(key->x, (unsigned char *)in, inlen)) != CRYPT_OK) { goto LBL_ERR; } + if ((err = mp_exptmod(key->g, key->x, key->p, key->y)) != CRYPT_OK) { goto LBL_ERR; } + } + else { + key->type = PK_PUBLIC; + if ((err = mp_read_unsigned_bin(key->y, (unsigned char *)in, inlen)) != CRYPT_OK) { goto LBL_ERR; } + } + + if ((err = dsa_int_validate_xy(key, &stat)) != CRYPT_OK) { goto LBL_ERR; } + if (stat == 0) { + err = CRYPT_INVALID_PACKET; + goto LBL_ERR; + } + + 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/libtomcrypt/src/pk/dsa/dsa_set_pqg_dsaparam.c b/libtomcrypt/src/pk/dsa/dsa_set_pqg_dsaparam.c new file mode 100644 index 0000000..edbed1c --- /dev/null +++ b/libtomcrypt/src/pk/dsa/dsa_set_pqg_dsaparam.c @@ -0,0 +1,67 @@ +/* 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's p, q & g from dsaparam + + dsaparam data: openssl dsaparam -outform DER -out dsaparam.der 2048 + + @param dsaparam The DSA param DER encoded data + @param dsaparamlen The length of dhparam data + @param key [out] the destination for the imported key + @return CRYPT_OK if successful. +*/ +int dsa_set_pqg_dsaparam(const unsigned char *dsaparam, unsigned long dsaparamlen, + dsa_key *key) +{ + int err, stat; + + LTC_ARGCHK(dsaparam != NULL); + LTC_ARGCHK(key != 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 = der_decode_sequence_multi(dsaparam, dsaparamlen, + LTC_ASN1_INTEGER, 1UL, key->p, + LTC_ASN1_INTEGER, 1UL, key->q, + LTC_ASN1_INTEGER, 1UL, key->g, + LTC_ASN1_EOL, 0UL, NULL)) != CRYPT_OK) { + goto LBL_ERR; + } + + key->qord = mp_unsigned_bin_size(key->q); + + /* quick p, q, g validation, without primality testing */ + if ((err = dsa_int_validate_pqg(key, &stat)) != CRYPT_OK) { + goto LBL_ERR; + } + if (stat == 0) { + err = CRYPT_INVALID_PACKET; + goto LBL_ERR; + } + + 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/libtomcrypt/src/pk/dsa/dsa_shared_secret.c b/libtomcrypt/src/pk/dsa/dsa_shared_secret.c index 5adaa5f..4c18261 100644 --- a/libtomcrypt/src/pk/dsa/dsa_shared_secret.c +++ b/libtomcrypt/src/pk/dsa/dsa_shared_secret.c @@ -5,22 +5,20 @@ * * The library is free for all purposes without any express * guarantee it works. - * - * Tom St Denis, tomstdenis@gmail.com, http://libtom.org */ #include "tomcrypt.h" /** @file dsa_shared_secret.c DSA Crypto, Tom St Denis -*/ +*/ #ifdef LTC_MDSA /** Create a DSA shared secret between two keys @param private_key The private DSA key (the exponent) - @param base The base of the exponentiation (allows this to be used for both encrypt and decrypt) + @param base The base of the exponentiation (allows this to be used for both encrypt and decrypt) @param public_key The public key @param out [out] Destination of the shared secret @param outlen [in/out] The max size and resulting size of the shared secret @@ -48,7 +46,7 @@ int dsa_shared_secret(void *private_key, void *base, mp_clear(res); return err; } - + x = (unsigned long)mp_unsigned_bin_size(res); if (*outlen < x) { *outlen = x; @@ -66,7 +64,7 @@ done: } #endif -/* $Source$ */ -/* $Revision$ */ -/* $Date$ */ +/* ref: $Format:%D$ */ +/* git commit: $Format:%H$ */ +/* commit time: $Format:%ai$ */ diff --git a/libtomcrypt/src/pk/dsa/dsa_sign_hash.c b/libtomcrypt/src/pk/dsa/dsa_sign_hash.c index 3fc7e99..fda2ca1 100644 --- a/libtomcrypt/src/pk/dsa/dsa_sign_hash.c +++ b/libtomcrypt/src/pk/dsa/dsa_sign_hash.c @@ -5,8 +5,6 @@ * * The library is free for all purposes without any express * guarantee it works. - * - * Tom St Denis, tomstdenis@gmail.com, http://libtom.org */ #include "tomcrypt.h" @@ -34,7 +32,7 @@ int dsa_sign_hash_raw(const unsigned char *in, unsigned long inlen, { void *k, *kinv, *tmp; unsigned char *buf; - int err; + int err, qbits; LTC_ARGCHK(in != NULL); LTC_ARGCHK(r != NULL); @@ -61,20 +59,15 @@ int dsa_sign_hash_raw(const unsigned char *in, unsigned long inlen, /* Init our temps */ if ((err = mp_init_multi(&k, &kinv, &tmp, NULL)) != CRYPT_OK) { goto ERRBUF; } + qbits = mp_count_bits(key->q); retry: do { /* gen random k */ - if (prng_descriptor[wprng].read(buf, key->qord, prng) != (unsigned long)key->qord) { - err = CRYPT_ERROR_READPRNG; - goto error; - } - - /* read k */ - if ((err = mp_read_unsigned_bin(k, buf, key->qord)) != CRYPT_OK) { goto error; } + if ((err = rand_bn_bits(k, qbits, prng, wprng)) != CRYPT_OK) { goto error; } - /* k > 1 ? */ - if (mp_cmp_d(k, 1) != LTC_MP_GT) { goto retry; } + /* k should be from range: 1 <= k <= q-1 (see FIPS 186-4 B.2.2) */ + if (mp_cmp_d(k, 0) != LTC_MP_GT || mp_cmp(k, key->q) != LTC_MP_LT) { goto retry; } /* test gcd */ if ((err = mp_gcd(k, key->q, tmp)) != CRYPT_OK) { goto error; } @@ -89,6 +82,9 @@ retry: if (mp_iszero(r) == LTC_MP_YES) { goto retry; } + /* FIPS 186-4 4.6: use leftmost min(bitlen(q), bitlen(hash)) bits of 'hash'*/ + inlen = MIN(inlen, (unsigned long)(key->qord)); + /* now find s = (in + xr)/k mod q */ if ((err = mp_read_unsigned_bin(tmp, (unsigned char *)in, inlen)) != CRYPT_OK) { goto error; } if ((err = mp_mul(key->x, r, s)) != CRYPT_OK) { goto error; } @@ -98,7 +94,7 @@ retry: if (mp_iszero(s) == LTC_MP_YES) { goto retry; } err = CRYPT_OK; -error: +error: mp_clear_multi(k, kinv, tmp, NULL); ERRBUF: #ifdef LTC_CLEAN_STACK @@ -139,9 +135,9 @@ int dsa_sign_hash(const unsigned char *in, unsigned long inlen, goto error; } - err = der_encode_sequence_multi(out, outlen, - LTC_ASN1_INTEGER, 1UL, r, - LTC_ASN1_INTEGER, 1UL, s, + err = der_encode_sequence_multi(out, outlen, + LTC_ASN1_INTEGER, 1UL, r, + LTC_ASN1_INTEGER, 1UL, s, LTC_ASN1_EOL, 0UL, NULL); error: @@ -151,6 +147,6 @@ error: #endif -/* $Source$ */ -/* $Revision$ */ -/* $Date$ */ +/* ref: $Format:%D$ */ +/* git commit: $Format:%H$ */ +/* commit time: $Format:%ai$ */ diff --git a/libtomcrypt/src/pk/dsa/dsa_verify_hash.c b/libtomcrypt/src/pk/dsa/dsa_verify_hash.c index 59beec2..3d3fab5 100644 --- a/libtomcrypt/src/pk/dsa/dsa_verify_hash.c +++ b/libtomcrypt/src/pk/dsa/dsa_verify_hash.c @@ -5,8 +5,6 @@ * * The library is free for all purposes without any express * guarantee it works. - * - * Tom St Denis, tomstdenis@gmail.com, http://libtom.org */ #include "tomcrypt.h" @@ -25,11 +23,11 @@ @param hash The hash that was signed @param hashlen The length of the hash that was signed @param stat [out] The result of the signature verification, 1==valid, 0==invalid - @param key The corresponding public DH key + @param key The corresponding public DSA key @return CRYPT_OK if successful (even if the signature is invalid) */ int dsa_verify_hash_raw( void *r, void *s, - const unsigned char *hash, unsigned long hashlen, + const unsigned char *hash, unsigned long hashlen, int *stat, dsa_key *key) { void *w, *v, *u1, *u2; @@ -49,11 +47,14 @@ int dsa_verify_hash_raw( void *r, void *s, } /* neither r or s can be null or >q*/ - if (mp_iszero(r) == LTC_MP_YES || mp_iszero(s) == LTC_MP_YES || mp_cmp(r, key->q) != LTC_MP_LT || mp_cmp(s, key->q) != LTC_MP_LT) { + if (mp_cmp_d(r, 0) != LTC_MP_GT || mp_cmp_d(s, 0) != LTC_MP_GT || mp_cmp(r, key->q) != LTC_MP_LT || mp_cmp(s, key->q) != LTC_MP_LT) { err = CRYPT_INVALID_PACKET; goto error; } - + + /* FIPS 186-4 4.7: use leftmost min(bitlen(q), bitlen(hash)) bits of 'hash' */ + hashlen = MIN(hashlen, (unsigned long)(key->qord)); + /* w = 1/s mod q */ if ((err = mp_invmod(s, key->q, w)) != CRYPT_OK) { goto error; } @@ -62,7 +63,7 @@ int dsa_verify_hash_raw( void *r, void *s, if ((err = mp_mulmod(u1, w, key->q, u1)) != CRYPT_OK) { goto error; } /* u2 = r*w mod q */ - if ((err = mp_mulmod(r, w, key->q, u2)) != CRYPT_OK) { goto error; } + if ((err = mp_mulmod(r, w, key->q, u2)) != CRYPT_OK) { goto error; } /* v = g^u1 * y^u2 mod p mod q */ if ((err = mp_exptmod(key->g, u1, key->p, u1)) != CRYPT_OK) { goto error; } @@ -88,25 +89,35 @@ error: @param hash The hash that was signed @param hashlen The length of the hash that was signed @param stat [out] The result of the signature verification, 1==valid, 0==invalid - @param key The corresponding public DH key + @param key The corresponding public DSA key @return CRYPT_OK if successful (even if the signature is invalid) */ int dsa_verify_hash(const unsigned char *sig, unsigned long siglen, - const unsigned char *hash, unsigned long hashlen, + const unsigned char *hash, unsigned long hashlen, int *stat, dsa_key *key) { int err; void *r, *s; + ltc_asn1_list sig_seq[2]; + unsigned long reallen = 0; + + LTC_ARGCHK(stat != NULL); + *stat = 0; /* must be set before the first return */ if ((err = mp_init_multi(&r, &s, NULL)) != CRYPT_OK) { - return CRYPT_MEM; + return err; + } + + LTC_SET_ASN1(sig_seq, 0, LTC_ASN1_INTEGER, r, 1UL); + LTC_SET_ASN1(sig_seq, 1, LTC_ASN1_INTEGER, s, 1UL); + + err = der_decode_sequence(sig, siglen, sig_seq, 2); + if (err != CRYPT_OK) { + goto LBL_ERR; } - /* decode the sequence */ - if ((err = der_decode_sequence_multi(sig, siglen, - LTC_ASN1_INTEGER, 1UL, r, - LTC_ASN1_INTEGER, 1UL, s, - LTC_ASN1_EOL, 0UL, NULL)) != CRYPT_OK) { + err = der_length_sequence(sig_seq, 2, &reallen); + if (err != CRYPT_OK || reallen != siglen) { goto LBL_ERR; } @@ -121,6 +132,6 @@ LBL_ERR: #endif -/* $Source$ */ -/* $Revision$ */ -/* $Date$ */ +/* ref: $Format:%D$ */ +/* git commit: $Format:%H$ */ +/* commit time: $Format:%ai$ */ diff --git a/libtomcrypt/src/pk/dsa/dsa_verify_key.c b/libtomcrypt/src/pk/dsa/dsa_verify_key.c index fa839ef..258e6cb 100644 --- a/libtomcrypt/src/pk/dsa/dsa_verify_key.c +++ b/libtomcrypt/src/pk/dsa/dsa_verify_key.c @@ -5,8 +5,6 @@ * * The library is free for all purposes without any express * guarantee it works. - * - * Tom St Denis, tomstdenis@gmail.com, http://libtom.org */ #include "tomcrypt.h" @@ -18,83 +16,184 @@ #ifdef LTC_MDSA /** - Verify a DSA key for validity - @param key The key to verify + Validate a DSA key + + Yeah, this function should've been called dsa_validate_key() + in the first place and for compat-reasons we keep it + as it was (for now). + + @param key The key to validate @param stat [out] Result of test, 1==valid, 0==invalid @return CRYPT_OK if successful */ int dsa_verify_key(dsa_key *key, int *stat) { - void *tmp, *tmp2; - int res, err; + int err; + + err = dsa_int_validate_primes(key, stat); + if (err != CRYPT_OK || *stat == 0) return err; + + err = dsa_int_validate_pqg(key, stat); + if (err != CRYPT_OK || *stat == 0) return err; + + return dsa_int_validate_xy(key, stat); +} + +/** + Non-complex part (no primality testing) of the validation + of DSA params (p, q, g) + + @param key The key to validate + @param stat [out] Result of test, 1==valid, 0==invalid + @return CRYPT_OK if successful +*/ +int dsa_int_validate_pqg(dsa_key *key, int *stat) +{ + void *tmp1, *tmp2; + int err; LTC_ARGCHK(key != NULL); LTC_ARGCHK(stat != NULL); - - /* default to an invalid key */ *stat = 0; - /* first make sure key->q and key->p are prime */ - if ((err = mp_prime_is_prime(key->q, 8, &res)) != CRYPT_OK) { - return err; - } - if (res == 0) { + /* check q-order */ + 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 ) { return CRYPT_OK; } - if ((err = mp_prime_is_prime(key->p, 8, &res)) != CRYPT_OK) { - return err; - } - if (res == 0) { + /* FIPS 186-4 chapter 4.1: 1 < g < p */ + if (mp_cmp_d(key->g, 1) != LTC_MP_GT || mp_cmp(key->g, key->p) != LTC_MP_LT) { return CRYPT_OK; } - /* now make sure that g is not -1, 0 or 1 and

g, 0) == LTC_MP_EQ || mp_cmp_d(key->g, 1) == LTC_MP_EQ) { - return CRYPT_OK; - } - if ((err = mp_init_multi(&tmp, &tmp2, NULL)) != CRYPT_OK) { return err; } - if ((err = mp_sub_d(key->p, 1, tmp)) != CRYPT_OK) { goto error; } - if (mp_cmp(tmp, key->g) == LTC_MP_EQ || mp_cmp(key->g, key->p) != LTC_MP_LT) { + if ((err = mp_init_multi(&tmp1, &tmp2, NULL)) != CRYPT_OK) { return err; } + + /* FIPS 186-4 chapter 4.1: q is a divisor of (p - 1) */ + if ((err = mp_sub_d(key->p, 1, tmp1)) != CRYPT_OK) { goto error; } + if ((err = mp_div(tmp1, key->q, tmp1, tmp2)) != CRYPT_OK) { goto error; } + if (mp_iszero(tmp2) != LTC_MP_YES) { err = CRYPT_OK; goto error; } - /* 1 < y < p-1 */ - if (!(mp_cmp_d(key->y, 1) == LTC_MP_GT && mp_cmp(key->y, tmp) == LTC_MP_LT)) { + /* FIPS 186-4 chapter 4.1: g is a generator of a subgroup of order q in + * the multiplicative group of GF(p) - so we make sure that g^q mod p = 1 + */ + if ((err = mp_exptmod(key->g, key->q, key->p, tmp1)) != CRYPT_OK) { goto error; } + if (mp_cmp_d(tmp1, 1) != LTC_MP_EQ) { err = CRYPT_OK; goto error; } - /* now we have to make sure that g^q = 1, and that p-1/q gives 0 remainder */ - if ((err = mp_div(tmp, key->q, tmp, tmp2)) != CRYPT_OK) { goto error; } - if (mp_iszero(tmp2) != LTC_MP_YES) { - err = CRYPT_OK; - goto error; + err = CRYPT_OK; + *stat = 1; +error: + mp_clear_multi(tmp2, tmp1, NULL); + return err; +} + +/** + Primality testing of DSA params p and q + + @param key The key to validate + @param stat [out] Result of test, 1==valid, 0==invalid + @return CRYPT_OK if successful +*/ +int dsa_int_validate_primes(dsa_key *key, int *stat) +{ + int err, res; + + *stat = 0; + LTC_ARGCHK(key != NULL); + LTC_ARGCHK(stat != NULL); + + /* key->q prime? */ + if ((err = mp_prime_is_prime(key->q, LTC_MILLER_RABIN_REPS, &res)) != CRYPT_OK) { + return err; + } + if (res == LTC_MP_NO) { + return CRYPT_OK; } - if ((err = mp_exptmod(key->g, key->q, key->p, tmp)) != CRYPT_OK) { goto error; } - if (mp_cmp_d(tmp, 1) != LTC_MP_EQ) { - err = CRYPT_OK; - goto error; + /* key->p prime? */ + if ((err = mp_prime_is_prime(key->p, LTC_MILLER_RABIN_REPS, &res)) != CRYPT_OK) { + return err; } + if (res == LTC_MP_NO) { + return CRYPT_OK; + } + + *stat = 1; + return CRYPT_OK; +} + +/** + Validation of a DSA key (x and y values) - /* now we have to make sure that y^q = 1, this makes sure y \in g^x mod p */ - if ((err = mp_exptmod(key->y, key->q, key->p, tmp)) != CRYPT_OK) { goto error; } - if (mp_cmp_d(tmp, 1) != LTC_MP_EQ) { + @param key The key to validate + @param stat [out] Result of test, 1==valid, 0==invalid + @return CRYPT_OK if successful +*/ +int dsa_int_validate_xy(dsa_key *key, int *stat) +{ + void *tmp; + int err; + + *stat = 0; + LTC_ARGCHK(key != NULL); + LTC_ARGCHK(stat != NULL); + + /* 1 < y < p-1 */ + if ((err = mp_init(&tmp)) != CRYPT_OK) { + return err; + } + if ((err = mp_sub_d(key->p, 1, tmp)) != CRYPT_OK) { + goto error; + } + if (mp_cmp_d(key->y, 1) != LTC_MP_GT || mp_cmp(key->y, tmp) != LTC_MP_LT) { err = CRYPT_OK; goto error; } - /* at this point we are out of tests ;-( */ + if (key->type == PK_PRIVATE) { + /* FIPS 186-4 chapter 4.1: 0 < x < q */ + if (mp_cmp_d(key->x, 0) != LTC_MP_GT || mp_cmp(key->x, key->q) != LTC_MP_LT) { + err = CRYPT_OK; + goto error; + } + /* FIPS 186-4 chapter 4.1: y = g^x mod p */ + if ((err = mp_exptmod(key->g, key->x, key->p, tmp)) != CRYPT_OK) { + goto error; + } + if (mp_cmp(tmp, key->y) != LTC_MP_EQ) { + err = CRYPT_OK; + goto error; + } + } + else { + /* with just a public key we cannot test y = g^x mod p therefore we + * only test that y^q mod p = 1, which makes sure y is in g^x mod p + */ + if ((err = mp_exptmod(key->y, key->q, key->p, tmp)) != CRYPT_OK) { + goto error; + } + if (mp_cmp_d(tmp, 1) != LTC_MP_EQ) { + err = CRYPT_OK; + goto error; + } + } + err = CRYPT_OK; *stat = 1; -error: - mp_clear_multi(tmp, tmp2, NULL); +error: + mp_clear(tmp); return err; } + #endif -/* $Source$ */ -/* $Revision$ */ -/* $Date$ */ +/* ref: $Format:%D$ */ +/* git commit: $Format:%H$ */ +/* commit time: $Format:%ai$ */ -- cgit v1.2.3