rejoined diffie hellman code from ltc 1.05, thanks to Alexander Kurpiers
This commit is contained in:
parent
5039e6520f
commit
6fecec107d
224
crypt.tex
224
crypt.tex
@ -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}
|
||||
|
@ -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);
|
||||
|
1
makefile
1
makefile
@ -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 \
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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
606
src/pk/dh/dh.c
Normal 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
491
src/pk/dh/dh_sys.c
Normal 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
122
testprof/dh_test.c
Normal 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
|
@ -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
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user