rejoined diffie hellman code from ltc 1.05, thanks to Alexander Kurpiers

This commit is contained in:
Steffen Jaeckel 2011-01-18 20:06:03 +01:00
parent 5039e6520f
commit 6fecec107d
14 changed files with 1594 additions and 1 deletions

224
crypt.tex
View File

@ -3675,6 +3675,230 @@ As of v1.06 this function can also import OpenSSL DER formatted public RSA keys.
import the key, strip off the additional data (it's the preferred hash) and fill in the rsa\_key structure as if it were a native RSAPublicKey. Note that
there is no function provided to export in this format.
\chapter{Diffie-Hellman Key Exchange}
\section{Background}
Diffie-Hellman was the original public key system proposed. The system is based upon the group structure
of finite fields. For Diffie-Hellman a prime $p$ is chosen and a ``base'' $b$ such that $b^x\mbox{ }(\mbox{mod }p)$
generates a large sub-group of prime order (for unique values of $x$).
A secret key is an exponent $x$ and a public key is the value of $y \equiv g^x\mbox{ }(\mbox{mod }p)$. The term
``discrete logarithm'' denotes the action of finding $x$ given only $y$, $g$ and $p$. The key exchange part of
Diffie-Hellman arises from the fact that two users A and B with keys $(A_x, A_y)$ and $(B_x, B_y)$ can exchange
a shared key $K \equiv B_y^{A_x} \equiv A_y^{B_x} \equiv g^{A_xB_x}\mbox{ }(\mbox{mod }p)$.
From this public encryption and signatures can be developed. The trivial way to encrypt (for example) using a public key
$y$ is to perform the key exchange offline. The sender invents a key $k$ and its public copy
$k' \equiv g^k\mbox{ }(\mbox{mod }p)$ and uses $K \equiv k'^{A_x}\mbox{ }(\mbox{mod }p)$ as a key to encrypt
the message with. Typically $K$ would be sent to a one-way hash and the message digested used as a key in a
symmetric cipher.
It is important that the order of the sub-group that $g$ generates not only be large but also prime. There are
discrete logarithm algorithms that take $\sqrt r$ time given the order $r$. The discrete logarithm can be computed
modulo each prime factor of $r$ and the results combined using the Chinese Remainder Theorem. In the cases where
$r$ is ``B-Smooth'' (e.g. all small factors or powers of small prime factors) the solution is trivial to find.
To thwart such attacks the primes and bases in the library have been designed and fixed. Given a prime $p$ the order of
the sub-group generated is a large prime namely ${p - 1} \over 2$. Such primes are known as ``strong primes'' and the
smaller prime (e.g. the order of the base) are known as Sophie-Germaine primes.
\section{Core Functions}
This library also provides core Diffie-Hellman functions so you can negotiate keys over insecure mediums. The routines
provided are relatively easy to use and only take two function calls to negotiate a shared key. There is a structure
called ``dh\_key'' which stores the Diffie-Hellman key in a format these routines can use. The first routine is to
make a Diffie-Hellman private key pair:
\index{dh\_make\_key()}
\begin{verbatim}
int dh_make_key(prng_state *prng, int wprng,
int keysize, dh_key *key);
\end{verbatim}
The ``keysize'' is the size of the modulus you want in bytes. Currently support sizes are 96 to 512 bytes which correspond
to key sizes of 768 to 4096 bits. The smaller the key the faster it is to use however it will be less secure. When
specifying a size not explicitly supported by the library it will round {\em up} to the next key size. If the size is
above 512 it will return an error. So if you pass ``keysize == 32'' it will use a 768 bit key but if you pass
``keysize == 20000'' it will return an error. The primes and generators used are built-into the library and were designed
to meet very specific goals. The primes are strong primes which means that if $p$ is the prime then
$p-1$ is equal to $2r$ where $r$ is a large prime. The bases are chosen to generate a group of order $r$ to prevent
leaking a bit of the key. This means the bases generate a very large prime order group which is good to make cryptanalysis
hard.
The next two routines are for exporting/importing Diffie-Hellman keys in a binary format. This is useful for transport
over communication mediums.
\index{dh\_export()} \index{dh\_import()}
\begin{verbatim}
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);
\end{verbatim}
These two functions work just like the ``rsa\_export()'' and ``rsa\_import()'' functions except these work with
Diffie-Hellman keys. Its important to note you do not have to free the ram for a ``dh\_key'' if an import fails. You can free a
``dh\_key'' using:
\begin{verbatim}
void dh_free(dh_key *key);
\end{verbatim}
After you have exported a copy of your public key (using {\bf PK\_PUBLIC} as ``type'') you can now create a shared secret
with the other user using:
\index{dh\_shared\_secret()}
\begin{verbatim}
int dh_shared_secret(dh_key *private_key,
dh_key *public_key,
unsigned char *out, unsigned long *outlen);
\end{verbatim}
Where ``private\_key'' is the key you made and ``public\_key'' is the copy of the public key the other user sent you. The result goes
into ``out'' and the length into ``outlen''. If all went correctly the data in ``out'' should be identical for both parties. It is important to
note that the two keys have to be the same size in order for this to work. There is a function to get the size of a
key:
\index{dh\_get\_size()}
\begin{verbatim}
int dh_get_size(dh_key *key);
\end{verbatim}
This returns the size in bytes of the modulus chosen for that key.
\subsection{Remarks on Usage}
Its important that you hash the shared key before trying to use it as a key for a symmetric cipher or something. An
example program that communicates over sockets, using MD5 and 1024-bit DH keys is\footnote{This function is a small example. It is suggested that proper packaging be used. For example, if the public key sent is truncated these routines will not detect that.}:
\newpage
\begin{small}
\begin{verbatim}
int establish_secure_socket(int sock, int mode, unsigned char *key,
prng_state *prng, int wprng)
{
unsigned char buf[4096], buf2[4096];
unsigned long x, len;
int res, err, inlen;
dh_key mykey, theirkey;
/* make up our private key */
if ((err = dh_make_key(prng, wprng, 128, &mykey)) != CRYPT_OK) {
return err;
}
/* export our key as public */
x = sizeof(buf);
if ((err = dh_export(buf, &x, PK_PUBLIC, &mykey)) != CRYPT_OK) {
res = err;
goto done2;
}
if (mode == 0) {
/* mode 0 so we send first */
if (send(sock, buf, x, 0) != x) {
res = CRYPT_ERROR;
goto done2;
}
/* get their key */
if ((inlen = recv(sock, buf2, sizeof(buf2), 0)) <= 0) {
res = CRYPT_ERROR;
goto done2;
}
} else {
/* mode >0 so we send second */
if ((inlen = recv(sock, buf2, sizeof(buf2), 0)) <= 0) {
res = CRYPT_ERROR;
goto done2;
}
if (send(sock, buf, x, 0) != x) {
res = CRYPT_ERROR;
goto done2;
}
}
if ((err = dh_import(buf2, inlen, &theirkey)) != CRYPT_OK) {
res = err;
goto done2;
}
/* make shared secret */
x = sizeof(buf);
if ((err = dh_shared_secret(&mykey, &theirkey, buf, &x)) != CRYPT_OK) {
res = err;
goto done;
}
/* hash it */
len = 16; /* default is MD5 so "key" must be at least 16 bytes long */
if ((err = hash_memory(find_hash("md5"), buf, x, key, &len)) != CRYPT_OK) {
res = err;
goto done;
}
/* clean up and return */
res = CRYPT_OK;
done:
dh_free(&theirkey);
done2:
dh_free(&mykey);
zeromem(buf, sizeof(buf));
zeromem(buf2, sizeof(buf2));
return res;
}
\end{verbatim}
\end{small}
\newpage
\subsection{Remarks on The Snippet}
When the above code snippet is done (assuming all went well) their will be a shared 128-bit key in the ``key'' array
passed to ``establish\_secure\_socket()''.
\section{Other Diffie-Hellman Functions}
In order to test the Diffie-Hellman function internal workings (e.g. the primes and bases) their is a test function made
available:
\index{dh\_test()}
\begin{verbatim}
int dh_test(void);
\end{verbatim}
This function returns {\bf CRYPT\_OK} if the bases and primes in the library are correct. There is one last helper
function:
\index{dh\_sizes()}
\begin{verbatim}
void dh_sizes(int *low, int *high);
\end{verbatim}
Which stores the smallest and largest key sizes support into the two variables.
\section{DH Packet}
Similar to the RSA related functions there are functions to encrypt or decrypt symmetric keys using the DH public key
algorithms.
\index{dh\_encrypt\_key()} \index{dh\_decrypt\_key()}
\begin{verbatim}
int dh_encrypt_key(const unsigned char *in, unsigned long inlen,
unsigned char *out, unsigned long *len,
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);
\end{verbatim}
Where ``in'' is an input symmetric key of no more than 32 bytes. Essentially these routines created a random public key
and find the hash of the shared secret. The message digest is than XOR'ed against the symmetric key. All of the
required data is placed in ``out'' by ``dh\_encrypt\_key()''. The hash must produce a message digest at least as large
as the symmetric key you are trying to share.
Similar to the RSA system you can sign and verify a hash of a message.
\index{dh\_sign\_hash()} \index{dh\_verify\_hash()}
\begin{verbatim}
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);
\end{verbatim}
The ``dh\_sign\_hash'' function signs the message hash in ``in'' of length ``inlen'' and forms a DH packet in ``out''.
The ``dh\_verify\_hash'' function verifies the DH signature in ``sig'' against the hash in ``hash''. It sets ``stat''
to non-zero if the signature passes or zero if it fails.
\chapter{Elliptic Curve Cryptography}
\mysection{Background}

View File

@ -24,6 +24,7 @@ int main(void)
printf("\nmac_test......"); fflush(stdout); x = mac_test(); printf(x ? "failed" : "passed");if (x) exit(EXIT_FAILURE);
printf("\npkcs_1_test..."); fflush(stdout); x = pkcs_1_test(); printf(x ? "failed" : "passed");if (x) exit(EXIT_FAILURE);
printf("\nrsa_test......"); fflush(stdout); x = rsa_test(); printf(x ? "failed" : "passed");if (x) exit(EXIT_FAILURE);
printf("\ndh_test......."); fflush(stdout); x = dh_test(); printf(x ? "failed" : "passed");if (x) exit(EXIT_FAILURE);
printf("\necc_test......"); fflush(stdout); x = ecc_tests(); printf(x ? "failed" : "passed");if (x) exit(EXIT_FAILURE);
printf("\ndsa_test......"); fflush(stdout); x = dsa_test(); printf(x ? "failed" : "passed");if (x) exit(EXIT_FAILURE);
printf("\nkatja_test...."); fflush(stdout); x = katja_test(); printf(x ? "failed" : "passed");if (x) exit(EXIT_FAILURE);

View File

@ -208,6 +208,7 @@ src/pk/ecc/ecc_sign_hash.o src/pk/ecc/ecc_sizes.o src/pk/ecc/ecc_test.o src/pk/e
src/pk/ecc/ltc_ecc_is_valid_idx.o src/pk/ecc/ltc_ecc_map.o src/pk/ecc/ltc_ecc_mul2add.o \
src/pk/ecc/ltc_ecc_mulmod.o src/pk/ecc/ltc_ecc_mulmod_timing.o src/pk/ecc/ltc_ecc_points.o \
src/pk/ecc/ltc_ecc_projective_add_point.o src/pk/ecc/ltc_ecc_projective_dbl_point.o \
src/pk/dh/dh.o \
src/pk/katja/katja_decrypt_key.o src/pk/katja/katja_encrypt_key.o src/pk/katja/katja_export.o \
src/pk/katja/katja_exptmod.o src/pk/katja/katja_free.o src/pk/katja/katja_import.o \
src/pk/katja/katja_make_key.o src/pk/pkcs1/pkcs_1_i2osp.o src/pk/pkcs1/pkcs_1_mgf1.o \

View File

@ -302,6 +302,26 @@
/* Include RSA support */
#define LTC_MRSA
/* Include Diffie-Hellman support */
#ifndef GPM_DESC
/* is_prime fails for GPM */
#define MDH
/* Supported Key Sizes */
#define DH768
#define DH1024
#define DH1280
#define DH1536
#define DH1792
#define DH2048
#ifndef TFM_DESC
/* tfm has a problem in fp_isprime for larger key sizes */
#define DH2560
#define DH3072
#define DH4096
#endif
#endif
/* Include Katja (a Rabin variant like RSA) */
/* #define MKAT */

View File

@ -258,6 +258,24 @@ typedef struct {
*/
int (*lcm)(void *a, void *b, void *c);
/** Modular addition
@param a The first source
@param b The second source
@param c The modulus
@param d The destination (a + b mod c)
@return CRYPT_OK on success
*/
int (*addmod)(void *a, void *b, void *c, void *d);
/** Modular substraction
@param a The first source
@param b The second source
@param c The modulus
@param d The destination (a - b mod c)
@return CRYPT_OK on success
*/
int (*submod)(void *a, void *b, void *c, void *d);
/** Modular multiplication
@param a The first source
@param b The second source
@ -475,6 +493,8 @@ extern const ltc_math_descriptor gmp_desc;
#define mp_gcd(a, b, c) ltc_mp.gcd(a, b, c)
#define mp_lcm(a, b, c) ltc_mp.lcm(a, b, c)
#define mp_addmod(a, b, c, d) ltc_mp.addmod(a, b, c, d)
#define mp_submod(a, b, c, d) ltc_mp.submod(a, b, c, d)
#define mp_mulmod(a, b, c, d) ltc_mp.mulmod(a, b, c, d)
#define mp_sqrmod(a, b, c) ltc_mp.sqrmod(a, b, c)
#define mp_invmod(a, b, c) ltc_mp.invmod(a, b, c)

View File

@ -143,6 +143,49 @@ int katja_import(const unsigned char *in, unsigned long inlen, katja_key *key);
#endif
/* ---- DH Routines ---- */
#ifdef MDH
typedef struct Dh_key {
int idx, type;
void *x;
void *y;
} dh_key;
int dh_compat_test(void);
void dh_sizes(int *low, int *high);
int dh_get_size(dh_key *key);
int dh_make_key(prng_state *prng, int wprng, int keysize, 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_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);
#endif
/* ---- ECC Routines ---- */
#ifdef LTC_MECC

View File

@ -305,6 +305,28 @@ static int lcm(void *a, void *b, void *c)
return CRYPT_OK;
}
static int addmod(void *a, void *b, void *c, void *d)
{
LTC_ARGCHK(a != NULL);
LTC_ARGCHK(b != NULL);
LTC_ARGCHK(c != NULL);
LTC_ARGCHK(d != NULL);
mpz_add(d, a, b);
mpz_mod(d, d, c);
return CRYPT_OK;
}
static int submod(void *a, void *b, void *c, void *d)
{
LTC_ARGCHK(a != NULL);
LTC_ARGCHK(b != NULL);
LTC_ARGCHK(c != NULL);
LTC_ARGCHK(d != NULL);
mpz_sub(d, a, b);
mpz_mod(d, d, c);
return CRYPT_OK;
}
static int mulmod(void *a, void *b, void *c, void *d)
{
LTC_ARGCHK(a != NULL);
@ -427,6 +449,8 @@ const ltc_math_descriptor gmp_desc = {
&gcd,
&lcm,
&addmod,
&submod,
&mulmod,
&sqrmod,
&invmod,

View File

@ -308,6 +308,24 @@ static int lcm(void *a, void *b, void *c)
return mpi_to_ltc_error(mp_lcm(a, b, c));
}
static int addmod(void *a, void *b, void *c, void *d)
{
LTC_ARGCHK(a != NULL);
LTC_ARGCHK(b != NULL);
LTC_ARGCHK(c != NULL);
LTC_ARGCHK(d != NULL);
return mpi_to_ltc_error(mp_addmod(a,b,c,d));
}
static int submod(void *a, void *b, void *c, void *d)
{
LTC_ARGCHK(a != NULL);
LTC_ARGCHK(b != NULL);
LTC_ARGCHK(c != NULL);
LTC_ARGCHK(d != NULL);
return mpi_to_ltc_error(mp_submod(a,b,c,d));
}
static int mulmod(void *a, void *b, void *c, void *d)
{
LTC_ARGCHK(a != NULL);
@ -433,6 +451,8 @@ const ltc_math_descriptor ltm_desc = {
&gcd,
&lcm,
&addmod,
&submod,
&mulmod,
&sqrmod,
&invmod,

View File

@ -319,6 +319,24 @@ static int lcm(void *a, void *b, void *c)
return CRYPT_OK;
}
static int addmod(void *a, void *b, void *c, void *d)
{
LTC_ARGCHK(a != NULL);
LTC_ARGCHK(b != NULL);
LTC_ARGCHK(c != NULL);
LTC_ARGCHK(d != NULL);
return tfm_to_ltc_error(fp_addmod(a,b,c,d));
}
static int submod(void *a, void *b, void *c, void *d)
{
LTC_ARGCHK(a != NULL);
LTC_ARGCHK(b != NULL);
LTC_ARGCHK(c != NULL);
LTC_ARGCHK(d != NULL);
return tfm_to_ltc_error(fp_submod(a,b,c,d));
}
static int mulmod(void *a, void *b, void *c, void *d)
{
LTC_ARGCHK(a != NULL);
@ -721,6 +739,8 @@ const ltc_math_descriptor tfm_desc = {
&gcd,
&lcm,
&addmod,
&submod,
&mulmod,
&sqrmod,
&invmod,

606
src/pk/dh/dh.c Normal file
View File

@ -0,0 +1,606 @@
/* 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.c
DH crypto, Tom St Denis
*/
#ifdef 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 void packet_store_header(unsigned char *dst, int section, int subsection)
{
LTC_ARGCHK(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 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;
}
/* max export size we'll encounter (smaller than this but lets round up a bit) */
#define DH_BUF_SIZE 1200
/* This holds the key settings. ***MUST*** be organized by size from smallest to largest. */
static const struct {
int size;
char *name, *base, *prime;
} sets[] = {
#ifdef DH768
{
96,
"DH-768",
"4",
"F///////////////////////////////////////////////////////////"
"////////////////////////////////////////////////////////////"
"//////m3wvV"
},
#endif
#ifdef DH1024
{
128,
"DH-1024",
"4",
"F///////////////////////////////////////////////////////////"
"////////////////////////////////////////////////////////////"
"////////////////////////////////////////////////m3C47"
},
#endif
#ifdef DH1280
{
160,
"DH-1280",
"4",
"F///////////////////////////////////////////////////////////"
"////////////////////////////////////////////////////////////"
"////////////////////////////////////////////////////////////"
"//////////////////////////////m4kSN"
},
#endif
#ifdef DH1536
{
192,
"DH-1536",
"4",
"F///////////////////////////////////////////////////////////"
"////////////////////////////////////////////////////////////"
"////////////////////////////////////////////////////////////"
"////////////////////////////////////////////////////////////"
"////////////m5uqd"
},
#endif
#ifdef DH1792
{
224,
"DH-1792",
"4",
"F///////////////////////////////////////////////////////////"
"////////////////////////////////////////////////////////////"
"////////////////////////////////////////////////////////////"
"////////////////////////////////////////////////////////////"
"//////////////////////////////////////////////////////mT/sd"
},
#endif
#ifdef DH2048
{
256,
"DH-2048",
"4",
"3///////////////////////////////////////////////////////////"
"////////////////////////////////////////////////////////////"
"////////////////////////////////////////////////////////////"
"////////////////////////////////////////////////////////////"
"////////////////////////////////////////////////////////////"
"/////////////////////////////////////////m8MPh"
},
#endif
#ifdef DH2560
{
320,
"DH-2560",
"4",
"3///////////////////////////////////////////////////////////"
"////////////////////////////////////////////////////////////"
"////////////////////////////////////////////////////////////"
"////////////////////////////////////////////////////////////"
"////////////////////////////////////////////////////////////"
"////////////////////////////////////////////////////////////"
"////////////////////////////////////////////////////////////"
"/////mKFpF"
},
#endif
#ifdef DH3072
{
384,
"DH-3072",
"4",
"3///////////////////////////////////////////////////////////"
"////////////////////////////////////////////////////////////"
"////////////////////////////////////////////////////////////"
"////////////////////////////////////////////////////////////"
"////////////////////////////////////////////////////////////"
"////////////////////////////////////////////////////////////"
"////////////////////////////////////////////////////////////"
"////////////////////////////////////////////////////////////"
"/////////////////////////////m32nN"
},
#endif
#ifdef DH4096
{
512,
"DH-4096",
"4",
"////////////////////////////////////////////////////////////"
"////////////////////////////////////////////////////////////"
"////////////////////////////////////////////////////////////"
"////////////////////////////////////////////////////////////"
"////////////////////////////////////////////////////////////"
"////////////////////////////////////////////////////////////"
"////////////////////////////////////////////////////////////"
"////////////////////////////////////////////////////////////"
"////////////////////////////////////////////////////////////"
"////////////////////////////////////////////////////////////"
"////////////////////////////////////////////////////////////"
"/////////////////////m8pOF"
},
#endif
{
0,
NULL,
NULL,
NULL
}
};
static int is_valid_idx(int n)
{
int x;
for (x = 0; sets[x].size; x++);
if ((n < 0) || (n >= x)) {
return 0;
}
return 1;
}
/**
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);
#endif
if ((err = mp_read_radix(g,(char *)sets[x].base, 64)) != CRYPT_OK) { goto error; }
if ((err = mp_read_radix(p,(char *)sets[x].prime, 64)) != 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_ARGCHK(low != NULL);
LTC_ARGCHK(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;
}
}
/**
Returns the key size of a given DH key (octets)
@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 (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 keysize The key size (octets) desired
@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 keysize, dh_key *key)
{
unsigned char *buf;
unsigned long x;
void *p, *g;
int err;
LTC_ARGCHK(key != NULL);
/* good prng? */
if ((err = prng_is_valid(wprng)) != CRYPT_OK) {
return err;
}
/* find key size */
for (x = 0; (keysize > sets[x].size) && (sets[x].size != 0); x++);
#ifdef FAST_PK
keysize = MIN(sets[x].size, 32);
#else
keysize = sets[x].size;
#endif
if (sets[x].size == 0) {
return CRYPT_INVALID_KEYSIZE;
}
key->idx = x;
/* allocate buffer */
buf = XMALLOC(keysize);
if (buf == NULL) {
return CRYPT_MEM;
}
/* make up random string */
if ( rng_make_prng( keysize, wprng, prng, NULL) != CRYPT_OK) {
err = CRYPT_ERROR_READPRNG;
goto error2;
}
if (prng_descriptor[wprng].read(buf, keysize, prng) != (unsigned long)keysize) {
err = CRYPT_ERROR_READPRNG;
goto error2;
}
/* init parameters */
if ((err = mp_init_multi(&g, &p, &key->x, &key->y, NULL)) != CRYPT_OK) {
goto error;
}
if ((err = mp_read_radix(g, sets[key->idx].base, 64)) != CRYPT_OK) { goto error; }
if ((err = mp_read_radix(p, sets[key->idx].prime, 64)) != CRYPT_OK) { goto error; }
/* load the x value */
if ((err = mp_read_unsigned_bin(key->x, buf, keysize)) != CRYPT_OK) { goto error; }
if ((err = mp_exptmod(g, key->x, p, key->y)) != CRYPT_OK) { goto error; }
key->type = PK_PRIVATE;
/* free up ram */
err = CRYPT_OK;
goto done;
error:
mp_clear_multi(key->x, key->y, NULL);
done:
mp_clear_multi(p, g, NULL);
error2:
#ifdef LTC_CLEAN_STACK
zeromem(buf, keysize);
#endif
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_ARGCHK(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 (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;
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, NULL)) != CRYPT_OK) {
return err;
}
if ((err = mp_read_radix(p, (char *)sets[private_key->idx].prime, 64)) != CRYPT_OK) { 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 done;
}
if ((err = mp_to_unsigned_bin(tmp, out)) != CRYPT_OK) { goto error; }
*outlen = x;
err = CRYPT_OK;
goto done;
error:
done:
mp_clear_multi(p, tmp, NULL);
return err;
}
#include "dh_sys.c"
#endif

491
src/pk/dh/dh_sys.c Normal file
View File

@ -0,0 +1,491 @@
/* 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
*/
/**
@file dh_sys.c
DH Crypto, Tom St Denis
*/
/**
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, hashsize, 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;
}
/* make random key */
hashsize = hash_descriptor[hash].hashsize;
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, hashsize, 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;
}
/* common values */
hashsize = hash_descriptor[hash].hashsize;
/* 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;
} else {
inlen -= keysize;
}
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 (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;
}
/* 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 error; }
if ((err = mp_read_unsigned_bin(k, buf, sets[key->idx].size)) != CRYPT_OK) { goto error; }
/* load g, p and p1 */
if ((err = mp_read_radix(g, sets[key->idx].base, 64)) != CRYPT_OK) { goto error; }
if ((err = mp_read_radix(p, sets[key->idx].prime, 64)) != CRYPT_OK) { goto error; }
if ((err = mp_sub_d(p, 1, p1)) != CRYPT_OK) { goto error; }
if ((err = mp_div_2(p1, p1)) != CRYPT_OK) { goto error; } /* p1 = (p-1)/2 */
/* now get a = g^k mod p */
if ((err = mp_exptmod(g, k, p, a)) != CRYPT_OK) { goto error; }
/* 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 error; } /* k = 1/k mod p1 */
if ((err = mp_mulmod(a, key->x, p1, tmp)) != CRYPT_OK) { goto error; } /* tmp = xa */
if ((err = mp_submod(m, tmp, p1, tmp)) != CRYPT_OK) { goto error; } /* tmp = M - xa */
if ((err = mp_mulmod(k, tmp, p1, b)) != CRYPT_OK) { goto error; } /* 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 error; }
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 error; }
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;
goto LBL_ERR;
error:
LBL_ERR:
mp_clear_multi(tmp, p1, g, p, m, k, b, a, NULL);
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, 64)) != CRYPT_OK) { goto error1; }
if ((err = mp_read_radix(g, sets[key->idx].base, 64)) != 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;
}

122
testprof/dh_test.c Normal file
View File

@ -0,0 +1,122 @@
#include <tomcrypt_test.h>
#ifdef MDH
#ifdef DH4096
#define KEYSIZE 4096
#else
#define KEYSIZE 2048
#endif
int dh_test (void)
{
unsigned char buf[3][4096];
unsigned long x, y, z;
int stat, stat2;
dh_key usera, userb;
prng_state yarrow_prng;
if (register_prng(&yarrow_desc) == -1) {
printf("Error registering yarrow PRNG\n");
exit(-1);
}
if (register_hash(&md5_desc) == -1) {
printf("Error registering md5 hash\n");
exit(-1);
}
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 (x = 0; x < 16; x++) {
buf[0][x] = x;
}
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 (x = 0; x < 16; x++)
if (buf[0][x] != x) {
fprintf(stderr, "Failed (contents)\n");
dh_free (&usera);
return 1;
}
/* test sign_hash */
for (x = 0; x < 16; x++) {
buf[0][x] = x;
}
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;
}
#else
int dh_test(void)
{
fprintf(stderr, "NOP");
return 0;
}
#endif

View File

@ -7,7 +7,7 @@ endif
OBJECTS = base64_test.o cipher_hash_test.o der_tests.o \
dsa_test.o ecc_test.o mac_test.o modes_test.o pkcs_1_test.o rsa_test.o \
store_test.o test_driver.o x86_prof.o katja_test.o
store_test.o test_driver.o x86_prof.o katja_test.o dh_test.o
ifndef LIBTEST_S
LIBTEST_S=libtomcrypt_prof.a

View File

@ -32,6 +32,7 @@ int mac_test(void);
int pkcs_1_test(void);
int store_test(void);
int rsa_test(void);
int dh_test(void);
int katja_test(void);
int ecc_tests(void);
int dsa_test(void);