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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user