diff --git a/demos/timing.c b/demos/timing.c index b36ba61..aa7c9a5 100644 --- a/demos/timing.c +++ b/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 diff --git a/src/headers/tomcrypt_pk.h b/src/headers/tomcrypt_pk.h index aa00be1..7dc30dc 100644 --- a/src/headers/tomcrypt_pk.h +++ b/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 diff --git a/src/pk/dh/dh.c b/src/pk/dh/dh.c index b907540..763b007 100644 --- a/src/pk/dh/dh.c +++ b/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, tomstdenis@gmail.com, 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) + @return The group size in octets (0 on error) + */ +int dh_get_groupsize(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) -{ - 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$ */ diff --git a/src/pk/dh/dh_check_pubkey.c b/src/pk/dh/dh_check_pubkey.c new file mode 100644 index 0000000..c77e4bd --- /dev/null +++ b/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$ */ diff --git a/src/pk/dh/dh_export.c b/src/pk/dh/dh_export.c new file mode 100644 index 0000000..6a02a89 --- /dev/null +++ b/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$ */ diff --git a/src/pk/dh/dh_export_radix.c b/src/pk/dh/dh_export_radix.c new file mode 100644 index 0000000..301fd7f --- /dev/null +++ b/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$ */ diff --git a/src/pk/dh/dh_free.c b/src/pk/dh/dh_free.c new file mode 100644 index 0000000..8ca1f65 --- /dev/null +++ b/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$ */ diff --git a/src/pk/dh/dh_import.c b/src/pk/dh/dh_import.c new file mode 100644 index 0000000..aa16842 --- /dev/null +++ b/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$ */ diff --git a/src/pk/dh/dh_import_radix.c b/src/pk/dh/dh_import_radix.c new file mode 100644 index 0000000..cbd6c41 --- /dev/null +++ b/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$ */ diff --git a/src/pk/dh/dh_make_key.c b/src/pk/dh/dh_make_key.c new file mode 100644 index 0000000..ddb34be --- /dev/null +++ b/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$ */ diff --git a/src/pk/dh/dh_shared_secret.c b/src/pk/dh/dh_shared_secret.c new file mode 100644 index 0000000..1eb69fb --- /dev/null +++ b/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$ */ diff --git a/src/pk/dh/dh_static.c b/src/pk/dh/dh_static.c deleted file mode 100644 index d5be03c..0000000 --- a/src/pk/dh/dh_static.c +++ /dev/null @@ -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, tomstdenis@gmail.com, 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 */ diff --git a/src/pk/dh/dh_static.h b/src/pk/dh/dh_static.h deleted file mode 100644 index 5a47ee0..0000000 --- a/src/pk/dh/dh_static.h +++ /dev/null @@ -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, tomstdenis@gmail.com, 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 */ diff --git a/src/pk/dh/dh_sys.c b/src/pk/dh/dh_sys.c deleted file mode 100644 index 8a42c96..0000000 --- a/src/pk/dh/dh_sys.c +++ /dev/null @@ -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, tomstdenis@gmail.com, 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 */ diff --git a/tests/dh_test.c b/tests/dh_test.c index efca705..3374c80 100644 --- a/tests/dh_test.c +++ b/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)); - /* 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"); + 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; - } + 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; + } -/* 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; + /* 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)