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
|
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.
|
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}
|
\chapter{Elliptic Curve Cryptography}
|
||||||
|
|
||||||
\mysection{Background}
|
\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("\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("\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("\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("\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("\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);
|
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_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_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/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_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_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 \
|
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 */
|
/* Include RSA support */
|
||||||
#define LTC_MRSA
|
#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) */
|
/* Include Katja (a Rabin variant like RSA) */
|
||||||
/* #define MKAT */
|
/* #define MKAT */
|
||||||
|
|
||||||
|
@ -258,6 +258,24 @@ typedef struct {
|
|||||||
*/
|
*/
|
||||||
int (*lcm)(void *a, void *b, void *c);
|
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
|
/** Modular multiplication
|
||||||
@param a The first source
|
@param a The first source
|
||||||
@param b The second 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_gcd(a, b, c) ltc_mp.gcd(a, b, c)
|
||||||
#define mp_lcm(a, b, c) ltc_mp.lcm(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_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_sqrmod(a, b, c) ltc_mp.sqrmod(a, b, c)
|
||||||
#define mp_invmod(a, b, c) ltc_mp.invmod(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
|
#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 ---- */
|
/* ---- ECC Routines ---- */
|
||||||
#ifdef LTC_MECC
|
#ifdef LTC_MECC
|
||||||
|
|
||||||
|
@ -305,6 +305,28 @@ static int lcm(void *a, void *b, void *c)
|
|||||||
return CRYPT_OK;
|
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)
|
static int mulmod(void *a, void *b, void *c, void *d)
|
||||||
{
|
{
|
||||||
LTC_ARGCHK(a != NULL);
|
LTC_ARGCHK(a != NULL);
|
||||||
@ -427,6 +449,8 @@ const ltc_math_descriptor gmp_desc = {
|
|||||||
&gcd,
|
&gcd,
|
||||||
&lcm,
|
&lcm,
|
||||||
|
|
||||||
|
&addmod,
|
||||||
|
&submod,
|
||||||
&mulmod,
|
&mulmod,
|
||||||
&sqrmod,
|
&sqrmod,
|
||||||
&invmod,
|
&invmod,
|
||||||
|
@ -308,6 +308,24 @@ static int lcm(void *a, void *b, void *c)
|
|||||||
return mpi_to_ltc_error(mp_lcm(a, b, 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)
|
static int mulmod(void *a, void *b, void *c, void *d)
|
||||||
{
|
{
|
||||||
LTC_ARGCHK(a != NULL);
|
LTC_ARGCHK(a != NULL);
|
||||||
@ -433,6 +451,8 @@ const ltc_math_descriptor ltm_desc = {
|
|||||||
&gcd,
|
&gcd,
|
||||||
&lcm,
|
&lcm,
|
||||||
|
|
||||||
|
&addmod,
|
||||||
|
&submod,
|
||||||
&mulmod,
|
&mulmod,
|
||||||
&sqrmod,
|
&sqrmod,
|
||||||
&invmod,
|
&invmod,
|
||||||
|
@ -319,6 +319,24 @@ static int lcm(void *a, void *b, void *c)
|
|||||||
return CRYPT_OK;
|
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)
|
static int mulmod(void *a, void *b, void *c, void *d)
|
||||||
{
|
{
|
||||||
LTC_ARGCHK(a != NULL);
|
LTC_ARGCHK(a != NULL);
|
||||||
@ -721,6 +739,8 @@ const ltc_math_descriptor tfm_desc = {
|
|||||||
&gcd,
|
&gcd,
|
||||||
&lcm,
|
&lcm,
|
||||||
|
|
||||||
|
&addmod,
|
||||||
|
&submod,
|
||||||
&mulmod,
|
&mulmod,
|
||||||
&sqrmod,
|
&sqrmod,
|
||||||
&invmod,
|
&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 \
|
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 \
|
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
|
ifndef LIBTEST_S
|
||||||
LIBTEST_S=libtomcrypt_prof.a
|
LIBTEST_S=libtomcrypt_prof.a
|
||||||
|
@ -32,6 +32,7 @@ int mac_test(void);
|
|||||||
int pkcs_1_test(void);
|
int pkcs_1_test(void);
|
||||||
int store_test(void);
|
int store_test(void);
|
||||||
int rsa_test(void);
|
int rsa_test(void);
|
||||||
|
int dh_test(void);
|
||||||
int katja_test(void);
|
int katja_test(void);
|
||||||
int ecc_tests(void);
|
int ecc_tests(void);
|
||||||
int dsa_test(void);
|
int dsa_test(void);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user