Browse Source

DH facelift part1

Karel Miko 8 years ago
parent
commit
771d67e102

+ 2 - 22
demos/timing.c

@@ -891,8 +891,7 @@ static void time_dh(void)
 {
    dh_key key;
    ulong64 t1, t2;
-   unsigned char buf[2][4096];
-   unsigned long i, x, y, z;
+   unsigned long i, x, y;
    int           err;
    static unsigned long sizes[] = {768/8, 1024/8, 1536/8, 2048/8, 3072/8, 4096/8, 6144/8, 8192/8, 100000};
 
@@ -908,29 +907,10 @@ static void time_dh(void)
            t1 = t_read() - t1;
            t2 += t1;
 
-           if (y < 15) {
-              dh_free(&key);
-           }
+           dh_free(&key);
        }
        t2 >>= 4;
        fprintf(stderr, "DH-%4lu make_key    took %15llu cycles\n", x*8, t2);
-
-       t2 = 0;
-       for (y = 0; y < 16; y++) {
-           t_start();
-           t1 = t_read();
-           z = sizeof(buf[1]);
-           if ((err = dh_encrypt_key(buf[0], 20, buf[1], &z, &yarrow_prng, find_prng("yarrow"), find_hash("sha1"),
-                                      &key)) != CRYPT_OK) {
-              fprintf(stderr, "\n\ndh_encrypt_key says %s, wait...no it should say %s...damn you!\n", error_to_string(err), error_to_string(CRYPT_OK));
-              exit(EXIT_FAILURE);
-           }
-           t1 = t_read() - t1;
-           t2 += t1;
-       }
-       t2 >>= 4;
-       fprintf(stderr, "DH-%4lu encrypt_key took %15llu cycles\n", x*8, t2);
-       dh_free(&key);
   }
 }
 #else

+ 36 - 24
src/headers/tomcrypt_pk.h

@@ -183,45 +183,57 @@ int katja_import(const unsigned char *in, unsigned long inlen, katja_key *key);
 /* ---- DH Routines ---- */
 #ifdef LTC_MDH
 
-typedef struct Dh_key {
-    int idx, type;
+#ifndef DH_BUF_SIZE
+#define DH_BUF_SIZE 2100
+#endif
+
+typedef struct {
+  int size;
+  char *name, *base, *prime;
+} ltc_dh_set_type;
+
+extern const ltc_dh_set_type ltc_dh_sets[];
+
+typedef struct {
+    int type;
     void *x;
     void *y;
+    void *base;
+    void *prime;
 } dh_key;
 
-int dh_compat_test(void);
-void dh_sizes(int *low, int *high);
-int dh_get_size(dh_key *key);
+int dh_get_groupsize(dh_key *key);
 
-int dh_make_key(prng_state *prng, int wprng, int keysize, dh_key *key);
+int dh_make_key(prng_state *prng, int wprng, int groupsize, dh_key *key);
+int dh_make_key_ex(prng_state *prng, int wprng, int radix,
+                   void *prime, unsigned long primelen,
+                   void *base,  unsigned long baselen,
+                   dh_key *key);
+int dh_make_key_dhparam(prng_state *prng, int wprng, unsigned char *dhparam, unsigned long dhparamlen, dh_key *key);
 void dh_free(dh_key *key);
 
 int dh_export(unsigned char *out, unsigned long *outlen, int type, dh_key *key);
 int dh_import(const unsigned char *in, unsigned long inlen, dh_key *key);
 
+int dh_export_radix(int radix,
+                    void *out, unsigned long *outlen,
+                    int type, dh_key *key);
+int dh_import_radix(int radix,
+                    void *in,    unsigned long inlen,
+                    void *prime, unsigned long primelen,
+                    void *base,  unsigned long baselen,
+                    int type, dh_key *key);
+
 int dh_shared_secret(dh_key        *private_key, dh_key        *public_key,
                      unsigned char *out,         unsigned long *outlen);
 
-int dh_encrypt_key(const unsigned char *in,    unsigned long  keylen,
-                         unsigned char *out,   unsigned long *outlen,
-                         prng_state    *prng,  int wprng, int hash,
-                         dh_key        *key);
-
-int dh_decrypt_key(const unsigned char *in,  unsigned long  inlen,
-                         unsigned char *out, unsigned long *outlen,
-                         dh_key *key);
-
-int dh_sign_hash(const unsigned char *in,   unsigned long inlen,
-                       unsigned char *out,  unsigned long *outlen,
-                       prng_state    *prng, int wprng, dh_key *key);
-
-int dh_verify_hash(const unsigned char *sig,  unsigned long siglen,
-                   const unsigned char *hash, unsigned long hashlen,
-                   int *stat, dh_key *key);
-
-
+#ifdef LTC_SOURCE
+/* INTERNAL ONLY - it should be later moved to src/headers/tomcrypt_internal.h */
+int dh_check_pubkey(dh_key *key);
 #endif
 
+#endif /* LTC_MDH */
+
 
 /* ---- ECC Routines ---- */
 #ifdef LTC_MECC

+ 215 - 384
src/pk/dh/dh.c

@@ -5,402 +5,233 @@
  *
  * The library is free for all purposes without any express
  * guarantee it works.
- *
- * Tom St Denis, [email protected], http://libtomcrypt.org
  */
-#include "tomcrypt.h"
 
-/**
-  @file dh.c
-  DH crypto, Tom St Denis
-*/
+#include "tomcrypt.h"
 
 #ifdef LTC_MDH
 
-
-#include "dh_static.h"
-
-/**
-   Test the DH sub-system (can take a while)
-   @return CRYPT_OK if successful
-*/
-int dh_compat_test(void)
-{
-    void *p, *g, *tmp;
-    int x, err, primality;
-
-    if ((err = mp_init_multi(&p, &g, &tmp, NULL)) != CRYPT_OK)                 { goto error; }
-
-    for (x = 0; sets[x].size != 0; x++) {
-#if 0
-        printf("dh_test():testing size %d-bits\n", sets[x].size * 8);
+/* This holds the key settings.  ***MUST*** be organized by size from smallest to largest. */
+const ltc_dh_set_type ltc_dh_sets[] = {
+#ifdef LTC_DH768
+{  /* 768-bit MODP Group 1 - https://tools.ietf.org/html/rfc7296#appendix-B.1 */
+   96,
+   "DH-768",
+   "2",
+   "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
+   "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
+   "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
+   "E485B576625E7EC6F44C42E9A63A3620FFFFFFFFFFFFFFFF"
+},
+#endif
+#ifdef LTC_DH1024
+{  /* 1024-bit MODP Group 2 - https://tools.ietf.org/html/rfc7296#appendix-B.2 */
+   128,
+   "DH-1024",
+   "2",
+   "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
+   "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
+   "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
+   "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
+   "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381"
+   "FFFFFFFFFFFFFFFF"
+},
+#endif
+#ifdef LTC_DH1536
+{  /* 1536-bit MODP Group 5 - https://tools.ietf.org/html/rfc3526#section-2 */
+   192,
+   "DH-1536",
+   "2",
+   "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
+   "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
+   "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
+   "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
+   "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
+   "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F"
+   "83655D23DCA3AD961C62F356208552BB9ED529077096966D"
+   "670C354E4ABC9804F1746C08CA237327FFFFFFFFFFFFFFFF"
+},
+#endif
+#ifdef LTC_DH2048
+{  /* 2048-bit MODP Group 14 - https://tools.ietf.org/html/rfc3526#section-3 */
+   256,
+   "DH-2048",
+   "2",
+   "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
+   "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
+   "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
+   "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
+   "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
+   "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F"
+   "83655D23DCA3AD961C62F356208552BB9ED529077096966D"
+   "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B"
+   "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9"
+   "DE2BCBF6955817183995497CEA956AE515D2261898FA0510"
+   "15728E5A8AACAA68FFFFFFFFFFFFFFFF"
+},
+#endif
+#ifdef LTC_DH3072
+{  /* 3072-bit MODP Group 15 - https://tools.ietf.org/html/rfc3526#section-4 */
+   384,
+   "DH-3072",
+   "2",
+   "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
+   "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
+   "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
+   "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
+   "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
+   "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F"
+   "83655D23DCA3AD961C62F356208552BB9ED529077096966D"
+   "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B"
+   "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9"
+   "DE2BCBF6955817183995497CEA956AE515D2261898FA0510"
+   "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64"
+   "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7"
+   "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B"
+   "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C"
+   "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31"
+   "43DB5BFCE0FD108E4B82D120A93AD2CAFFFFFFFFFFFFFFFF"
+},
+#endif
+#ifdef LTC_DH4096
+{  /* 4096-bit MODP Group 16 - https://tools.ietf.org/html/rfc3526#section-5 */
+   512,
+   "DH-4096",
+   "2",
+   "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
+   "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
+   "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
+   "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
+   "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
+   "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F"
+   "83655D23DCA3AD961C62F356208552BB9ED529077096966D"
+   "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B"
+   "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9"
+   "DE2BCBF6955817183995497CEA956AE515D2261898FA0510"
+   "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64"
+   "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7"
+   "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B"
+   "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C"
+   "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31"
+   "43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7"
+   "88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA"
+   "2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6"
+   "287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED"
+   "1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9"
+   "93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934063199"
+   "FFFFFFFFFFFFFFFF"
+},
+#endif
+#ifdef LTC_DH6144
+{  /* 6144-bit MODP Group 17 - https://tools.ietf.org/html/rfc3526#section-6 */
+   768,
+   "DH-6144",
+   "2",
+   "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
+   "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
+   "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
+   "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
+   "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
+   "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F"
+   "83655D23DCA3AD961C62F356208552BB9ED529077096966D"
+   "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B"
+   "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9"
+   "DE2BCBF6955817183995497CEA956AE515D2261898FA0510"
+   "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64"
+   "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7"
+   "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B"
+   "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C"
+   "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31"
+   "43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7"
+   "88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA"
+   "2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6"
+   "287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED"
+   "1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9"
+   "93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934028492"
+   "36C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BD"
+   "F8FF9406AD9E530EE5DB382F413001AEB06A53ED9027D831"
+   "179727B0865A8918DA3EDBEBCF9B14ED44CE6CBACED4BB1B"
+   "DB7F1447E6CC254B332051512BD7AF426FB8F401378CD2BF"
+   "5983CA01C64B92ECF032EA15D1721D03F482D7CE6E74FEF6"
+   "D55E702F46980C82B5A84031900B1C9E59E7C97FBEC7E8F3"
+   "23A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA"
+   "CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE328"
+   "06A1D58BB7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55C"
+   "DA56C9EC2EF29632387FE8D76E3C0468043E8F663F4860EE"
+   "12BF2D5B0B7474D6E694F91E6DCC4024FFFFFFFFFFFFFFFF"
+},
+#endif
+#ifdef LTC_DH8192
+{  /* 8192-bit MODP Group 18 - https://tools.ietf.org/html/rfc3526#section-7 */
+   1024,
+   "DH-8192",
+   "2",
+   "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
+   "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
+   "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
+   "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
+   "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
+   "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F"
+   "83655D23DCA3AD961C62F356208552BB9ED529077096966D"
+   "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B"
+   "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9"
+   "DE2BCBF6955817183995497CEA956AE515D2261898FA0510"
+   "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64"
+   "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7"
+   "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B"
+   "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C"
+   "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31"
+   "43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7"
+   "88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA"
+   "2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6"
+   "287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED"
+   "1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9"
+   "93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934028492"
+   "36C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BD"
+   "F8FF9406AD9E530EE5DB382F413001AEB06A53ED9027D831"
+   "179727B0865A8918DA3EDBEBCF9B14ED44CE6CBACED4BB1B"
+   "DB7F1447E6CC254B332051512BD7AF426FB8F401378CD2BF"
+   "5983CA01C64B92ECF032EA15D1721D03F482D7CE6E74FEF6"
+   "D55E702F46980C82B5A84031900B1C9E59E7C97FBEC7E8F3"
+   "23A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA"
+   "CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE328"
+   "06A1D58BB7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55C"
+   "DA56C9EC2EF29632387FE8D76E3C0468043E8F663F4860EE"
+   "12BF2D5B0B7474D6E694F91E6DBE115974A3926F12FEE5E4"
+   "38777CB6A932DF8CD8BEC4D073B931BA3BC832B68D9DD300"
+   "741FA7BF8AFC47ED2576F6936BA424663AAB639C5AE4F568"
+   "3423B4742BF1C978238F16CBE39D652DE3FDB8BEFC848AD9"
+   "22222E04A4037C0713EB57A81A23F0C73473FC646CEA306B"
+   "4BCBC8862F8385DDFA9D4B7FA2C087E879683303ED5BDD3A"
+   "062B3CF5B3A278A66D2A13F83F44F82DDF310EE074AB6A36"
+   "4597E899A0255DC164F31CC50846851DF9AB48195DED7EA1"
+   "B1D510BD7EE74D73FAF36BC31ECFA268359046F4EB879F92"
+   "4009438B481C6CD7889A002ED5EE382BC9190DA6FC026E47"
+   "9558E4475677E9AA9E3050E2765694DFC81F56E880B96E71"
+   "60C980DD98EDD3DFFFFFFFFFFFFFFFFF"
+},
 #endif
-        if ((err = mp_read_radix(g,(char *)sets[x].base, 16)) != CRYPT_OK)    { goto error; }
-        if ((err = mp_read_radix(p,(char *)sets[x].prime, 16)) != CRYPT_OK)   { goto error; }
-
-        /* ensure p is prime */
-        if ((err = mp_prime_is_prime(p, 8, &primality)) != CRYPT_OK)                     { goto done; }
-        if (primality != LTC_MP_YES ) {
-           err = CRYPT_FAIL_TESTVECTOR;
-           goto done;
-        }
-
-        if ((err = mp_sub_d(p, 1, tmp)) != CRYPT_OK)                         { goto error; }
-        if ((err = mp_div_2(tmp, tmp)) != CRYPT_OK)                          { goto error; }
-
-        /* ensure (p-1)/2 is prime */
-        if ((err = mp_prime_is_prime(tmp, 8, &primality)) != CRYPT_OK)                   { goto done; }
-        if (primality == 0) {
-           err = CRYPT_FAIL_TESTVECTOR;
-           goto done;
-        }
-
-        /* now see if g^((p-1)/2) mod p is in fact 1 */
-        if ((err = mp_exptmod(g, tmp, p, tmp)) != CRYPT_OK)                { goto error; }
-        if (mp_cmp_d(tmp, 1)) {
-           err = CRYPT_FAIL_TESTVECTOR;
-           goto done;
-        }
-    }
-    err = CRYPT_OK;
-error:
-done:
-    mp_clear_multi(tmp, g, p, NULL);
-    return err;
-}
-
-/**
-   Get the min and max DH key sizes (octets)
-   @param low    [out] The smallest key size supported
-   @param high   [out] The largest key size supported
-*/
-void dh_sizes(int *low, int *high)
 {
-   int x;
-   LTC_ARGCHKVD(low != NULL);
-   LTC_ARGCHKVD(high != NULL);
-   *low  = INT_MAX;
-   *high = 0;
-   for (x = 0; sets[x].size != 0; x++) {
-       if (*low > sets[x].size)  *low  = sets[x].size;
-       if (*high < sets[x].size) *high = sets[x].size;
-   }
+   0,
+   NULL,
+   NULL,
+   NULL
 }
+};
 
 /**
-  Returns the key size of a given DH key (octets)
+  Returns the DH group size (octets) for given key
   @param key   The DH key to get the size of
-  @return The size if valid or INT_MAX if not
-*/
-int dh_get_size(dh_key *key)
-{
-    LTC_ARGCHK(key != NULL);
-    if (dh_is_valid_idx(key->idx) == 1) {
-        return sets[key->idx].size;
-    } else {
-        return INT_MAX; /* large value that would cause dh_make_key() to fail */
-    }
-}
-
-/**
-  Make a DH key [private key pair]
-  @param prng       An active PRNG state
-  @param wprng      The index for the PRNG you desire to use
-  @param groupsize  The size (octets) of used DH group
-  @param key        [out] Where the newly created DH key will be stored
-  @return CRYPT_OK if successful, note: on error all allocated memory will be freed automatically.
-*/
-int dh_make_key(prng_state *prng, int wprng, int groupsize, dh_key *key)
-{
-   unsigned char *buf;
-   unsigned long idx, keysize;
-   void *p, *g, *p_minus1;
-   int err;
-
-   LTC_ARGCHK(key  != NULL);
-   LTC_ARGCHK(prng != NULL);
-
-   /* good prng? */
-   if ((err = prng_is_valid(wprng)) != CRYPT_OK) {
-      return err;
-   }
-
-   /* find group size */
-   for (idx = 0; (groupsize > sets[idx].size) && (sets[idx].size != 0); idx++);
-   if (sets[idx].size == 0) {
-      return CRYPT_INVALID_KEYSIZE;
-   }
-   groupsize = sets[idx].size;
-
-   /* The strength estimates from https://tools.ietf.org/html/rfc3526#section-8
-    * We use "Estimate 2" to get an appropriate private key (exponent) size.
-    */
-   if (groupsize <= 192) {
-      keysize = 30;     /* 1536-bit => key size 240-bit */
-   }
-   else if (groupsize <= 256) {
-      keysize = 40;     /* 2048-bit => key size 320-bit */
-   }
-   else if (groupsize <= 384) {
-      keysize = 52;     /* 3072-bit => key size 416-bit */
-   }
-   else if (groupsize <= 512) {
-      keysize = 60;     /* 4096-bit => key size 480-bit */
-   }
-   else if (groupsize <= 768) {
-      keysize = 67;     /* 6144-bit => key size 536-bit */
-   }
-   else if (groupsize <= 1024) {
-      keysize = 77;     /* 8192-bit => key size 616-bit */
-   }
-   else {
-      return CRYPT_INVALID_KEYSIZE;
-   }
-
-   /* allocate buffer */
-   buf = XMALLOC(keysize);
-   if (buf == NULL) {
-      return CRYPT_MEM;
-   }
-
-   /* init big numbers */
-   if ((err = mp_init_multi(&g, &p, &p_minus1, &key->x, &key->y, NULL)) != CRYPT_OK) {
-      goto freebuf;
-   }
-
-   if ((err = mp_read_radix(g, sets[idx].base, 16)) != CRYPT_OK)           { goto error; }
-   if ((err = mp_read_radix(p, sets[idx].prime, 16)) != CRYPT_OK)          { goto error; }
-   if ((err = mp_sub_d(p, 1, p_minus1)) != CRYPT_OK)                       { goto error; }
-
-   do {
-      /* make up random buf */
-      if (prng_descriptor[wprng].read(buf, keysize, prng) != keysize) {
-         err = CRYPT_ERROR_READPRNG;
-         goto error;
-      }
-      /* load the x value - private key */
-      if ((err = mp_read_unsigned_bin(key->x, buf, keysize)) != CRYPT_OK)  { goto error; }
-      /* compute the y value - public key */
-      if ((err = mp_exptmod(g, key->x, p, key->y)) != CRYPT_OK)            { goto error; }
-      /* avoid: y <= 1 OR y >= p-1 */
-   } while (mp_cmp(key->y, p_minus1) != LTC_MP_LT || mp_cmp_d(key->y, 1) != LTC_MP_GT);
-
-   /* success */
-   key->idx = idx;
-   key->type = PK_PRIVATE;
-   err = CRYPT_OK;
-   goto done;
-
-error:
-   mp_clear_multi(key->x, key->y, NULL);
-done:
-   mp_clear_multi(g, p, p_minus1, NULL);
-freebuf:
-   zeromem(buf, keysize);
-   XFREE(buf);
-   return err;
-}
-
-/**
-  Free the allocated ram for a DH key
-  @param key   The key which you wish to free
-*/
-void dh_free(dh_key *key)
-{
-   LTC_ARGCHKVD(key != NULL);
-   if ( key->x ) {
-      mp_clear( key->x );
-      key->x = NULL;
-   }
-   if ( key->y ) {
-      mp_clear( key->y );
-      key->y = NULL;
-   }
-}
-
-/**
-  Export a DH key to a binary packet
-  @param out    [out] The destination for the key
-  @param outlen [in/out] The max size and resulting size of the DH key
-  @param type   Which type of key (PK_PRIVATE or PK_PUBLIC)
-  @param key    The key you wish to export
-  @return CRYPT_OK if successful
-*/
-int dh_export(unsigned char *out, unsigned long *outlen, int type, dh_key *key)
-{
-   unsigned long y, z;
-   int err;
-
-   LTC_ARGCHK(out    != NULL);
-   LTC_ARGCHK(outlen != NULL);
-   LTC_ARGCHK(key    != NULL);
-
-   /* can we store the static header?  */
-   if (*outlen < (PACKET_SIZE + 2)) {
-      return CRYPT_BUFFER_OVERFLOW;
-   }
-
-   if (type == PK_PRIVATE && key->type != PK_PRIVATE) {
-      return CRYPT_PK_NOT_PRIVATE;
-   }
-
-   /* header */
-   y = PACKET_SIZE;
-
-   /* header */
-   out[y++] = type;
-   out[y++] = (unsigned char)(sets[key->idx].size / 8);
-
-   /* export y */
-   OUTPUT_BIGNUM(key->y, out, y, z);
-
-   if (type == PK_PRIVATE) {
-      /* export x */
-      OUTPUT_BIGNUM(key->x, out, y, z);
-   }
-
-   /* store header */
-   packet_store_header(out, PACKET_SECT_DH, PACKET_SUB_KEY);
-
-   /* store len */
-   *outlen = y;
-   return CRYPT_OK;
-}
-
-/**
-  Import a DH key from a binary packet
-  @param in     The packet to read
-  @param inlen  The length of the input packet
-  @param key    [out] Where to import the key to
-  @return CRYPT_OK if successful, on error all allocated memory is freed automatically
-*/
-int dh_import(const unsigned char *in, unsigned long inlen, dh_key *key)
-{
-   unsigned long x, y, s;
-   int err;
-
-   LTC_ARGCHK(in  != NULL);
-   LTC_ARGCHK(key != NULL);
-
-   /* make sure valid length */
-   if ((2+PACKET_SIZE) > inlen) {
-      return CRYPT_INVALID_PACKET;
-   }
-
-   /* check type byte */
-   if ((err = packet_valid_header((unsigned char *)in, PACKET_SECT_DH, PACKET_SUB_KEY)) != CRYPT_OK) {
-      return err;
-   }
-
-   /* init */
-   if ((err = mp_init_multi(&key->x, &key->y, NULL)) != CRYPT_OK) {
-      return err;
-   }
-
-   /* advance past packet header */
-   y = PACKET_SIZE;
-
-   /* key type, e.g. private, public */
-   key->type = (int)in[y++];
-
-   /* key size in bytes */
-   s  = (unsigned long)in[y++] * 8;
-
-   for (x = 0; (s > (unsigned long)sets[x].size) && (sets[x].size != 0); x++);
-   if (sets[x].size == 0) {
-      err = CRYPT_INVALID_KEYSIZE;
-      goto error;
-   }
-   key->idx = (int)x;
-
-   /* type check both values */
-   if ((key->type != PK_PUBLIC) && (key->type != PK_PRIVATE))  {
-      err = CRYPT_PK_TYPE_MISMATCH;
-      goto error;
-   }
-
-   /* is the key idx valid? */
-   if (dh_is_valid_idx(key->idx) != 1) {
-      err = CRYPT_PK_TYPE_MISMATCH;
-      goto error;
-   }
-
-   /* load public value g^x mod p*/
-   INPUT_BIGNUM(key->y, in, x, y, inlen);
-
-   if (key->type == PK_PRIVATE) {
-      INPUT_BIGNUM(key->x, in, x, y, inlen);
-   }
-
-   /* eliminate private key if public */
-   if (key->type == PK_PUBLIC) {
-      mp_clear(key->x);
-      key->x = NULL;
-   }
-
-   return CRYPT_OK;
-error:
-   mp_clear_multi(key->y, key->x, NULL);
-   return err;
-}
-
-/**
-   Create a DH shared secret.
-   @param private_key     The private DH key in the pair
-   @param public_key      The public DH key in the pair
-   @param out             [out] The destination of the shared data
-   @param outlen          [in/out] The max size and resulting size of the shared data.
-   @return CRYPT_OK if successful
-*/
-int dh_shared_secret(dh_key *private_key, dh_key *public_key,
-                     unsigned char *out, unsigned long *outlen)
+  @return The group size in octets (0 on error)
+ */
+int dh_get_groupsize(dh_key *key)
 {
-   void *tmp, *p, *p_minus1;
-   unsigned long x;
-   int err;
-
-   LTC_ARGCHK(private_key != NULL);
-   LTC_ARGCHK(public_key  != NULL);
-   LTC_ARGCHK(out         != NULL);
-   LTC_ARGCHK(outlen      != NULL);
-
-   /* types valid? */
-   if (private_key->type != PK_PRIVATE) {
-      return CRYPT_PK_NOT_PRIVATE;
-   }
-
-   /* same idx? */
-   if (private_key->idx != public_key->idx) {
-      return CRYPT_PK_TYPE_MISMATCH;
-   }
-
-   /* compute y^x mod p */
-   if ((err = mp_init_multi(&tmp, &p, &p_minus1, NULL)) != CRYPT_OK) {
-      return err;
-   }
-
-   if ((err = mp_read_radix(p, sets[private_key->idx].prime, 16)) != CRYPT_OK)  { goto error; }
-   if ((err = mp_sub_d(p, 1, p_minus1)) != CRYPT_OK)                            { goto error; }
-   if (mp_cmp(public_key->y, p_minus1) != LTC_MP_LT || mp_cmp_d(public_key->y, 1) != LTC_MP_GT) {
-      /* reject public key with: y <= 1 OR y >= p-1 */
-      err = CRYPT_INVALID_ARG;
-      goto error;
-   }
-   if ((err = mp_exptmod(public_key->y, private_key->x, p, tmp)) != CRYPT_OK)   { goto error; }
-
-   /* enough space for output? */
-   x = (unsigned long)mp_unsigned_bin_size(tmp);
-   if (*outlen < x) {
-      err = CRYPT_BUFFER_OVERFLOW;
-      goto error;
-   }
-   if ((err = mp_to_unsigned_bin(tmp, out)) != CRYPT_OK)                        { goto error; }
-   *outlen = x;
-   err = CRYPT_OK;
-
-error:
-   mp_clear_multi(p_minus1, p, tmp, NULL);
-   return err;
+   if (key == NULL) return 0;
+   return mp_unsigned_bin_size(key->prime);
 }
 
 #endif /* LTC_MDH */
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */

+ 68 - 0
src/pk/dh/dh_check_pubkey.c

@@ -0,0 +1,68 @@
+/* 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_MDH
+
+/**
+  Check DH public key (INTERNAL ONLY, not part of public API)
+  @param key    The key you wish to test
+  @return CRYPT_OK if successful
+*/
+int dh_check_pubkey(dh_key *key)
+{
+   void *p_minus1;
+   ltc_mp_digit digit;
+   int i, digit_count, bits_set = 0, err;
+
+   LTC_ARGCHK(key != NULL);
+   LTC_ARGCHK(key->y != NULL);
+   LTC_ARGCHK(key->base != NULL);
+   LTC_ARGCHK(key->prime != NULL);
+
+   if ((err = mp_init(&p_minus1)) != CRYPT_OK) {
+      return err;
+   }
+
+   /* avoid: y <= 1 OR y >= p-1 */
+   if ((err = mp_sub_d(key->prime, 1, p_minus1)) != CRYPT_OK) {
+      goto error;
+   }
+   if (mp_cmp(key->y, p_minus1) != LTC_MP_LT || mp_cmp_d(key->y, 1) != LTC_MP_GT) {
+      err = CRYPT_INVALID_ARG;
+      goto error;
+   }
+
+   /* public key must have more than one bit set */
+   digit_count = mp_get_digit_count(key->y);
+   for (i = 0; i < digit_count && bits_set < 2; i++) {
+      digit = mp_get_digit(key->y, i);
+      while (digit > 0) {
+         if (digit & 1) bits_set++;
+         digit >>= 1;
+      }
+   }
+   if (bits_set > 1) {
+      err = CRYPT_OK;
+   }
+   else {
+      err = CRYPT_INVALID_ARG;
+   }
+
+error:
+   mp_clear(p_minus1);
+   return err;
+}
+
+#endif /* LTC_MDH */
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */

+ 62 - 0
src/pk/dh/dh_export.c

@@ -0,0 +1,62 @@
+/* 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_MDH
+
+/**
+  Export a DH key to a binary packet
+  @param out    [out] The destination for the key
+  @param outlen [in/out] The max size and resulting size of the DH key
+  @param type   Which type of key (PK_PRIVATE or PK_PUBLIC)
+  @param key    The key you wish to export
+  @return CRYPT_OK if successful
+*/
+int dh_export(unsigned char *out, unsigned long *outlen, int type, dh_key *key)
+{
+   unsigned char flags[1];
+   int err;
+   unsigned long version = 0;
+
+   LTC_ARGCHK(out    != NULL);
+   LTC_ARGCHK(outlen != NULL);
+   LTC_ARGCHK(key    != NULL);
+
+   if (type == PK_PRIVATE) {
+      /* export x - private key */
+      flags[0] = 1;
+      err = der_encode_sequence_multi(out, outlen,
+                                LTC_ASN1_SHORT_INTEGER, 1UL, &version,
+                                LTC_ASN1_BIT_STRING,    1UL, flags,
+                                LTC_ASN1_INTEGER,       1UL, key->prime,
+                                LTC_ASN1_INTEGER,       1UL, key->base,
+                                LTC_ASN1_INTEGER,       1UL, key->x,
+                                LTC_ASN1_EOL,           0UL, NULL);
+   }
+   else {
+      /* export y - public key */
+      flags[0] = 0;
+      err = der_encode_sequence_multi(out, outlen,
+                                LTC_ASN1_SHORT_INTEGER, 1UL, &version,
+                                LTC_ASN1_BIT_STRING,    1UL, flags,
+                                LTC_ASN1_INTEGER,       1UL, key->prime,
+                                LTC_ASN1_INTEGER,       1UL, key->base,
+                                LTC_ASN1_INTEGER,       1UL, key->y,
+                                LTC_ASN1_EOL,           0UL, NULL);
+   }
+
+   return err;
+}
+
+#endif /* LTC_MDH */
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */

+ 68 - 0
src/pk/dh/dh_export_radix.c

@@ -0,0 +1,68 @@
+/* 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_MDH
+
+static unsigned long _count_digits(int radix, void *num)
+{
+   void *r, *t;
+   unsigned long digits = 0;
+
+   if (mp_iszero(num) == LTC_MP_YES) return 1;
+   if (mp_init_multi(&t, &r, NULL) != CRYPT_OK) return 0;
+   mp_copy(num, t);
+   mp_set_int(r, radix);
+   while (mp_iszero(t) == LTC_MP_NO) {
+      if (mp_div(t, r, t, NULL) != CRYPT_OK) {
+         mp_clear_multi(t, r, NULL);
+         return 0;
+      }
+      digits++;
+   }
+   mp_clear_multi(t, r, NULL);
+   return digits;
+}
+
+/**
+  Export a DH key to a binary packet
+  @param out    [out] The destination for the key
+  @param outlen [in/out] The max size and resulting size of the DH key
+  @param type   Which type of key (PK_PRIVATE or PK_PUBLIC)
+  @param key    The key you wish to export
+  @return CRYPT_OK if successful
+*/
+int dh_export_radix(int radix, void *out, unsigned long *outlen, int type, dh_key *key)
+{
+   unsigned long len;
+   void *k;
+
+   LTC_ARGCHK(out    != NULL);
+   LTC_ARGCHK(outlen != NULL);
+   LTC_ARGCHK(key    != NULL);
+   LTC_ARGCHK((radix >= 2 && radix <= 64) || radix == 256);
+
+   k = (type == PK_PRIVATE) ? key->x : key->y;
+   len = (radix == 256) ? mp_unsigned_bin_size(k) : _count_digits(radix, k) + 1;
+
+   if (*outlen < len) {
+      *outlen = len;
+      return CRYPT_BUFFER_OVERFLOW;
+   }
+   *outlen = len;
+
+   return (radix == 256) ? mp_to_unsigned_bin(k, out) : mp_toradix(k, out, radix);
+}
+
+#endif /* LTC_MDH */
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */

+ 43 - 0
src/pk/dh/dh_free.c

@@ -0,0 +1,43 @@
+/* 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_MDH
+
+/**
+  Free the allocated ram for a DH key
+  @param key   The key which you wish to free
+*/
+void dh_free(dh_key *key)
+{
+   LTC_ARGCHKVD(key != NULL);
+   if ( key->base ) {
+      mp_clear( key->base );
+      key->base = NULL;
+   }
+   if ( key->prime ) {
+      mp_clear( key->prime );
+      key->prime = NULL;
+   }
+   if ( key->x ) {
+      mp_clear( key->x );
+      key->x = NULL;
+   }
+   if ( key->y ) {
+      mp_clear( key->y );
+      key->y = NULL;
+   }
+}
+
+#endif /* LTC_MDH */
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */

+ 97 - 0
src/pk/dh/dh_import.c

@@ -0,0 +1,97 @@
+/* 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_MDH
+
+/**
+  Import a DH key from a binary packet
+  @param in     The packet to read
+  @param inlen  The length of the input packet
+  @param key    [out] Where to import the key to
+  @return CRYPT_OK if successful, on error all allocated memory is freed automatically
+*/
+int dh_import(const unsigned char *in, unsigned long inlen, dh_key *key)
+{
+   unsigned char flags[1];
+   int err;
+   unsigned long version;
+
+   LTC_ARGCHK(in  != NULL);
+   LTC_ARGCHK(key != NULL);
+
+   /* init */
+   if ((err = mp_init_multi(&key->prime, &key->base, &key->x, &key->y, NULL)) != CRYPT_OK) {
+      return err;
+   }
+
+   /* find out what type of key it is */
+   err = der_decode_sequence_multi(in, inlen,
+                                   LTC_ASN1_SHORT_INTEGER, 1UL, &version,
+                                   LTC_ASN1_BIT_STRING, 1UL, &flags,
+                                   LTC_ASN1_EOL, 0UL, NULL);
+   if (err != CRYPT_OK) {
+      goto error;
+   }
+
+   if (version == 0) {
+      if (flags[0] == 1) {
+         key->type = PK_PRIVATE;
+         if ((err = der_decode_sequence_multi(in, inlen,
+                                              LTC_ASN1_SHORT_INTEGER, 1UL, &version,
+                                              LTC_ASN1_BIT_STRING,    1UL, flags,
+                                              LTC_ASN1_INTEGER,       1UL, key->prime,
+                                              LTC_ASN1_INTEGER,       1UL, key->base,
+                                              LTC_ASN1_INTEGER,       1UL, key->x,
+                                              LTC_ASN1_EOL,           0UL, NULL)) != CRYPT_OK) {
+            goto error;
+         }
+         /* compute public key: y = (base ^ x) mod prime */
+         if ((err = mp_exptmod(key->base, key->x, key->prime, key->y)) != CRYPT_OK) {
+            goto error;
+         }
+      }
+      else {
+         key->type = PK_PUBLIC;
+         if ((err = der_decode_sequence_multi(in, inlen,
+                                              LTC_ASN1_SHORT_INTEGER, 1UL, &version,
+                                              LTC_ASN1_BIT_STRING,    1UL, flags,
+                                              LTC_ASN1_INTEGER,       1UL, key->prime,
+                                              LTC_ASN1_INTEGER,       1UL, key->base,
+                                              LTC_ASN1_INTEGER,       1UL, key->y,
+                                              LTC_ASN1_EOL,           0UL, NULL)) != CRYPT_OK) {
+            goto error;
+         }
+         mp_clear(key->x);
+         key->x = NULL;
+      }
+   }
+   else {
+      err = CRYPT_INVALID_PACKET;
+      goto error;
+   }
+
+   /* check public key */
+   if ((err = dh_check_pubkey(key)) != CRYPT_OK) {
+      goto error;
+   }
+
+   return CRYPT_OK;
+
+error:
+   mp_clear_multi(key->prime, key->base, key->y, key->x, NULL);
+   return err;
+}
+
+#endif /* LTC_MDH */
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */

+ 90 - 0
src/pk/dh/dh_import_radix.c

@@ -0,0 +1,90 @@
+/* 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_MDH
+
+/**
+  Import a DH key from a binary string
+  @param in     The string to read
+  @param inlen  The length of the input packet
+  @param type   The type of key (PK_PRIVATE or PK_PUBLIC)
+  @param base   The base (generator) in hex string
+  @param prime  The prime in hex string
+  @param key    [out] Where to import the key to
+  @return CRYPT_OK if successful, on error all allocated memory is freed automatically
+*/
+int dh_import_radix(int radix,
+                    void *in,    unsigned long inlen,
+                    void *prime, unsigned long primelen,
+                    void *base,  unsigned long baselen,
+                    int type, dh_key *key)
+{
+   int err;
+
+   LTC_ARGCHK(in    != NULL);
+   LTC_ARGCHK(base  != NULL);
+   LTC_ARGCHK(prime != NULL);
+   LTC_ARGCHK(key   != NULL);
+
+   if ((err = mp_init_multi(&key->x, &key->y, &key->base, &key->prime, NULL)) != CRYPT_OK) {
+      goto error;
+   }
+   if (radix == 256) {
+      if ((err = mp_read_unsigned_bin(key->base, base, baselen)) != CRYPT_OK)     { goto error; }
+      if ((err = mp_read_unsigned_bin(key->prime, prime, primelen)) != CRYPT_OK)  { goto error; }
+   }
+   else {
+      if ((err = mp_read_radix(key->base, base, radix)) != CRYPT_OK)              { goto error; }
+      if ((err = mp_read_radix(key->prime, prime, radix)) != CRYPT_OK)            { goto error; }
+   }
+
+   if (type == PK_PRIVATE) {
+      /* load the x value */
+      if (radix == 256) {
+         if ((err = mp_read_unsigned_bin(key->x, in, inlen)) != CRYPT_OK)         { goto error; }
+      }
+      else {
+         if ((err = mp_read_radix(key->x, in, radix)) != CRYPT_OK)                { goto error; }
+      }
+      /* compute y value */
+      if ((err = mp_exptmod(key->base, key->x, key->prime, key->y)) != CRYPT_OK)  { goto error; }
+      key->type = PK_PRIVATE;
+   }
+   else {
+      /* load the y value */
+      if (radix == 256) {
+         if ((err = mp_read_unsigned_bin(key->y, in, inlen)) != CRYPT_OK)         { goto error; }
+      }
+      else {
+         if ((err = mp_read_radix(key->y, in, radix)) != CRYPT_OK)                { goto error; }
+      }
+      key->type = PK_PUBLIC;
+      mp_clear(key->x);
+      key->x = NULL;
+   }
+
+   /* check public key */
+   if ((err = dh_check_pubkey(key)) != CRYPT_OK) {
+      goto error;
+   }
+
+   return CRYPT_OK;
+
+error:
+   mp_clear_multi(key->prime, key->base, key->y, key->x, NULL);
+   return err;
+}
+
+#endif /* LTC_MDH */
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */

+ 207 - 0
src/pk/dh/dh_make_key.c

@@ -0,0 +1,207 @@
+/* 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_MDH
+
+static int _dh_groupsize_to_keysize(int groupsize)
+{
+   /* The strength estimates from https://tools.ietf.org/html/rfc3526#section-8
+    * We use "Estimate 2" to get an appropriate private key (exponent) size.
+    */
+   if (groupsize <= 0) {
+      return 0;
+   }
+   else if (groupsize <= 192) {
+      return 30;     /* 1536-bit => key size 240-bit */
+   }
+   else if (groupsize <= 256) {
+      return 40;     /* 2048-bit => key size 320-bit */
+   }
+   else if (groupsize <= 384) {
+      return 52;     /* 3072-bit => key size 416-bit */
+   }
+   else if (groupsize <= 512) {
+      return 60;     /* 4096-bit => key size 480-bit */
+   }
+   else if (groupsize <= 768) {
+      return 67;     /* 6144-bit => key size 536-bit */
+   }
+   else if (groupsize <= 1024) {
+      return 77;     /* 8192-bit => key size 616-bit */
+   }
+   else {
+      return 0;
+   }
+}
+
+static int _dh_make_key(prng_state *prng, int wprng, void *prime, void *base, dh_key *key)
+{
+   unsigned char *buf;
+   unsigned long keysize;
+   int err, max_iterations = PK_MAX_RETRIES;
+
+   LTC_ARGCHK(key   != NULL);
+   LTC_ARGCHK(prng  != NULL);
+   LTC_ARGCHK(prime != NULL);
+   LTC_ARGCHK(base  != NULL);
+
+   /* good prng? */
+   if ((err = prng_is_valid(wprng)) != CRYPT_OK) {
+      return err;
+   }
+
+   /* init big numbers */
+   if ((err = mp_init_multi(&key->x, &key->y, &key->base, &key->prime, NULL)) != CRYPT_OK) {
+      return err;
+   }
+
+   /* load the prime and the base */
+   if ((err = mp_copy(base, key->base)) != CRYPT_OK)   { goto freemp; }
+   if ((err = mp_copy(prime, key->prime)) != CRYPT_OK) { goto freemp; }
+
+   keysize = _dh_groupsize_to_keysize(mp_unsigned_bin_size(key->prime));
+   if (keysize == 0) {
+      err = CRYPT_INVALID_KEYSIZE;
+      goto freemp;
+   }
+
+   /* allocate buffer */
+   buf = XMALLOC(keysize);
+   if (buf == NULL) {
+      err = CRYPT_MEM;
+      goto freemp;
+   }
+
+   key->type = PK_PRIVATE;
+   do {
+      /* make up random buf */
+      if (prng_descriptor[wprng].read(buf, keysize, prng) != keysize) {
+         err = CRYPT_ERROR_READPRNG;
+         goto freebuf;
+      }
+      /* load the x value - private key */
+      if ((err = mp_read_unsigned_bin(key->x, buf, keysize)) != CRYPT_OK) {
+         goto freebuf;
+      }
+      /* compute the y value - public key */
+      if ((err = mp_exptmod(key->base, key->x, key->prime, key->y)) != CRYPT_OK) {
+         goto freebuf;
+      }
+      err = dh_check_pubkey(key);
+   } while (err != CRYPT_OK && max_iterations-- > 0);
+
+freebuf:
+   zeromem(buf, keysize);
+   XFREE(buf);
+freemp:
+   if (err != CRYPT_OK) mp_clear_multi(key->x, key->y, key->base, key->prime, NULL);
+   return err;
+}
+
+/**
+  Make a DH key (custom DH group) [private key pair]
+  @param prng       An active PRNG state
+  @param wprng      The index for the PRNG you desire to use
+  @param prime_hex  The prime p (hexadecimal string)
+  @param base_hex   The base g (hexadecimal string)
+  @param key        [out] Where the newly created DH key will be stored
+  @return CRYPT_OK if successful, note: on error all allocated memory will be freed automatically.
+*/
+static int _dh_make_key_ex(prng_state *prng, int wprng, int radix,
+                   void *prime, unsigned long primelen,
+                   void *base,  unsigned long baselen,
+                   dh_key *key)
+{
+   void *p, *b;
+   int err;
+
+   LTC_ARGCHK(prime != NULL);
+   LTC_ARGCHK(base  != NULL);
+   LTC_ARGCHK((radix >= 2 && radix <= 64) || radix == 256);
+
+   if ((err = mp_init_multi(&p, &b, NULL)) != CRYPT_OK)    { return err; }
+   if (radix == 256) {
+     if ((err = mp_read_unsigned_bin(b, base, baselen)) != CRYPT_OK)   { goto error; }
+     if ((err = mp_read_unsigned_bin(p, prime, primelen)) != CRYPT_OK) { goto error; }
+   }
+   else {
+     if ((err = mp_read_radix(b, base, radix)) != CRYPT_OK)  { goto error; }
+     if ((err = mp_read_radix(p, prime, radix)) != CRYPT_OK) { goto error; }
+   }
+   err = _dh_make_key(prng, wprng, p, b, key);
+
+error:
+   mp_clear_multi(p, b, NULL);
+   return err;
+}
+
+/**
+  Make a DH key (use built-in DH groups) [private key pair]
+  @param prng       An active PRNG state
+  @param wprng      The index for the PRNG you desire to use
+  @param groupsize  The size (octets) of used DH group
+  @param key        [out] Where the newly created DH key will be stored
+  @return CRYPT_OK if successful, note: on error all allocated memory will be freed automatically.
+*/
+int dh_make_key(prng_state *prng, int wprng, int groupsize, dh_key *key)
+{
+   int i;
+
+   LTC_ARGCHK(groupsize > 0);
+
+   for (i = 0; (groupsize > ltc_dh_sets[i].size) && (ltc_dh_sets[i].size != 0); i++);
+   if (ltc_dh_sets[i].size == 0) return CRYPT_INVALID_KEYSIZE;
+
+   return _dh_make_key_ex(prng, wprng, 16,
+                         ltc_dh_sets[i].prime, strlen(ltc_dh_sets[i].prime) + 1,
+                         ltc_dh_sets[i].base,  strlen(ltc_dh_sets[i].base)  + 1,
+                         key);
+}
+
+/**
+  Make a DH key (dhparam data: openssl dhparam -outform DER -out dhparam.der 2048)
+  @param prng       An active PRNG state
+  @param wprng      The index for the PRNG you desire to use
+  @param dhparam    The DH param DER encoded data
+  @param dhparamlen The length of dhparam data
+  @param key        [out] Where the newly created DH key will be stored
+  @return CRYPT_OK if successful, note: on error all allocated memory will be freed automatically.
+*/
+int dh_make_key_dhparam(prng_state *prng, int wprng, unsigned char *dhparam, unsigned long dhparamlen, dh_key *key)
+{
+   void *prime, *base;
+   int err;
+
+   LTC_ARGCHK(dhparam != NULL);
+   LTC_ARGCHK(dhparamlen > 0);
+
+   if ((err = mp_init_multi(&prime, &base, NULL)) != CRYPT_OK) {
+      return err;
+   }
+   if ((err = der_decode_sequence_multi(dhparam, dhparamlen,
+                                        LTC_ASN1_INTEGER, 1UL, prime,
+                                        LTC_ASN1_INTEGER, 1UL, base,
+                                        LTC_ASN1_EOL,     0UL, NULL)) != CRYPT_OK) {
+      goto error;
+   }
+   err = _dh_make_key(prng, wprng, prime, base, key);
+
+error:
+   mp_clear_multi(prime, base, NULL);
+   return err;
+}
+
+
+#endif /* LTC_MDH */
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */

+ 80 - 0
src/pk/dh/dh_shared_secret.c

@@ -0,0 +1,80 @@
+/* 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_MDH
+
+/**
+   Create a DH shared secret.
+   @param private_key     The private DH key in the pair
+   @param public_key      The public DH key in the pair
+   @param out             [out] The destination of the shared data
+   @param outlen          [in/out] The max size and resulting size of the shared data.
+   @return CRYPT_OK if successful
+*/
+int dh_shared_secret(dh_key *private_key, dh_key *public_key,
+                     unsigned char *out, unsigned long *outlen)
+{
+   void *tmp;
+   unsigned long x;
+   int err;
+
+   LTC_ARGCHK(private_key != NULL);
+   LTC_ARGCHK(public_key  != NULL);
+   LTC_ARGCHK(out         != NULL);
+   LTC_ARGCHK(outlen      != NULL);
+
+   /* types valid? */
+   if (private_key->type != PK_PRIVATE) {
+      return CRYPT_PK_NOT_PRIVATE;
+   }
+
+   /* same DH group? */
+   if (mp_cmp(private_key->prime, public_key->prime) != LTC_MP_EQ) { return CRYPT_PK_TYPE_MISMATCH; }
+   if (mp_cmp(private_key->base, public_key->base) != LTC_MP_EQ)   { return CRYPT_PK_TYPE_MISMATCH; }
+
+   /* init big numbers */
+   if ((err = mp_init(&tmp)) != CRYPT_OK) {
+      return err;
+   }
+
+   /* check public key */
+   if ((err = dh_check_pubkey(public_key)) != CRYPT_OK) {
+      goto error;
+   }
+
+   /* compute tmp = y^x mod p */
+   if ((err = mp_exptmod(public_key->y, private_key->x, private_key->prime, tmp)) != CRYPT_OK)  {
+      goto error;
+   }
+
+   /* enough space for output? */
+   x = (unsigned long)mp_unsigned_bin_size(tmp);
+   if (*outlen < x) {
+      *outlen = x;
+      err = CRYPT_BUFFER_OVERFLOW;
+      goto error;
+   }
+   if ((err = mp_to_unsigned_bin(tmp, out)) != CRYPT_OK) {
+      goto error;
+   }
+   *outlen = x;
+   err = CRYPT_OK;
+
+error:
+   mp_clear(tmp);
+   return err;
+}
+
+#endif /* LTC_MDH */
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */

+ 0 - 243
src/pk/dh/dh_static.c

@@ -1,243 +0,0 @@
-/* LibTomCrypt, modular cryptographic library -- Tom St Denis
- *
- * LibTomCrypt is a library that provides various cryptographic
- * algorithms in a highly modular and flexible manner.
- *
- * The library is free for all purposes without any express
- * guarantee it works.
- *
- * Tom St Denis, [email protected], http://libtomcrypt.org
- */
-#include "tomcrypt.h"
-
-/**
-  @file dh_static.c
-  DH crypto, Tom St Denis
-*/
-
-#ifdef LTC_MDH
-
-#define __DECL_DH_STATIC_H__
-#include "dh_static.h"
-
-/* This holds the key settings.  ***MUST*** be organized by size from smallest to largest. */
-const dh_set sets[] = {
-#ifdef LTC_DH768
-{  /* 768-bit MODP Group 1 - https://tools.ietf.org/html/rfc7296#appendix-B.1 */
-   96,
-   "DH-768",
-   "2",
-   "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
-   "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
-   "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
-   "E485B576625E7EC6F44C42E9A63A3620FFFFFFFFFFFFFFFF"
-},
-#endif
-#ifdef LTC_DH1024
-{  /* 1024-bit MODP Group 2 - https://tools.ietf.org/html/rfc7296#appendix-B.2 */
-   128,
-   "DH-1024",
-   "2",
-   "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
-   "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
-   "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
-   "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
-   "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381"
-   "FFFFFFFFFFFFFFFF"
-},
-#endif
-#ifdef LTC_DH1536
-{  /* 1536-bit MODP Group 5 - https://tools.ietf.org/html/rfc3526#section-2 */
-   192,
-   "DH-1536",
-   "2",
-   "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
-   "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
-   "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
-   "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
-   "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
-   "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F"
-   "83655D23DCA3AD961C62F356208552BB9ED529077096966D"
-   "670C354E4ABC9804F1746C08CA237327FFFFFFFFFFFFFFFF"
-},
-#endif
-#ifdef LTC_DH2048
-{  /* 2048-bit MODP Group 14 - https://tools.ietf.org/html/rfc3526#section-3 */
-   256,
-   "DH-2048",
-   "2",
-   "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
-   "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
-   "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
-   "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
-   "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
-   "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F"
-   "83655D23DCA3AD961C62F356208552BB9ED529077096966D"
-   "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B"
-   "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9"
-   "DE2BCBF6955817183995497CEA956AE515D2261898FA0510"
-   "15728E5A8AACAA68FFFFFFFFFFFFFFFF"
-},
-#endif
-#ifdef LTC_DH3072
-{  /* 3072-bit MODP Group 15 - https://tools.ietf.org/html/rfc3526#section-4 */
-   384,
-   "DH-3072",
-   "2",
-   "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
-   "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
-   "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
-   "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
-   "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
-   "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F"
-   "83655D23DCA3AD961C62F356208552BB9ED529077096966D"
-   "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B"
-   "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9"
-   "DE2BCBF6955817183995497CEA956AE515D2261898FA0510"
-   "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64"
-   "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7"
-   "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B"
-   "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C"
-   "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31"
-   "43DB5BFCE0FD108E4B82D120A93AD2CAFFFFFFFFFFFFFFFF"
-},
-#endif
-#ifdef LTC_DH4096
-{  /* 4096-bit MODP Group 16 - https://tools.ietf.org/html/rfc3526#section-5 */
-   512,
-   "DH-4096",
-   "2",
-   "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
-   "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
-   "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
-   "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
-   "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
-   "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F"
-   "83655D23DCA3AD961C62F356208552BB9ED529077096966D"
-   "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B"
-   "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9"
-   "DE2BCBF6955817183995497CEA956AE515D2261898FA0510"
-   "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64"
-   "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7"
-   "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B"
-   "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C"
-   "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31"
-   "43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7"
-   "88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA"
-   "2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6"
-   "287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED"
-   "1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9"
-   "93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934063199"
-   "FFFFFFFFFFFFFFFF"
-},
-#endif
-#ifdef LTC_DH6144
-{  /* 6144-bit MODP Group 17 - https://tools.ietf.org/html/rfc3526#section-6 */
-   786,
-   "DH-6144",
-   "2",
-   "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
-   "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
-   "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
-   "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
-   "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
-   "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F"
-   "83655D23DCA3AD961C62F356208552BB9ED529077096966D"
-   "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B"
-   "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9"
-   "DE2BCBF6955817183995497CEA956AE515D2261898FA0510"
-   "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64"
-   "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7"
-   "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B"
-   "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C"
-   "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31"
-   "43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7"
-   "88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA"
-   "2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6"
-   "287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED"
-   "1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9"
-   "93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934028492"
-   "36C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BD"
-   "F8FF9406AD9E530EE5DB382F413001AEB06A53ED9027D831"
-   "179727B0865A8918DA3EDBEBCF9B14ED44CE6CBACED4BB1B"
-   "DB7F1447E6CC254B332051512BD7AF426FB8F401378CD2BF"
-   "5983CA01C64B92ECF032EA15D1721D03F482D7CE6E74FEF6"
-   "D55E702F46980C82B5A84031900B1C9E59E7C97FBEC7E8F3"
-   "23A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA"
-   "CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE328"
-   "06A1D58BB7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55C"
-   "DA56C9EC2EF29632387FE8D76E3C0468043E8F663F4860EE"
-   "12BF2D5B0B7474D6E694F91E6DCC4024FFFFFFFFFFFFFFFF"
-},
-#endif
-#ifdef LTC_DH8192
-{  /* 8192-bit MODP Group 18 - https://tools.ietf.org/html/rfc3526#section-7 */
-   1024,
-   "DH-8192",
-   "2",
-   "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
-   "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
-   "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
-   "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
-   "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
-   "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F"
-   "83655D23DCA3AD961C62F356208552BB9ED529077096966D"
-   "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B"
-   "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9"
-   "DE2BCBF6955817183995497CEA956AE515D2261898FA0510"
-   "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64"
-   "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7"
-   "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B"
-   "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C"
-   "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31"
-   "43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7"
-   "88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA"
-   "2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6"
-   "287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED"
-   "1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9"
-   "93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934028492"
-   "36C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BD"
-   "F8FF9406AD9E530EE5DB382F413001AEB06A53ED9027D831"
-   "179727B0865A8918DA3EDBEBCF9B14ED44CE6CBACED4BB1B"
-   "DB7F1447E6CC254B332051512BD7AF426FB8F401378CD2BF"
-   "5983CA01C64B92ECF032EA15D1721D03F482D7CE6E74FEF6"
-   "D55E702F46980C82B5A84031900B1C9E59E7C97FBEC7E8F3"
-   "23A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA"
-   "CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE328"
-   "06A1D58BB7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55C"
-   "DA56C9EC2EF29632387FE8D76E3C0468043E8F663F4860EE"
-   "12BF2D5B0B7474D6E694F91E6DBE115974A3926F12FEE5E4"
-   "38777CB6A932DF8CD8BEC4D073B931BA3BC832B68D9DD300"
-   "741FA7BF8AFC47ED2576F6936BA424663AAB639C5AE4F568"
-   "3423B4742BF1C978238F16CBE39D652DE3FDB8BEFC848AD9"
-   "22222E04A4037C0713EB57A81A23F0C73473FC646CEA306B"
-   "4BCBC8862F8385DDFA9D4B7FA2C087E879683303ED5BDD3A"
-   "062B3CF5B3A278A66D2A13F83F44F82DDF310EE074AB6A36"
-   "4597E899A0255DC164F31CC50846851DF9AB48195DED7EA1"
-   "B1D510BD7EE74D73FAF36BC31ECFA268359046F4EB879F92"
-   "4009438B481C6CD7889A002ED5EE382BC9190DA6FC026E47"
-   "9558E4475677E9AA9E3050E2765694DFC81F56E880B96E71"
-   "60C980DD98EDD3DFFFFFFFFFFFFFFFFF"
-},
-#endif
-{
-   0,
-   NULL,
-   NULL,
-   NULL
-}
-};
-
-int dh_is_valid_idx(int n)
-{
-   int x;
-
-   for (x = 0; sets[x].size; x++);
-   if ((n < 0) || (n >= x)) {
-      return 0;
-   }
-   return 1;
-}
-
-
-#endif /* LTC_MDH */

+ 0 - 125
src/pk/dh/dh_static.h

@@ -1,125 +0,0 @@
-#ifndef __DH_STATIC_H__
-#define __DH_STATIC_H__
-#ifndef __DECL_DH_STATIC_H__
-#define __DECL_DH_STATIC_H__ extern
-#endif
-
-/* 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.
- *
- * Tom St Denis, [email protected], http://libtomcrypt.org
- */
-#include "tomcrypt.h"
-
-/**
-  @file dh_static.h
-  DH crypto, Tom St Denis
-*/
-
-#ifdef LTC_MDH
-
-/* size of a packet header in bytes */
-#define PACKET_SIZE            4
-
-/* Section tags */
-#define PACKET_SECT_DH         1
-
-/* Subsection Tags for the first three sections */
-#define PACKET_SUB_KEY         0
-#define PACKET_SUB_ENCRYPTED   1
-#define PACKET_SUB_SIGNED      2
-#define PACKET_SUB_ENC_KEY     3
-
-#define OUTPUT_BIGNUM(num, out, y, z)                                                             \
-{                                                                                                 \
-      if ((y + 4) > *outlen) { return CRYPT_BUFFER_OVERFLOW; }                                    \
-      z = (unsigned long)mp_unsigned_bin_size(num);                                               \
-      STORE32L(z, out+y);                                                                         \
-      y += 4;                                                                                     \
-      if ((y + z) > *outlen) { return CRYPT_BUFFER_OVERFLOW; }                                    \
-      if ((err = mp_to_unsigned_bin(num, out+y)) != CRYPT_OK) { return err; }    \
-      y += z;                                                                                     \
-}
-
-#define INPUT_BIGNUM(num, in, x, y, inlen)                       \
-{                                                                \
-     /* load value */                                            \
-     if ((y + 4) > inlen) {                                      \
-        err = CRYPT_INVALID_PACKET;                              \
-        goto error;                                              \
-     }                                                           \
-     LOAD32L(x, in+y);                                           \
-     y += 4;                                                     \
-                                                                 \
-     /* sanity check... */                                       \
-     if ((x+y) > inlen) {                                        \
-        err = CRYPT_INVALID_PACKET;                              \
-        goto error;                                              \
-     }                                                           \
-                                                                 \
-     /* load it */                                               \
-     if ((err = mp_read_unsigned_bin(num, (unsigned char *)in+y, (int)x)) != CRYPT_OK) {\
-        goto error;                                              \
-     }                                                           \
-     y += x;                                                     \
-}
-
-static LTC_INLINE void packet_store_header (unsigned char *dst, int section, int subsection)
-{
-   LTC_ARGCHKVD(dst != NULL);
-
-   /* store version number */
-   dst[0] = (unsigned char)(CRYPT&255);
-   dst[1] = (unsigned char)((CRYPT>>8)&255);
-
-   /* store section and subsection */
-   dst[2] = (unsigned char)(section & 255);
-   dst[3] = (unsigned char)(subsection & 255);
-
-}
-
-static LTC_INLINE int packet_valid_header (unsigned char *src, int section, int subsection)
-{
-   unsigned long ver;
-
-   LTC_ARGCHK(src != NULL);
-
-   /* check version */
-   ver = ((unsigned long)src[0]) | ((unsigned long)src[1] << 8U);
-   if (CRYPT < ver) {
-      return CRYPT_INVALID_PACKET;
-   }
-
-   /* check section and subsection */
-   if (section != (int)src[2] || subsection != (int)src[3]) {
-      return CRYPT_INVALID_PACKET;
-   }
-
-   return CRYPT_OK;
-}
-
-#ifndef DH_BUF_SIZE
-/* max export size we'll encounter (smaller than this but lets round up a bit) */
-#define DH_BUF_SIZE 1200
-#endif /* DH_BUF_SIZE */
-
-typedef struct {
-  int size;
-  char *name, *base, *prime;
-} dh_set;
-
-/* This holds the key settings.  ***MUST*** be organized by size from smallest to largest. */
-__DECL_DH_STATIC_H__ const dh_set sets[];
-
-
-int dh_is_valid_idx(int n);
-
-
-#endif /* __DH_STATIC_H__ */
-
-#endif /* LTC_MDH */

+ 0 - 490
src/pk/dh/dh_sys.c

@@ -1,490 +0,0 @@
-/* LibTomCrypt, modular cryptographic library -- Tom St Denis
- *
- * LibTomCrypt is a library that provides various cryptographic
- * algorithms in a highly modular and flexible manner.
- *
- * The library is free for all purposes without any express
- * guarantee it works.
- *
- * Tom St Denis, [email protected], http://libtomcrypt.org
- */
-
-#include "tomcrypt.h"
-
-#ifdef LTC_MDH
-/**
-  @file dh_sys.c
-  DH Crypto, Tom St Denis
-*/
-
-#include "dh_static.h"
-
-
-/**
-  Encrypt a short symmetric key with a public DH key
-  @param in        The symmetric key to encrypt
-  @param inlen     The length of the key (octets)
-  @param out       [out] 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 desired
-  @param hash      The index of the hash desired (must produce a digest of size >= the size of the plaintext)
-  @param key       The public key you wish to encrypt with.
-  @return CRYPT_OK if successful
-*/
-int dh_encrypt_key(const unsigned char *in,   unsigned long inlen,
-                         unsigned char *out,  unsigned long *outlen,
-                         prng_state *prng, int wprng, int hash,
-                         dh_key *key)
-{
-    unsigned char *pub_expt, *dh_shared, *skey;
-    dh_key        pubkey;
-    unsigned long x, y, z, pubkeysize;
-    int           err;
-
-    LTC_ARGCHK(in != NULL);
-    LTC_ARGCHK(out   != NULL);
-    LTC_ARGCHK(outlen   != NULL);
-    LTC_ARGCHK(key   != NULL);
-
-    /* check that wprng/hash are not invalid */
-    if ((err = prng_is_valid(wprng)) != CRYPT_OK) {
-       return err;
-    }
-
-    if ((err = hash_is_valid(hash)) != CRYPT_OK) {
-       return err;
-    }
-
-    if (inlen > hash_descriptor[hash].hashsize)  {
-        return CRYPT_INVALID_HASH;
-    }
-
-    /* allocate memory */
-    pub_expt  = XMALLOC(DH_BUF_SIZE);
-    dh_shared = XMALLOC(DH_BUF_SIZE);
-    skey      = XMALLOC(MAXBLOCKSIZE);
-    if (pub_expt == NULL || dh_shared == NULL || skey == NULL) {
-       if (pub_expt != NULL) {
-          XFREE(pub_expt);
-       }
-       if (dh_shared != NULL) {
-          XFREE(dh_shared);
-       }
-       if (skey != NULL) {
-          XFREE(skey);
-       }
-       return CRYPT_MEM;
-    }
-
-    /* make a random key and export the public copy */
-    if ((err = dh_make_key(prng, wprng, dh_get_size(key), &pubkey)) != CRYPT_OK) {
-       goto LBL_ERR;
-    }
-
-    pubkeysize = DH_BUF_SIZE;
-    if ((err = dh_export(pub_expt, &pubkeysize, PK_PUBLIC, &pubkey)) != CRYPT_OK) {
-       dh_free(&pubkey);
-       goto LBL_ERR;
-    }
-
-    /* now check if the out buffer is big enough */
-    if (*outlen < (1 + 4 + 4 + PACKET_SIZE + pubkeysize + inlen)) {
-       dh_free(&pubkey);
-       err = CRYPT_BUFFER_OVERFLOW;
-       goto LBL_ERR;
-    }
-
-    x = DH_BUF_SIZE;
-    if ((err = dh_shared_secret(&pubkey, key, dh_shared, &x)) != CRYPT_OK) {
-       dh_free(&pubkey);
-       goto LBL_ERR;
-    }
-    dh_free(&pubkey);
-
-    z = MAXBLOCKSIZE;
-    if ((err = hash_memory(hash, dh_shared, x, skey, &z)) != CRYPT_OK) {
-       goto LBL_ERR;
-    }
-
-    /* store header */
-    packet_store_header(out, PACKET_SECT_DH, PACKET_SUB_ENC_KEY);
-
-    /* output header */
-    y = PACKET_SIZE;
-
-    /* size of hash name and the name itself */
-    out[y++] = hash_descriptor[hash].ID;
-
-    /* length of DH pubkey and the key itself */
-    STORE32L(pubkeysize, out+y);
-    y += 4;
-    for (x = 0; x < pubkeysize; x++, y++) {
-        out[y] = pub_expt[x];
-    }
-
-    /* Store the encrypted key */
-    STORE32L(inlen, out+y);
-    y += 4;
-
-    for (x = 0; x < inlen; x++, y++) {
-      out[y] = skey[x] ^ in[x];
-    }
-    *outlen = y;
-
-    err = CRYPT_OK;
-LBL_ERR:
-#ifdef LTC_CLEAN_STACK
-    /* clean up */
-    zeromem(pub_expt,  DH_BUF_SIZE);
-    zeromem(dh_shared, DH_BUF_SIZE);
-    zeromem(skey,      MAXBLOCKSIZE);
-#endif
-    XFREE(skey);
-    XFREE(dh_shared);
-    XFREE(pub_expt);
-
-    return err;
-}
-
-/**
-   Decrypt a DH encrypted symmetric key
-   @param in       The DH encrypted packet
-   @param inlen    The length of the DH encrypted packet
-   @param out      The plaintext
-   @param outlen   [in/out]  The max size and resulting size of the plaintext
-   @param key      The private DH key corresponding to the public key that encrypted the plaintext
-   @return CRYPT_OK if successful
-*/
-int dh_decrypt_key(const unsigned char *in, unsigned long inlen,
-                         unsigned char *out, unsigned long *outlen,
-                         dh_key *key)
-{
-   unsigned char *shared_secret, *skey;
-   unsigned long  x, y, z, keysize;
-   int            hash, err;
-   dh_key         pubkey;
-
-   LTC_ARGCHK(in     != NULL);
-   LTC_ARGCHK(out != NULL);
-   LTC_ARGCHK(outlen != NULL);
-   LTC_ARGCHK(key    != NULL);
-
-   /* right key type? */
-   if (key->type != PK_PRIVATE) {
-      return CRYPT_PK_NOT_PRIVATE;
-   }
-
-   /* allocate ram */
-   shared_secret = XMALLOC(DH_BUF_SIZE);
-   skey          = XMALLOC(MAXBLOCKSIZE);
-   if (shared_secret == NULL || skey == NULL) {
-      if (shared_secret != NULL) {
-         XFREE(shared_secret);
-      }
-      if (skey != NULL) {
-         XFREE(skey);
-      }
-      return CRYPT_MEM;
-   }
-
-   /* check if initial header should fit */
-   if (inlen < PACKET_SIZE+1+4+4) {
-      err =  CRYPT_INVALID_PACKET;
-      goto LBL_ERR;
-   } else {
-      inlen -= PACKET_SIZE+1+4+4;
-   }
-
-   /* is header correct? */
-   if ((err = packet_valid_header((unsigned char *)in, PACKET_SECT_DH, PACKET_SUB_ENC_KEY)) != CRYPT_OK)  {
-      goto LBL_ERR;
-   }
-
-   /* now lets get the hash name */
-   y = PACKET_SIZE;
-   hash = find_hash_id(in[y++]);
-   if (hash == -1) {
-      err = CRYPT_INVALID_HASH;
-      goto LBL_ERR;
-   }
-
-   /* get public key */
-   LOAD32L(x, in+y);
-
-   /* now check if the imported key will fit */
-   if (inlen < x) {
-      err = CRYPT_INVALID_PACKET;
-      goto LBL_ERR;
-   } else {
-      inlen -= x;
-   }
-
-   y += 4;
-   if ((err = dh_import(in+y, x, &pubkey)) != CRYPT_OK) {
-      goto LBL_ERR;
-   }
-   y += x;
-
-   /* make shared key */
-   x = DH_BUF_SIZE;
-   if ((err = dh_shared_secret(key, &pubkey, shared_secret, &x)) != CRYPT_OK) {
-      dh_free(&pubkey);
-      goto LBL_ERR;
-   }
-   dh_free(&pubkey);
-
-   z = MAXBLOCKSIZE;
-   if ((err = hash_memory(hash, shared_secret, x, skey, &z)) != CRYPT_OK) {
-      goto LBL_ERR;
-   }
-
-   /* load in the encrypted key */
-   LOAD32L(keysize, in+y);
-
-   /* will the out fit as part of the input */
-   if (inlen < keysize) {
-      err = CRYPT_INVALID_PACKET;
-      goto LBL_ERR;
-   }
-
-   if (keysize > *outlen) {
-       err = CRYPT_BUFFER_OVERFLOW;
-       goto LBL_ERR;
-   }
-   y += 4;
-
-   *outlen = keysize;
-
-   for (x = 0; x < keysize; x++, y++) {
-      out[x] = skey[x] ^ in[y];
-   }
-
-   err = CRYPT_OK;
-LBL_ERR:
-#ifdef LTC_CLEAN_STACK
-   zeromem(shared_secret, DH_BUF_SIZE);
-   zeromem(skey,          MAXBLOCKSIZE);
-#endif
-
-   XFREE(skey);
-   XFREE(shared_secret);
-
-   return err;
-}
-
-/* perform an ElGamal Signature of a hash
- *
- * The math works as follows.  x is the private key, M is the message to sign
-
- 1.  pick a random k
- 2.  compute a = g^k mod p
- 3.  compute b = (M - xa)/k mod p
- 4.  Send (a,b)
-
- Now to verify with y=g^x mod p, a and b
-
- 1.  compute y^a * a^b = g^(xa) * g^(k*(M-xa)/k)
-                       = g^(xa + (M - xa))
-                       = g^M [all mod p]
-
- 2.  Compare against g^M mod p [based on input hash].
- 3.  If result of #2 == result of #1 then signature valid
-*/
-
-/**
-  Sign a message digest using a DH private key
-  @param in      The data to sign
-  @param inlen   The length of the input (octets)
-  @param out     [out] The destination of the signature
-  @param outlen  [in/out] The max size and resulting size of the output
-  @param prng    An active PRNG state
-  @param wprng   The index of the PRNG desired
-  @param key     A private DH key
-  @return CRYPT_OK if successful
-*/
-int dh_sign_hash(const unsigned char *in,  unsigned long inlen,
-                       unsigned char *out, unsigned long *outlen,
-                       prng_state *prng, int wprng, dh_key *key)
-{
-   void         *a, *b, *k, *m, *g, *p, *p1, *tmp;
-   unsigned char *buf;
-   unsigned long  x, y;
-   int            err;
-
-   LTC_ARGCHK(in     != NULL);
-   LTC_ARGCHK(out    != NULL);
-   LTC_ARGCHK(outlen != NULL);
-   LTC_ARGCHK(key    != NULL);
-
-   /* check parameters */
-   if (key->type != PK_PRIVATE) {
-      return CRYPT_PK_NOT_PRIVATE;
-   }
-
-   if ((err = prng_is_valid(wprng)) != CRYPT_OK) {
-      return err;
-   }
-
-   /* is the IDX valid ?  */
-   if (dh_is_valid_idx(key->idx) != 1) {
-      return CRYPT_PK_INVALID_TYPE;
-   }
-
-   /* allocate ram for buf */
-   buf = XMALLOC(520);
-
-   /* make up a random value k,
-    * since the order of the group is prime
-    * we need not check if gcd(k, r) is 1
-    */
-   if (prng_descriptor[wprng].read(buf, sets[key->idx].size, prng) !=
-       (unsigned long)(sets[key->idx].size)) {
-      err = CRYPT_ERROR_READPRNG;
-      goto LBL_ERR_1;
-   }
-
-   /* init bignums */
-   if ((err = mp_init_multi(&a, &b, &k, &m, &p, &g, &p1, &tmp, NULL)) != CRYPT_OK) {
-      goto LBL_ERR;
-   }
-
-   /* load k and m */
-   if ((err = mp_read_unsigned_bin(m, (unsigned char *)in, inlen)) != CRYPT_OK)        { goto LBL_ERR; }
-   if ((err = mp_read_unsigned_bin(k, buf, sets[key->idx].size)) != CRYPT_OK)          { goto LBL_ERR; }
-
-   /* load g, p and p1 */
-   if ((err = mp_read_radix(g, sets[key->idx].base, 16)) != CRYPT_OK)               { goto LBL_ERR; }
-   if ((err = mp_read_radix(p, sets[key->idx].prime, 16)) != CRYPT_OK)              { goto LBL_ERR; }
-   if ((err = mp_sub_d(p, 1, p1)) != CRYPT_OK)                                     { goto LBL_ERR; }
-   if ((err = mp_div_2(p1, p1)) != CRYPT_OK)                                       { goto LBL_ERR; } /* p1 = (p-1)/2 */
-
-   /* now get a = g^k mod p */
-   if ((err = mp_exptmod(g, k, p, a)) != CRYPT_OK)                               { goto LBL_ERR; }
-
-   /* now find M = xa + kb mod p1 or just b = (M - xa)/k mod p1 */
-   if ((err = mp_invmod(k, p1, k)) != CRYPT_OK)                                   { goto LBL_ERR; } /* k = 1/k mod p1 */
-   if ((err = mp_mulmod(a, key->x, p1, tmp)) != CRYPT_OK)                        { goto LBL_ERR; } /* tmp = xa */
-   if ((err = mp_submod(m, tmp, p1, tmp)) != CRYPT_OK)                           { goto LBL_ERR; } /* tmp = M - xa */
-   if ((err = mp_mulmod(k, tmp, p1, b)) != CRYPT_OK)                             { goto LBL_ERR; } /* b = (M - xa)/k */
-
-   /* check for overflow */
-   if ((unsigned long)(PACKET_SIZE + 4 + 4 + mp_unsigned_bin_size(a) + mp_unsigned_bin_size(b)) > *outlen) {
-      err = CRYPT_BUFFER_OVERFLOW;
-      goto LBL_ERR;
-   }
-
-   /* store header  */
-   y = PACKET_SIZE;
-
-   /* now store them both (a,b) */
-   x = (unsigned long)mp_unsigned_bin_size(a);
-   STORE32L(x, out+y);  y += 4;
-   if ((err = mp_to_unsigned_bin(a, out+y)) != CRYPT_OK)                            { goto LBL_ERR; }
-   y += x;
-
-   x = (unsigned long)mp_unsigned_bin_size(b);
-   STORE32L(x, out+y);  y += 4;
-   if ((err = mp_to_unsigned_bin(b, out+y)) != CRYPT_OK)                            { goto LBL_ERR; }
-   y += x;
-
-   /* check if size too big */
-   if (*outlen < y) {
-      err = CRYPT_BUFFER_OVERFLOW;
-      goto LBL_ERR;
-   }
-
-   /* store header */
-   packet_store_header(out, PACKET_SECT_DH, PACKET_SUB_SIGNED);
-   *outlen = y;
-
-   err = CRYPT_OK;
-LBL_ERR:
-   mp_clear_multi(tmp, p1, g, p, m, k, b, a, NULL);
-LBL_ERR_1:
-
-   XFREE(buf);
-
-   return err;
-}
-
-
-/**
-   Verify the signature given
-   @param sig        The signature
-   @param siglen     The length of the signature (octets)
-   @param hash       The hash that was signed
-   @param hashlen    The length of the hash (octets)
-   @param stat       [out] Result of signature comparison, 1==valid, 0==invalid
-   @param key        The public DH key that signed the hash
-   @return CRYPT_OK if succsessful (even if signature is invalid)
-*/
-int dh_verify_hash(const unsigned char *sig, unsigned long siglen,
-                   const unsigned char *hash, unsigned long hashlen,
-                         int *stat, dh_key *key)
-{
-   void        *a, *b, *p, *g, *m, *tmp;
-   unsigned long x, y;
-   int           err;
-
-   LTC_ARGCHK(sig  != NULL);
-   LTC_ARGCHK(hash != NULL);
-   LTC_ARGCHK(stat != NULL);
-   LTC_ARGCHK(key  != NULL);
-
-   /* default to invalid */
-   *stat = 0;
-
-   /* check initial input length */
-   if (siglen < PACKET_SIZE+4+4) {
-      return CRYPT_INVALID_PACKET;
-   }
-
-   /* header ok? */
-   if ((err = packet_valid_header((unsigned char *)sig, PACKET_SECT_DH, PACKET_SUB_SIGNED)) != CRYPT_OK) {
-      return err;
-   }
-
-   /* get hash out of packet */
-   y = PACKET_SIZE;
-
-   /* init all bignums */
-   if ((err = mp_init_multi(&a, &p, &b, &g, &m, &tmp, NULL)) != CRYPT_OK) {
-      return err;
-   }
-
-   /* load a and b */
-   INPUT_BIGNUM(a, sig, x, y, siglen);
-   INPUT_BIGNUM(b, sig, x, y, siglen);
-
-   /* load p and g */
-   if ((err = mp_read_radix(p, sets[key->idx].prime, 16)) != CRYPT_OK)              { goto error1; }
-   if ((err = mp_read_radix(g, sets[key->idx].base, 16)) != CRYPT_OK)               { goto error1; }
-
-   /* load m */
-   if ((err = mp_read_unsigned_bin(m, (unsigned char *)hash, hashlen)) != CRYPT_OK) { goto error1; }
-
-   /* find g^m mod p */
-   if ((err = mp_exptmod(g, m, p, m)) != CRYPT_OK)                { goto error1; } /* m = g^m mod p */
-
-   /* find y^a * a^b */
-   if ((err = mp_exptmod(key->y, a, p, tmp)) != CRYPT_OK)         { goto error1; } /* tmp = y^a mod p */
-   if ((err = mp_exptmod(a, b, p, a)) != CRYPT_OK)                { goto error1; } /* a = a^b mod p */
-   if ((err = mp_mulmod(a, tmp, p, a)) != CRYPT_OK)               { goto error1; } /* a = y^a * a^b mod p */
-
-   /* y^a * a^b == g^m ??? */
-   if (mp_cmp(a, m) == 0) {
-      *stat = 1;
-   }
-
-   /* clean up */
-   err = CRYPT_OK;
-   goto done;
-error1:
-error:
-done:
-   mp_clear_multi(tmp, m, g, p, b, a, NULL);
-   return err;
-}
-
-#endif /* LTC_MDH */

+ 203 - 91
tests/dh_test.c

@@ -16,108 +16,220 @@
 #define KEYSIZE 2048
 #endif
 
-int dh_test (void)
+static int _prime_test(void)
 {
-  unsigned char buf[3][4096], ch;
-  unsigned long x, y, z;
-  int           stat, stat2;
-  dh_key        usera, userb;
+   void *p, *g, *tmp;
+   int x, err, primality;
+
+   if ((err = mp_init_multi(&p, &g, &tmp, NULL)) != CRYPT_OK)               { goto error; }
+
+   for (x = 0; ltc_dh_sets[x].size != 0; x++) {
+      if ((err = mp_read_radix(g, ltc_dh_sets[x].base, 16)) != CRYPT_OK)    { goto error; }
+      if ((err = mp_read_radix(p, ltc_dh_sets[x].prime, 16)) != CRYPT_OK)   { goto error; }
+
+      /* ensure p is prime */
+      if ((err = mp_prime_is_prime(p, 8, &primality)) != CRYPT_OK)          { goto done; }
+      if (primality != LTC_MP_YES ) {
+         err = CRYPT_FAIL_TESTVECTOR;
+         goto done;
+      }
+
+      if ((err = mp_sub_d(p, 1, tmp)) != CRYPT_OK)                          { goto error; }
+      if ((err = mp_div_2(tmp, tmp)) != CRYPT_OK)                           { goto error; }
+
+      /* ensure (p-1)/2 is prime */
+      if ((err = mp_prime_is_prime(tmp, 8, &primality)) != CRYPT_OK)        { goto done; }
+      if (primality == 0) {
+         err = CRYPT_FAIL_TESTVECTOR;
+         goto done;
+      }
+
+      /* now see if g^((p-1)/2) mod p is in fact 1 */
+      if ((err = mp_exptmod(g, tmp, p, tmp)) != CRYPT_OK)                   { goto error; }
+      if (mp_cmp_d(tmp, 1)) {
+         err = CRYPT_FAIL_TESTVECTOR;
+         goto done;
+      }
+   }
+   err = CRYPT_OK;
+error:
+done:
+   mp_clear_multi(tmp, g, p, NULL);
+   return err;
+}
+
+static int _dhparam_test(void)
+{
+   dh_key k;
+   unsigned char buf[1024];
+   /* generated by: openssl dhparam -outform der -out dhparam.der 2048 */
+   unsigned char dhparam_der[] = {
+      0x30, 0x82, 0x01, 0x08, 0x02, 0x82, 0x01, 0x01, 0x00, 0xae, 0xfe, 0x78, 0xce, 0x80, 0xd5, 0xd7,
+      0x8e, 0xcc, 0x4f, 0x0c, 0x1b, 0xb0, 0x95, 0x10, 0xe1, 0x41, 0x15, 0x53, 0x4d, 0x0e, 0x68, 0xb0,
+      0xf8, 0x5a, 0x41, 0x0e, 0x65, 0x2f, 0x9f, 0xac, 0x9c, 0x30, 0xb0, 0x76, 0xec, 0x02, 0xe9, 0x43,
+      0x55, 0x08, 0xb4, 0x20, 0x60, 0xd9, 0x52, 0xda, 0x2d, 0xab, 0x9a, 0xba, 0xe6, 0xcf, 0x11, 0xa7,
+      0x00, 0x44, 0xc2, 0x5e, 0xd1, 0xba, 0x9b, 0xaa, 0xfe, 0x03, 0xdd, 0xdc, 0xef, 0x41, 0x89, 0x9c,
+      0xac, 0x64, 0x13, 0xd9, 0x6a, 0x8a, 0x55, 0xa0, 0x5b, 0xff, 0x12, 0x92, 0x37, 0x52, 0x6a, 0x91,
+      0xa4, 0x6e, 0x9e, 0x61, 0xb7, 0xfe, 0xb0, 0x17, 0x8e, 0x67, 0x0f, 0x88, 0x46, 0xa7, 0x9e, 0xb1,
+      0xdb, 0x68, 0x77, 0x70, 0xb5, 0x77, 0xf2, 0x7e, 0x33, 0xb1, 0x3e, 0x10, 0xc4, 0x63, 0x36, 0xd0,
+      0x13, 0x27, 0xd3, 0x29, 0xc3, 0xb6, 0x5d, 0xf6, 0x5d, 0xa7, 0xd8, 0x25, 0x5c, 0x0b, 0x65, 0x99,
+      0xfa, 0xf9, 0x5f, 0x1d, 0xee, 0xd1, 0x86, 0x64, 0x7c, 0x44, 0xcb, 0xa0, 0x12, 0x52, 0x4c, 0xd4,
+      0x46, 0x81, 0xae, 0x07, 0xdb, 0xc7, 0x13, 0x29, 0xce, 0x9b, 0xcf, 0x1c, 0x06, 0xd2, 0x0f, 0x2d,
+      0xbb, 0x12, 0x33, 0xb9, 0xb1, 0x0f, 0x67, 0x5d, 0x3f, 0x0c, 0xe4, 0xfa, 0x67, 0x26, 0xe2, 0x89,
+      0xa2, 0xd5, 0x66, 0x29, 0x1c, 0xe2, 0x8e, 0xbb, 0x7b, 0xcb, 0xcc, 0x70, 0x7e, 0x4f, 0x0e, 0xd3,
+      0x5d, 0x64, 0x64, 0x1b, 0x27, 0xbb, 0xda, 0xa9, 0x08, 0x2b, 0x62, 0xd4, 0xca, 0xc3, 0x3a, 0x23,
+      0x39, 0x58, 0x57, 0xaf, 0x7b, 0x8b, 0x0c, 0x5b, 0x2e, 0xfc, 0x42, 0x57, 0x59, 0x39, 0x2e, 0x6d,
+      0x39, 0x97, 0xdb, 0x5b, 0x5c, 0xb9, 0x59, 0x71, 0x42, 0xf3, 0xcd, 0xea, 0xda, 0x86, 0x54, 0x86,
+      0x61, 0x8d, 0x93, 0x66, 0xc7, 0x65, 0xd1, 0x98, 0xcb, 0x02, 0x01, 0x02
+   };
+   /* text dump: openssl dh -inform DER -in dhparam.der -text
+      DH Parameters: (2048 bit)
+          prime:
+              00:ae:fe:78:ce:80:d5:d7:8e:cc:4f:0c:1b:b0:95:
+              10:e1:41:15:53:4d:0e:68:b0:f8:5a:41:0e:65:2f:
+              9f:ac:9c:30:b0:76:ec:02:e9:43:55:08:b4:20:60:
+              d9:52:da:2d:ab:9a:ba:e6:cf:11:a7:00:44:c2:5e:
+              d1:ba:9b:aa:fe:03:dd:dc:ef:41:89:9c:ac:64:13:
+              d9:6a:8a:55:a0:5b:ff:12:92:37:52:6a:91:a4:6e:
+              9e:61:b7:fe:b0:17:8e:67:0f:88:46:a7:9e:b1:db:
+              68:77:70:b5:77:f2:7e:33:b1:3e:10:c4:63:36:d0:
+              13:27:d3:29:c3:b6:5d:f6:5d:a7:d8:25:5c:0b:65:
+              99:fa:f9:5f:1d:ee:d1:86:64:7c:44:cb:a0:12:52:
+              4c:d4:46:81:ae:07:db:c7:13:29:ce:9b:cf:1c:06:
+              d2:0f:2d:bb:12:33:b9:b1:0f:67:5d:3f:0c:e4:fa:
+              67:26:e2:89:a2:d5:66:29:1c:e2:8e:bb:7b:cb:cc:
+              70:7e:4f:0e:d3:5d:64:64:1b:27:bb:da:a9:08:2b:
+              62:d4:ca:c3:3a:23:39:58:57:af:7b:8b:0c:5b:2e:
+              fc:42:57:59:39:2e:6d:39:97:db:5b:5c:b9:59:71:
+              42:f3:cd:ea:da:86:54:86:61:8d:93:66:c7:65:d1:
+              98:cb
+          generator: 2 (0x2)
+   */
+   unsigned char prime[] = {
+            0xae, 0xfe, 0x78, 0xce, 0x80, 0xd5, 0xd7, 0x8e, 0xcc, 0x4f, 0x0c, 0x1b, 0xb0, 0x95,
+      0x10, 0xe1, 0x41, 0x15, 0x53, 0x4d, 0x0e, 0x68, 0xb0, 0xf8, 0x5a, 0x41, 0x0e, 0x65, 0x2f,
+      0x9f, 0xac, 0x9c, 0x30, 0xb0, 0x76, 0xec, 0x02, 0xe9, 0x43, 0x55, 0x08, 0xb4, 0x20, 0x60,
+      0xd9, 0x52, 0xda, 0x2d, 0xab, 0x9a, 0xba, 0xe6, 0xcf, 0x11, 0xa7, 0x00, 0x44, 0xc2, 0x5e,
+      0xd1, 0xba, 0x9b, 0xaa, 0xfe, 0x03, 0xdd, 0xdc, 0xef, 0x41, 0x89, 0x9c, 0xac, 0x64, 0x13,
+      0xd9, 0x6a, 0x8a, 0x55, 0xa0, 0x5b, 0xff, 0x12, 0x92, 0x37, 0x52, 0x6a, 0x91, 0xa4, 0x6e,
+      0x9e, 0x61, 0xb7, 0xfe, 0xb0, 0x17, 0x8e, 0x67, 0x0f, 0x88, 0x46, 0xa7, 0x9e, 0xb1, 0xdb,
+      0x68, 0x77, 0x70, 0xb5, 0x77, 0xf2, 0x7e, 0x33, 0xb1, 0x3e, 0x10, 0xc4, 0x63, 0x36, 0xd0,
+      0x13, 0x27, 0xd3, 0x29, 0xc3, 0xb6, 0x5d, 0xf6, 0x5d, 0xa7, 0xd8, 0x25, 0x5c, 0x0b, 0x65,
+      0x99, 0xfa, 0xf9, 0x5f, 0x1d, 0xee, 0xd1, 0x86, 0x64, 0x7c, 0x44, 0xcb, 0xa0, 0x12, 0x52,
+      0x4c, 0xd4, 0x46, 0x81, 0xae, 0x07, 0xdb, 0xc7, 0x13, 0x29, 0xce, 0x9b, 0xcf, 0x1c, 0x06,
+      0xd2, 0x0f, 0x2d, 0xbb, 0x12, 0x33, 0xb9, 0xb1, 0x0f, 0x67, 0x5d, 0x3f, 0x0c, 0xe4, 0xfa,
+      0x67, 0x26, 0xe2, 0x89, 0xa2, 0xd5, 0x66, 0x29, 0x1c, 0xe2, 0x8e, 0xbb, 0x7b, 0xcb, 0xcc,
+      0x70, 0x7e, 0x4f, 0x0e, 0xd3, 0x5d, 0x64, 0x64, 0x1b, 0x27, 0xbb, 0xda, 0xa9, 0x08, 0x2b,
+      0x62, 0xd4, 0xca, 0xc3, 0x3a, 0x23, 0x39, 0x58, 0x57, 0xaf, 0x7b, 0x8b, 0x0c, 0x5b, 0x2e,
+      0xfc, 0x42, 0x57, 0x59, 0x39, 0x2e, 0x6d, 0x39, 0x97, 0xdb, 0x5b, 0x5c, 0xb9, 0x59, 0x71,
+      0x42, 0xf3, 0xcd, 0xea, 0xda, 0x86, 0x54, 0x86, 0x61, 0x8d, 0x93, 0x66, 0xc7, 0x65, 0xd1,
+      0x98, 0xcb
+   };
+
+   DO(dh_make_key_dhparam(&yarrow_prng, find_prng ("yarrow"), dhparam_der, sizeof(dhparam_der), &k));
+   if (mp_unsigned_bin_size(k.prime) > sizeof(buf)) {
+      printf("dhparam_test: short buf\n");
+      dh_free(&k);
+      return CRYPT_ERROR;
+   }
+   DO(mp_to_unsigned_bin(k.prime, buf));
+   if (compare_testvector(buf, sizeof(prime), prime, sizeof(prime), "dhparam_test", 1)) {
+      printf("dhparam_test: prime mismatch\n");
+      dh_free(&k);
+      return CRYPT_ERROR;
+   }
+   if (mp_cmp_d(k.base, 2) != LTC_MP_EQ) {
+      printf("dhparam_test: base mismatch\n");
+      dh_free(&k);
+      return CRYPT_ERROR;
+   }
+   dh_free(&k);
+   return CRYPT_OK;
+}
+
+static int _basic_test(void)
+{
+   unsigned char buf[3][4096];
+   unsigned long x, y, z;
+   int           size;
+   dh_key        usera, userb;
 
    if (register_prng(&yarrow_desc) == -1) {
       printf("Error registering yarrow PRNG\n");
-      exit(-1);
+      return CRYPT_ERROR;
    }
    if (register_hash(&md5_desc) == -1) {
       printf("Error registering md5 hash\n");
-      exit(-1);
+      return CRYPT_ERROR;
    }
 
-  DO(dh_compat_test());
-
-
-  /* make up two keys */
-  DO(dh_make_key (&yarrow_prng, find_prng ("yarrow"), KEYSIZE/8, &usera));
-  DO(dh_make_key (&yarrow_prng, find_prng ("yarrow"), KEYSIZE/8, &userb));
-
-  /* make the shared secret */
-  x = KEYSIZE;
-  DO(dh_shared_secret (&usera, &userb, buf[0], &x));
-
-  y = KEYSIZE;
-  DO(dh_shared_secret (&userb, &usera, buf[1], &y));
-  if (y != x) {
-    fprintf(stderr, "DH Shared keys are not same size.\n");
-    dh_free (&usera);
-    dh_free (&userb);
-    return 1;
-  }
-  if (memcmp (buf[0], buf[1], x)) {
-    fprintf(stderr, "DH Shared keys not same contents.\n");
-    dh_free (&usera);
-    dh_free (&userb);
-    return 1;
-  }
-
-  /* now export userb */
-  y = KEYSIZE;
-  DO(dh_export (buf[1], &y, PK_PUBLIC, &userb));
-  dh_free (&userb);
-
-  /* import and make the shared secret again */
-  DO(dh_import (buf[1], y, &userb));
-  z = KEYSIZE;
-  DO(dh_shared_secret (&usera, &userb, buf[2], &z));
-
-  dh_free (&usera);
-  dh_free (&userb);
-
-  if (z != x) {
-    fprintf(stderr, "failed.  Size don't match?\n");
-    return 1;
-  }
-  if (memcmp (buf[0], buf[2], x)) {
-    fprintf(stderr, "Failed.  Content didn't match.\n");
-    return 1;
-  }
-
-/* test encrypt_key */
-  dh_make_key (&yarrow_prng, find_prng ("yarrow"), KEYSIZE/8, &usera);
-  for (ch = 0; ch < 16; ch++) {
-    buf[0][ch] = ch;
-  }
-  y = sizeof (buf[1]);
-  DO(dh_encrypt_key (buf[0], 16, buf[1], &y, &yarrow_prng, find_prng ("yarrow"), find_hash ("md5"), &usera));
-  zeromem (buf[0], sizeof (buf[0]));
-  x = sizeof (buf[0]);
-  DO(dh_decrypt_key (buf[1], y, buf[0], &x, &usera));
-  if (x != 16) {
-    fprintf(stderr, "Failed (length)\n");
-    dh_free (&usera);
-    return 1;
-  }
-  for (ch = 0; ch < 16; ch++)
-    if (buf[0][ch] != ch) {
-      fprintf(stderr, "Failed (contents)\n");
+   /* make up two keys */
+   DO(dh_make_key (&yarrow_prng, find_prng ("yarrow"), KEYSIZE/8, &usera));
+   DO(dh_make_key (&yarrow_prng, find_prng ("yarrow"), KEYSIZE/8, &userb));
+
+   /* make the shared secret */
+   x = KEYSIZE;
+   DO(dh_shared_secret (&usera, &userb, buf[0], &x));
+
+   y = KEYSIZE;
+   DO(dh_shared_secret (&userb, &usera, buf[1], &y));
+   if (y != x) {
+      fprintf(stderr, "DH Shared keys are not same size.\n");
       dh_free (&usera);
-      return 1;
-    }
-
-/* test sign_hash */
-  for (ch = 0; ch < 16; ch++) {
-     buf[0][ch] = ch;
-  }
-  x = sizeof (buf[1]);
-  DO(dh_sign_hash (buf[0], 16, buf[1], &x, &yarrow_prng, find_prng ("yarrow"), &usera));
-  DO(dh_verify_hash (buf[1], x, buf[0], 16, &stat, &usera));
-  buf[0][0] ^= 1;
-  DO(dh_verify_hash (buf[1], x, buf[0], 16, &stat2, &usera));
-  dh_free (&usera);
-  if (!(stat == 1 && stat2 == 0)) {
-     fprintf(stderr, "dh_sign/verify_hash %d %d", stat, stat2);
-     return 1;
-  }
-  return 0;
+      dh_free (&userb);
+      return CRYPT_ERROR;
+   }
+   if (memcmp (buf[0], buf[1], x)) {
+      fprintf(stderr, "DH Shared keys not same contents.\n");
+      dh_free (&usera);
+      dh_free (&userb);
+      return CRYPT_ERROR;
+   }
+
+   /* now export userb */
+   y = KEYSIZE;
+   DO(dh_export (buf[1], &y, PK_PUBLIC, &userb));
+   dh_free (&userb);
+
+   /* import and make the shared secret again */
+   DO(dh_import (buf[1], y, &userb));
+   z = KEYSIZE;
+   DO(dh_shared_secret (&usera, &userb, buf[2], &z));
+
+   dh_free (&usera);
+   dh_free (&userb);
+
+   if (z != x) {
+      fprintf(stderr, "failed.  Size don't match?\n");
+      return CRYPT_ERROR;
+   }
+   if (memcmp (buf[0], buf[2], x)) {
+      fprintf(stderr, "Failed.  Content didn't match.\n");
+      return CRYPT_ERROR;
+   }
+
+   for (x = 0; ltc_dh_sets[x].size != 0; x++) {
+      DO(dh_make_key(&yarrow_prng, find_prng ("yarrow"), ltc_dh_sets[x].size, &usera));
+      size = dh_get_groupsize(&usera);
+      dh_free(&usera);
+      if (size != ltc_dh_sets[x].size) {
+         fprintf(stderr, "dh_groupsize mismatch %d %d\n", size, ltc_dh_sets[x].size);
+         return CRYPT_ERROR;
+      }
+   }
+
+   return CRYPT_OK;
 }
+
+int dh_test(void)
+{
+   int fails = 0;
+   if (_prime_test() != CRYPT_OK) fails++;
+   if (_basic_test() != CRYPT_OK) fails++;
+   if (_dhparam_test() != CRYPT_OK) fails++;
+   return fails > 0 ? CRYPT_FAIL_TESTVECTOR : CRYPT_OK;
+}
+
 #else
 
 int dh_test(void)