summaryrefslogtreecommitdiffhomepage
path: root/libtomcrypt/src/pk/dsa
diff options
context:
space:
mode:
authorMatt Johnston <matt@ucc.asn.au>2018-02-09 21:44:05 +0800
committerMatt Johnston <matt@ucc.asn.au>2018-02-09 21:44:05 +0800
commit4f2eb1914bdac3ed3ee504ad86061281dbe0d074 (patch)
tree078293375c3f3ee2d485cf9559a08d65d460786a /libtomcrypt/src/pk/dsa
parentd72f50ff3284e15124a0f233c26339229fe305ac (diff)
Update to libtomcrypt 1.18.1, merged with Dropbear changes
Diffstat (limited to 'libtomcrypt/src/pk/dsa')
-rw-r--r--libtomcrypt/src/pk/dsa/dsa_decrypt_key.c32
-rw-r--r--libtomcrypt/src/pk/dsa/dsa_encrypt_key.c45
-rw-r--r--libtomcrypt/src/pk/dsa/dsa_export.c90
-rw-r--r--libtomcrypt/src/pk/dsa/dsa_free.c11
-rw-r--r--libtomcrypt/src/pk/dsa/dsa_generate_key.c47
-rw-r--r--libtomcrypt/src/pk/dsa/dsa_generate_pqg.c244
-rw-r--r--libtomcrypt/src/pk/dsa/dsa_import.c138
-rw-r--r--libtomcrypt/src/pk/dsa/dsa_make_key.c116
-rw-r--r--libtomcrypt/src/pk/dsa/dsa_set.c112
-rw-r--r--libtomcrypt/src/pk/dsa/dsa_set_pqg_dsaparam.c67
-rw-r--r--libtomcrypt/src/pk/dsa/dsa_shared_secret.c14
-rw-r--r--libtomcrypt/src/pk/dsa/dsa_sign_hash.c34
-rw-r--r--libtomcrypt/src/pk/dsa/dsa_verify_hash.c47
-rw-r--r--libtomcrypt/src/pk/dsa/dsa_verify_key.c187
14 files changed, 880 insertions, 304 deletions
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 <N), then return INVALID.
+ * 3. n = ceil(L / outlen) - 1
+ * 4. b = L- 1 - (n * outlen)
+ * 5. domain_parameter_seed = an arbitrary sequence of seedlen bits
+ * 6. U = Hash (domain_parameter_seed) mod 2^(N-1)
+ * 7. q = 2^(N-1) + U + 1 - (U mod 2)
+ * 8. Test whether or not q is prime as specified in Appendix C.3
+ * 9. If qis not a prime, then go to step 5.
+ * 10. offset = 1
+ * 11. For counter = 0 to (4L- 1) do {
+ * For j=0 to n do {
+ * Vj = Hash ((domain_parameter_seed+ offset + j) mod 2^seedlen
+ * }
+ * W = V0 + (V1 *2^outlen) + ... + (Vn-1 * 2^((n-1) * outlen)) + ((Vn mod 2^b) * 2^(n * outlen))
+ * X = W + 2^(L-1) Comment: 0 <= W < 2^(L-1); hence 2^(L-1) <= X < 2^L
+ * c = X mod 2*q
+ * p = X - (c - 1) Comment: p ~ 1 (mod 2*q)
+ * If (p >= 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 <p */
- if (mp_cmp_d(key->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$ */