diff --git a/aes.c b/aes.c index 121a022..ad85b37 100644 --- a/aes.c +++ b/aes.c @@ -31,6 +31,18 @@ const struct _cipher_descriptor rijndael_desc = &rijndael_keysize }; +const struct _cipher_descriptor aes_desc = +{ + "aes", + 6, + 16, 32, 16, 10, + &rijndael_setup, + &rijndael_ecb_encrypt, + &rijndael_ecb_decrypt, + &rijndael_test, + &rijndael_keysize +}; + #include "aes_tab.c" #define byte(x, y) (((x)>>(8*(y)))&255) @@ -186,7 +198,7 @@ int rijndael_setup(const unsigned char *key, int keylen, int numrounds, symmetri f_rl(bo, bi, 2, k); \ f_rl(bo, bi, 3, k) -#ifdef RIJNDAEL_SMALL +#ifdef SMALL_CODE static void _fnround(unsigned long *bo, unsigned long *bi, unsigned long *k) { @@ -255,7 +267,7 @@ void rijndael_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_ i_rl(bo, bi, 2, k); \ i_rl(bo, bi, 3, k) -#ifdef RIJNDAEL_SMALL +#ifdef SMALL_CODE static void _inround(unsigned long *bo, unsigned long *bi, unsigned long *k) { diff --git a/changes b/changes index 414812b..4708da3 100644 --- a/changes +++ b/changes @@ -1,3 +1,17 @@ +Nov 28th, 2002 +v0.78 -- Made the default ARGCHK macro a function call instead which reduced the code size from 264KB to 239KB. + -- Fixed a bug in the XTEA keysize function which called ARGCHK incorrectly. + -- Added Noekeon block cipher at 2,800 bytes of object code and 345Mbit/sec it is a welcome addition. + -- Made the KR code check if the other PK systems are included [provides error when building otherwise]. + -- Made "aes" an alias for Rijndael via a pre-processor macro. Now you can use "aes_ecb_encrypt", etc... :-) + Thanks to Jean-Luc Cooke for the "buzzword conformance" suggestion. + -- Removed the old PK code entirely (e.g. rsa_sign, dh_encrypt). The *_sign_hash and *_encrypt_key functions + are all that is to remain. + -- **NOTE** Changed the PK *_import (including the keyring) routine to accept a "inlen" parameter. This fixes a + bug where improperly made key packets could result in reading passed the end of the buffer. This means + the code is no longer source compatible but still binary compatible. + -- Fixed a few other minor bugs in the PK import code while I was at it. + Nov 26th, 2002 v0.77 -- Updated the XTEA code to use pre-computed keys. With optimizations for speed it achieves 222Mbit/sec compared to the 121Mbit/sec before. It is 288 bytes bigger than before. diff --git a/crypt.c b/crypt.c index 0668b23..41d5eef 100644 --- a/crypt.c +++ b/crypt.c @@ -103,6 +103,21 @@ struct _prng_descriptor prng_descriptor[32] = { { NULL, NULL, NULL, NULL, NULL }, { NULL, NULL, NULL, NULL, NULL } }; +#if (ARGTYPE == 0) && defined(SMALL_CODE) + +void crypt_argchk(char *v, char *s, int d) +{ +#ifdef SONY_PS2 + printf("_ARGCHK '%s' failure on line %d of file %s\n", v, d, s); +#else + fprintf(stderr, "_ARGCHK '%s' failure on line %d of file %s\n", v, d, s); +#endif + raise(SIGABRT); +} + +#endif + + int find_cipher(const char *name) { int x; @@ -187,7 +202,7 @@ int register_cipher(const struct _cipher_descriptor *cipher) /* is it already registered? */ for (x = 0; x < 32; x++) { - if (!memcmp(&cipher_descriptor[x], cipher, sizeof(struct _cipher_descriptor))) { + if (cipher_descriptor[x].name != NULL && cipher_descriptor[x].ID == cipher->ID) { return x; } } @@ -214,6 +229,7 @@ int unregister_cipher(const struct _cipher_descriptor *cipher) for (x = 0; x < 32; x++) { if (!memcmp(&cipher_descriptor[x], cipher, sizeof(struct _cipher_descriptor))) { cipher_descriptor[x].name = NULL; + cipher_descriptor[x].ID = 255; return CRYPT_OK; } } diff --git a/crypt.pdf b/crypt.pdf index 161240b..fe3dc99 100644 Binary files a/crypt.pdf and b/crypt.pdf differ diff --git a/crypt.tex b/crypt.tex index 4c3b173..39f6abf 100644 --- a/crypt.tex +++ b/crypt.tex @@ -44,7 +44,7 @@ \def\gap{\vspace{0.5ex}} \makeindex \begin{document} -\title{A Tiny Crypto Library, \\ LibTomCrypt \\ Version 0.77} +\title{A Tiny Crypto Library, \\ LibTomCrypt \\ Version 0.78} \author{Tom St Denis \\ Algonquin College \\ \\ @@ -398,12 +398,6 @@ int main(void) symmetric_key skey; int errno; - /* first register Blowfish */ - if (register_cipher(&blowfish_desc) == -1) { - printf("Error registering Blowfish.\n"); - return -1; - } - /* ... key is loaded appropriately in ``key'' ... */ /* ... load a block of plaintext in ``pt'' ... */ @@ -484,11 +478,12 @@ As of this release the current cipher\_descriptors elements are \hline Safer K128 & safer\_k128\_desc & 8 & 16 & 6 .. 13 \\ \hline Safer SK128 & safer\_sk128\_desc & 8 & 16 & 6 .. 13 \\ \hline Serpent & serpent\_desc & 16 & 16 .. 32 & 32 \\ - \hline Rijndael (AES) & rijndael\_desc & 16 & 16, 24, 32 & 10, 12, 14 \\ + \hline AES & aes\_desc & 16 & 16, 24, 32 & 10, 12, 14 \\ \hline Twofish & twofish\_desc & 16 & 16, 24, 32 & 16 \\ \hline DES & des\_desc & 8 & 7 & 16 \\ \hline 3DES (EDE mode) & des3\_desc & 8 & 21 & 16 \\ \hline CAST5 (CAST-128) & cast5\_desc & 8 & 5 .. 16 & 12, 16 \\ + \hline Noekeon & noekeon\_desc & 16 & 16 & 16 \\ \hline \end{tabular} \end{center} @@ -704,7 +699,7 @@ Where ``XXX'' is one of (ecb, cbc) and ``YYY'' is one of (ctr, ofb, cfb). In th size of the buffer (as number of chars) to encrypt or decrypt. The CTR, OFB and CFB modes are order sensitive but not chunk sensitive. That is you can encrypt ``ABCDEF'' in three calls like ``AB'', ``CD'', ``EF'' or two like ``ABCDE'' and ``F'' and end up with the same ciphertext. However, encrypting ``ABC'' and ``DABC'' will result in different ciphertexts. All -four of the functions return {\bf CRYPT\_OK} on success. +five of the modes will return {\bf CRYPT\_OK} on success from the encrypt or decrypt functions. To decrypt in either mode you simply perform the setup like before (recall you have to fetch the IV value you used) and use the decrypt routine on all of the blocks. When you are done working with either mode you should wipe the @@ -1359,66 +1354,14 @@ int rsa_exptmod(const unsigned char *in, unsigned long inlen, unsigned char *out, unsigned long *outlen, int which, rsa_key *key); \end{verbatim} -This loads the bignum from ``in'' as a big endian word, raises it to either ``e'' or ``d'' and stores the result +This loads the bignum from ``in'' as a big endian word in the format PKCS specifies, raises it to either ``e'' or ``d'' and stores the result in ``out'' and the size of the result in ``outlen''. ``which'' is set to {\bf PK\_PUBLIC} to use ``e'' (i.e. for encryption/verifying) and set to {\bf PK\_PRIVATE} to use ``d'' as the exponent (i.e. for decrypting/signing). \section{Packet Routines} -The remaining RSA functions are non-standard but should (to the best of my knowledge) be secure if used correctly. To -encrypt a buffer of memory in a hybrid fashion call: -\index{rsa\_encrypt()} -\begin{verbatim} -int rsa_encrypt(const unsigned char *in, unsigned long len, - unsigned char *out, unsigned long *outlen, - prng_state *prng, int wprng, int cipher, - rsa_key *key); -\end{verbatim} -This will encrypt the message with the cipher specified by ``cipher'' under a random key made by a PRNG specified by -``wprng'' and RSA encrypt the symmetric key with ``key''. This stores all the relevant information in ``out'' and sets -the length in ``outlen''. You must ensure that ``outlen'' is set to the buffer size before calling this. - -The rsa\_encrypt() function will use up to a 256-bit symmetric key (limited by the max key length of the cipher being -used). To decrypt packets made by this routine call: -\index{rsa\_decrypt()} -\begin{verbatim} -int rsa_decrypt(const unsigned char *in, unsigned long len, - unsigned char *out, unsigned long *outlen, - rsa_key *key); -\end{verbatim} -Which works akin to rsa\_encrypt(). ``in'' is the ciphertext and ``out'' is where the plaintext will be stored. Similarly -to sign/verify there are: -\index{rsa\_sign()} \index{rsa\_verify()} -\begin{verbatim} -int rsa_sign(const unsigned char *in, unsigned long inlen, - unsigned char *out, unsigned long *outlen, - int hash, rsa_key *key); - -int rsa_verify(const unsigned char *sig, - const unsigned char *msg, - unsigned long inlen, int *stat, - rsa_key *key); -\end{verbatim} - -The verify function sets ``stat'' to 1 if it passes or to 0 if it fails. The ``sig'' parameter is the output of the -rsa\_sign() function and ``msg'' is the original msg that was signed. An important fact to note is that with -the padding scheme used in ``rsa\_sign()'' you cannot use the SHA-384 or SHA-512 hash function with 1024 bit -RSA keys. This is because the padding makes the values too large to fit in the space allowed. You can use SHA-384 -with 1160 and above bit RSA keys. You can use SHA-512 with 1544 and above bit RSA keys. - -There are related functions to sign and verify hashes. -\begin{verbatim} -int rsa_sign_hash(const unsigned char *in, unsigned long inlen, - unsigned char *out, unsigned long *outlen, - rsa_key *key); - -int rsa_verify_hash(const unsigned char *sig, const unsigned char *hash, - int *stat, rsa_key *key); -\end{verbatim} -Which works just like the two previous functions except the data is not hashed before being signed. - -There are times where you may want to encrypt a message to multiple recipients via RSA public keys. The simplest way to -accomplish this is to make up your own symmetric key and then RSA encrypt the symmetric key using all of the recipients -public keys. To facilitate this task two functions\footnote{Donated by Clay Culver.} are available: +To encrypt or decrypt a symmetric key using RSA the following functions are provided. The idea is that you make up +a random symmetric key and use that to encode your message. By RSA encrypting the symmetric key you can send it to a +recipient who can RSA decrypt it and symmetrically decrypt the message. \begin{verbatim} int rsa_encrypt_key(const unsigned char *inkey, unsigned long inlen, unsigned char *outkey, unsigned long *outlen, @@ -1434,12 +1377,27 @@ algorithm. It will store the result in ``outkey'' along with the length in ``ou performs the opposite. The ``in'' variable is where the RSA packet goes and it will store the original symmetric key in the ``outkey'' variable along with its length in ``keylen''. +Similarly to sign or verify a hash of a message the following two messages are provided. The idea is to hash your +message then use these functions to RSA sign the hash. +\begin{verbatim} +int rsa_sign_hash(const unsigned char *in, unsigned long inlen, + unsigned char *out, unsigned long *outlen, + rsa_key *key); + +int rsa_verify_hash(const unsigned char *sig, const unsigned char *hash, + int *stat, rsa_key *key); +\end{verbatim} +For ``rsa\_sign\_hash'' the input is intended to be the hash of a message the user wants to sign. The output is the +RSA signed packet which ``rsa\_verify\_hash'' can verify. For the verification function ``sig'' is the RSA signature +and ``hash'' is the hash of the message. The integer ``stat'' is set to non-zero if the signature is valid or zero +otherwise. + To import/export RSA keys as a memory buffer (e.g. to store them to disk) call: \begin{verbatim} int rsa_export(unsigned char *out, unsigned long *outlen, int type, rsa_key *key); -int rsa_import(const unsigned char *in, rsa_key *key); +int rsa_import(const unsigned char *in, unsigned long inlen, rsa_key *key); \end{verbatim} The ``type'' parameter is {\bf PK\_PUBLIC}, {\bf PK\_PRIVATE} or {\bf PK\_PRIVATE\_OPTIMIZED} to export either a public or @@ -1474,9 +1432,9 @@ The following table gives the size requirements for various hashes. \end{center} The symmetric ciphers will use at a maximum a 256-bit key which means at the least a 776-bit RSA key is -required to use all of the symmetric ciphers with the RSA routines. It is suggested that you make keys that -are at a minimum 1024 bits in length. If you want to use any of the large size message digests -(SHA-512 or SHA-384) you will have to use a larger key. +required to use all of the symmetric ciphers with the RSA routines. If you want to use any of the large size +message digests (SHA-512 or SHA-384) you will have to use a larger key. Or to be simple just make 2048-bit or larger +keys. None of the hashes will have problems with such key sizes. \chapter{Diffie-Hellman Key Exchange} @@ -1535,7 +1493,7 @@ over communication mediums. int dh_export(unsigned char *out, unsigned long *outlen, int type, dh_key *key); -int dh_import(const unsigned char *in, 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 @@ -1574,7 +1532,7 @@ int establish_secure_socket(int sock, int mode, unsigned char *key, { unsigned char buf[4096], buf2[4096]; unsigned long x, len; - int res, errno; + int res, errno, inlen; dh_key mykey, theirkey; /* make up our private key */ @@ -1597,13 +1555,13 @@ int establish_secure_socket(int sock, int mode, unsigned char *key, } /* get their key */ - if (recv(sock, buf2, sizeof(buf2), 0) <= 0) { + if ((inlen = recv(sock, buf2, sizeof(buf2), 0)) <= 0) { res = CRYPT_ERROR; goto done2; } } else { /* mode >0 so we send second */ - if (recv(sock, buf2, sizeof(buf2), 0) <= 0) { + if ((inlen = recv(sock, buf2, sizeof(buf2), 0)) <= 0) { res = CRYPT_ERROR; goto done2; } @@ -1614,7 +1572,7 @@ int establish_secure_socket(int sock, int mode, unsigned char *key, } } - if ((errno = dh_import(buf2, &theirkey)) != CRYPT_OK) { + if ((errno = dh_import(buf2, inlen, &theirkey)) != CRYPT_OK) { res = errno; goto done2; } @@ -1667,31 +1625,8 @@ void dh_sizes(int *low, int *high); Which stores the smallest and largest key sizes support into the two variables. \section{DH Packet} -There are routines to perform the work similar to that of ``rsa\_encrypt()'' and ``rsa\_decrypt()'' for DH keys as well. -The encrypt routine will make up a random key, attach the public key to the message and used the shared secret to encrypt -the message with a cipher you choose (and hash the shared secret into a symmetric key with a hash you choose). The encrypt -function is a bit long to call but its worth it. -\index{dh\_encrypt()} -\begin{verbatim} -int dh_encrypt(const unsigned char *in, unsigned long len, - unsigned char *out, unsigned long *outlen, - prng_state *prng, int wprng, int cipher, int hash, - dh_key *key); -\end{verbatim} -Where ``in'' is the plaintext and ``out'' is where the ciphertext will go. Make sure you set the ``outlen'' value before -calling. The ``key'' is the public DH key of the user you want to encrypt to not your private key. It will randomly make up -a Diffie-Hellman key, export the public copy, hash the shared key with the hash you specify and use the message digest in a -cipher you specify to encrypt the message. To decrypt one of these packets call: -\index{dh\_decrypt()} -\begin{verbatim} -int dh_decrypt(const unsigned char *in, unsigned long len, - unsigned char *out, unsigned long *outlen, - dh_key *key); -\end{verbatim} -Where ``in'' is the ciphertext and len is the length of the ciphertext. ``out'' is where the plaintext should be stored -and ``outlen'' is the length of the output (you must first set it to the size of your buffer). - -To facilate encrypting to multiple parties the follow two functions are provided: +Similar to the RSA related functions there are functions to encrypt or decrypt symmetric keys using the DH public key +algorithms. \begin{verbatim} int dh_encrypt_key(const unsigned char *inkey, unsigned long keylen, unsigned char *out, unsigned long *len, @@ -1706,25 +1641,7 @@ and find the hash of the shared secret. The message digest is than XOR'ed again 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. -To sign with a Diffie-Hellman key call: -\index{dh\_sign()} -\begin{verbatim} -int dh_sign(const unsigned char *in, unsigned long inlen, - unsigned char *out, unsigned long *outlen, int hash, - prng_state *prng, int wprng, dh_key *key); -\end{verbatim} -Where ``in'' is the message to size of length ``inlen'' bytes. ``out'' is where the signature is placed and ``outlen'' -is the length of the signature (you must first set it to the size of your buffer). To verify call: -\index{dh\_verify()} -\begin{verbatim} -int dh_verify(const unsigned char *sig, - const unsigned char *msg, - unsigned long inlen, int *stat, dh_key *key); -\end{verbatim} -Where ``sig'' is the output of ''dh\_sign()`` and ``msg'' is the message of length ``inlen''. It stores a zero in ``stat'' -if the signature is invalid otherwise it puts a one in there. - -Similar to the RSA system you can sign and verify a pre-hashed block as well using: +Similar to the RSA system you can sign and verify a hash of a message. \begin{verbatim} int dh_sign_hash(const unsigned char *in, unsigned long inlen, unsigned char *out, unsigned long *outlen, @@ -1735,6 +1652,10 @@ int dh_verify_hash(const unsigned char *sig, const unsigned char *hash, 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} \section{Background} @@ -1784,7 +1705,7 @@ To import and export a key there are: int ecc_export(unsigned char *out, unsigned long *outlen, int type, ecc_key *key); -int ecc_import(const unsigned char *in, ecc_key *key); +int ecc_import(const unsigned char *in, unsigned long inlen, ecc_key *key); \end{verbatim} These two work exactly like there DH counterparts. Finally when you share your public key you can make a shared secret with: @@ -1813,28 +1734,8 @@ void ecc_sizes(int *low, int *high); Which both work like their DH counterparts. \section{ECC Packet} -There are routines to perform the work similar to that of ``rsa\_encrypt()'' and ``rsa\_decrypt()'' for ECC keys as well. -The encrypt routine will make up a random key, attach the public key to the message and used the shared secret to encrypt -the message with a cipher you choose (and hash the shared secret into a symmetric key with a hash you choose). The encrypt -function is a bit long to call but its worth it. -\index{ecc\_encrypt()} -\begin{verbatim} -int ecc_encrypt(const unsigned char *in, unsigned long len, - unsigned char *out, unsigned long *outlen, - prng_state *prng, - int wprng, int cipher, int hash, - ecc_key *key); -\end{verbatim} -Where ``in'' is the plaintext and ``out'' is where the ciphertext will go. Make sure you set the ``outlen'' value before -calling. The ``key'' is the public ECC key of the user you want to encrypt too. To decrypt one of these packets call: -\index{ecc\_decrypt()} -\begin{verbatim} -int ecc_decrypt(const unsigned char *in, unsigned long len, - unsigned char *out, unsigned long *outlen, - ecc_key *key); -\end{verbatim} -Similar to the DH code there are two functions to facilate multi-party code. They work exactly like the DH code and are -given as: +Similar to the RSA API there are two functions which encrypt and decrypt symmetric keys using the ECC public key +algorithms. \begin{verbatim} int ecc_encrypt_key(const unsigned char *inkey, unsigned long keylen, unsigned char *out, unsigned long *len, @@ -1844,24 +1745,13 @@ int ecc_encrypt_key(const unsigned char *inkey, unsigned long keylen, int ecc_decrypt_key(const unsigned char *in, unsigned char *outkey, unsigned long *keylen, ecc_key *key); \end{verbatim} -You can sign messages with the ECC routines as well, to sign a message call: -\index{ecc\_sign()} -\begin{verbatim} -int ecc_sign(const unsigned char *in, unsigned long inlen, - unsigned char *out, unsigned long *outlen, - int hash, prng_state *prng, int wprng, - ecc_key *key); -\end{verbatim} -Where ``in'' is the message to sign and ``out'' is where the signature will go. ``hash'' is the index into the descriptor -table of which hash function you want to use (e.g. use ``find\_hash()''). You must set ``outlen'' to the size of the -output buffer before calling. To verify a signature call: -\index{ecc\_verify()} -\begin{verbatim} -int ecc_verify(const unsigned char *sig, const unsigned char *msg, - unsigned long inlen, int *stat, ecc_key *key); -\end{verbatim} -Where ``sig'' is the signature from ``ecc\_sign()'' and ``msg'' is the input message. It sets ``stat'' to 0 if the signature -is invalid and it sets ``stat'' to 1 if its valid. To sign or verify pre-hashed blocks use + +Where ``inkey'' 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 ``ecc\_encrypt\_key()''. The hash chosen must produce a message digest at least as large +as the symmetric key you are trying to share. + +There are also functions to sign and verify the hash of a message. \begin{verbatim} int ecc_sign_hash(const unsigned char *in, unsigned long inlen, unsigned char *out, unsigned long *outlen, @@ -1872,6 +1762,11 @@ int ecc_verify_hash(const unsigned char *sig, const unsigned char *hash, ecc_key *key); \end{verbatim} +The ``ecc\_sign\_hash'' function signs the message hash in ``in'' of length ``inlen'' and forms a ECC packet in ``out''. +The ``ecc\_verify\_hash'' function verifies the ECC signature in ``sig'' against the hash in ``hash''. It sets ``stat'' +to non-zero if the signature passes or zero if it fails. + + \section{ECC Keysizes} With ECC if you try and sign a hash that is bigger than your ECC key you can run into problems. The math will still work and in effect the signature will still work. With ECC keys the strength of the signature is limited by the size of @@ -2417,9 +2312,8 @@ useful when TWOFISH\_SMALL is defined as the table values are computed on the fl will increase by approximately 500 bytes. If this is defined but TWOFISH\_SMALL is not the cipher will still work but it will not speed up the encryption or decryption functions. -\subsubsection{SAFERP\_SMALL and RIJNDAEL\_SMALL} -These two build options let you use slower versions of the ciphers which are also much smaller. In the case of the SAFER+ -implementation it ends up being 1/6th the size. As for Rijndael its roughly half the size. - +\subsubsection{SMALL\_CODE} +When this is defined some of the code such as the Rijndael and SAFER+ ciphers are replaced with smaller code variants. +These variants are slower but can save quite a bit of code space. \end{document} diff --git a/demos/small.c b/demos/small.c index bb4bfdb..e45f3a6 100644 --- a/demos/small.c +++ b/demos/small.c @@ -6,6 +6,6 @@ int main(void) { register_cipher(&rijndael_desc); register_prng(&yarrow_desc); - register_hash(&sha1_desc); + register_hash(&sha256_desc); return 0; } diff --git a/demos/test.c b/demos/test.c index 3fcd645..dcd4a42 100644 --- a/demos/test.c +++ b/demos/test.c @@ -259,7 +259,7 @@ void ctr_tests(void) for (x = 0; x < 32; x++) blk[x] = count[x] = x; /* now lets start a ctr session */ - if ((errno = ctr_start(find_cipher("rijndael"), count, key, 16, 0, &ctr)) != CRYPT_OK) { printf("Error: %s\n", error_to_string(errno)); return; } + if ((errno = ctr_start(find_cipher("aes"), count, key, 16, 0, &ctr)) != CRYPT_OK) { printf("Error: %s\n", error_to_string(errno)); return; } /* now lets encode 32 bytes */ for (x = 0; x < 4; x++) @@ -272,7 +272,7 @@ void ctr_tests(void) for (x = 0; x < 32; x++) count[x] = x; /* now lets start a cbc session */ - if ((errno = ctr_start(find_cipher("rijndael"), count, key, 16, 0, &ctr)) != CRYPT_OK) { printf("Error: %s\n", error_to_string(errno)); return; } + if ((errno = ctr_start(find_cipher("aes"), count, key, 16, 0, &ctr)) != CRYPT_OK) { printf("Error: %s\n", error_to_string(errno)); return; } /* now lets decode 32 bytes */ for (x = 0; x < 4; x++) @@ -369,7 +369,7 @@ void rsa_test(void) /* now lets test rsa_encrypt() */ for (x = 0; x < 8; x++) in[x] = (unsigned char)x; x = sizeof(out); - if ((errno = rsa_encrypt(in, 8, out, &x, &prng, find_prng("yarrow"), find_cipher("rijndael"), &key)) != CRYPT_OK) { + if ((errno = rsa_encrypt(in, 8, out, &x, &prng, find_prng("yarrow"), find_cipher("aes"), &key)) != CRYPT_OK) { printf("Error: %s\n", error_to_string(errno)); return; } @@ -410,7 +410,7 @@ void rsa_test(void) } printf("RSA Export takes %lu bytes\n", x); rsa_free(&key); - if ((errno = rsa_import(out, &key)) != CRYPT_OK) { + if ((errno = rsa_import(out, &key, x)) != CRYPT_OK) { printf("Error: %s\n", error_to_string(errno)); return; } @@ -596,7 +596,7 @@ void time_ecb(void) func = cipher_descriptor[x].ecb_encrypt; y1 = 0; t1 = XCLOCK(); - while (XCLOCK() - t1 < 2*XCLOCKS_PER_SEC) { + while (XCLOCK() - t1 < 3*XCLOCKS_PER_SEC) { DO256; y1 += 256; } t1 = XCLOCK() - t1; @@ -604,7 +604,7 @@ void time_ecb(void) func = cipher_descriptor[x].ecb_decrypt; y2 = 0; t2 = XCLOCK(); - while (XCLOCK() - t2 < 2*XCLOCKS_PER_SEC) { + while (XCLOCK() - t2 < 3*XCLOCKS_PER_SEC) { DO256; y2 += 256; } t2 = XCLOCK() - t2; @@ -673,7 +673,7 @@ void dh_tests(void) dh_free(&userb); /* import and make the shared secret again */ - if ((errno = dh_import(buf[1], &userb)) != CRYPT_OK) { + if ((errno = dh_import(buf[1], y, &userb)) != CRYPT_OK) { printf("Error: %s\n", error_to_string(errno)); return; } @@ -741,7 +741,7 @@ void dh_tests(void) dh_make_key(&prng, find_prng("yarrow"), 24, &usera); x = 4096; - if (dh_encrypt(buf[0], 16, buf[1], &x, &prng, find_prng("yarrow"), find_cipher("rijndael"), + if (dh_encrypt(buf[0], 16, buf[1], &x, &prng, find_prng("yarrow"), find_cipher("aes"), find_hash("sha1"), &usera) != CRYPT_OK) { printf("dh_encrypt says %s\n", error_to_string(errno)); return; @@ -910,7 +910,7 @@ void ecc_tests(void) printf("ECC-192 export took %ld bytes\n", y); /* import and make the shared secret again */ - if ((errno = ecc_import(buf[1], &userb)) != CRYPT_OK) { + if ((errno = ecc_import(buf[1], y, &userb)) != CRYPT_OK) { printf("Error: %s\n", error_to_string(errno)); return; } @@ -973,7 +973,7 @@ void ecc_tests(void) ecc_make_key(&prng, find_prng("yarrow"), 20, &usera); x = 4096; - if (ecc_encrypt(buf[0], 16, buf[1], &x, &prng, find_prng("yarrow"), find_cipher("rijndael"), + if (ecc_encrypt(buf[0], 16, buf[1], &x, &prng, find_prng("yarrow"), find_cipher("aes"), find_hash("tiger"), &usera) != CRYPT_OK) { printf("ecc_encrypt says %s\n", error_to_string(errno)); return; @@ -1158,7 +1158,7 @@ void register_all_algs(void) register_cipher(&serpent_desc); #endif #ifdef RIJNDAEL - register_cipher(&rijndael_desc); + register_cipher(&aes_desc); #endif #ifdef TWOFISH register_cipher(&twofish_desc); @@ -1179,6 +1179,9 @@ void register_all_algs(void) #ifdef CAST5 register_cipher(&cast5_desc); #endif +#ifdef NOEKEON + register_cipher(&noekeon_desc); +#endif register_cipher(&null_desc); @@ -1284,7 +1287,7 @@ void kr_test(void) exit(-1); } kr_display(kr); - if ((errno = kr_import(kr, buf)) != CRYPT_OK) { + if ((errno = kr_import(kr, buf, len)) != CRYPT_OK) { printf("Error importing key %d, %s\n", i, error_to_string(errno)); exit(-1); } @@ -1303,7 +1306,7 @@ void kr_test(void) exit(-1); } kr_display(kr); - if ((errno = kr_import(kr, buf)) != CRYPT_OK) { + if ((errno = kr_import(kr, buf, len)) != CRYPT_OK) { printf("Error importing key %d, %s\n", i, error_to_string(errno)); exit(-1); } @@ -1441,7 +1444,7 @@ void kr_test(void) kr_clear(&kr); kr_init(&kr); kr_display(kr); - if ((errno = kr_import(kr, buf)) != CRYPT_OK) { + if ((errno = kr_import(kr, buf, len)) != CRYPT_OK) { printf("Error importing key %s\n", error_to_string(errno)); exit(-1); } @@ -1459,7 +1462,7 @@ void kr_test(void) kr_clear(&kr); kr_init(&kr); kr_display(kr); - if ((errno = kr_import(kr, buf2)) != CRYPT_OK) { + if ((errno = kr_import(kr, buf2, len)) != CRYPT_OK) { printf("Error importing key %s\n", error_to_string(errno)); exit(-1); } @@ -1529,7 +1532,7 @@ int main(void) #endif register_all_algs(); - + if ((errno = yarrow_start(&prng)) != CRYPT_OK) { printf("yarrow_start: %s\n", error_to_string(errno)); } diff --git a/dh.c b/dh.c index 019ab20..44a237a 100644 --- a/dh.c +++ b/dh.c @@ -315,18 +315,22 @@ void dh_free(dh_key *key) #define INPUT_BIGNUM(num, in, x, y) \ { \ /* load value */ \ + if (y + 4 > inlen) { \ + errno = CRYPT_INVALID_PACKET; \ + goto error; \ + } \ LOAD32L(x, in+y); \ y += 4; \ \ /* sanity check... */ \ - if (x > 1024) { \ - errno = CRYPT_ERROR; \ + if (x+y > inlen) { \ + errno = CRYPT_INVALID_PACKET; \ goto error; \ } \ \ /* load it */ \ if (mp_read_raw(num, (unsigned char *)in+y, x) != MP_OKAY) {\ - return CRYPT_MEM; \ + errno = CRYPT_MEM; \ goto error; \ } \ y += x; \ @@ -381,9 +385,9 @@ int dh_export(unsigned char *out, unsigned long *outlen, int type, dh_key *key) return CRYPT_OK; } -int dh_import(const unsigned char *in, dh_key *key) +int dh_import(const unsigned char *in, unsigned long inlen, dh_key *key) { - long x, y, s; + unsigned long x, y, s; int errno; _ARGCHK(in != NULL); @@ -393,6 +397,10 @@ int dh_import(const unsigned char *in, dh_key *key) if ((errno = packet_valid_header((unsigned char *)in, PACKET_SECT_DH, PACKET_SUB_KEY)) != CRYPT_OK) { return errno; } + + if (2+PACKET_SIZE > inlen) { + return CRYPT_INVALID_PACKET; + } /* init */ if (mp_init_multi(&key->x, &key->y, NULL) != MP_OKAY) { @@ -403,7 +411,7 @@ int dh_import(const unsigned char *in, dh_key *key) key->type = in[y++]; s = (long)in[y++] * 8; - for (x = 0; (s > sets[x].size) && (sets[x].size); x++); + for (x = 0; (s > (unsigned long)sets[x].size) && (sets[x].size); x++); if (sets[x].size == 0) { errno = CRYPT_INVALID_KEYSIZE; goto error; diff --git a/dh_sys.c b/dh_sys.c index ee31ee3..ad94896 100644 --- a/dh_sys.c +++ b/dh_sys.c @@ -1,432 +1,3 @@ -#ifdef PK_PACKET - -int dh_encrypt(const unsigned char *in, unsigned long len, - unsigned char *out, unsigned long *outlen, - prng_state *prng, int wprng, int cipher, int hash, - dh_key *key) -{ - unsigned char pub_expt[1536], dh_shared[1536], IV[MAXBLOCKSIZE], skey[MAXBLOCKSIZE]; - dh_key pubkey; - unsigned long x, y, z, hashsize, blocksize, pubkeysize; - int keysize, errno; - symmetric_CTR ctr; - - _ARGCHK(in != NULL); - _ARGCHK(out != NULL); - _ARGCHK(outlen != NULL); - _ARGCHK(key != NULL); - - /* check that wprng/cipher/hash are not invalid */ - if ((errno = prng_is_valid(wprng)) != CRYPT_OK) { - return errno; - } - - if ((errno = hash_is_valid(hash)) != CRYPT_OK) { - return errno; - } - - if ((errno = cipher_is_valid(cipher)) != CRYPT_OK) { - return errno; - } - - /* make a random key and export the public copy */ - if ((errno = dh_make_key(prng, wprng, dh_get_size(key), &pubkey)) != CRYPT_OK) { - return errno; - } - - pubkeysize = sizeof(pub_expt); - if ((errno = dh_export(pub_expt, &pubkeysize, PK_PUBLIC, &pubkey)) != CRYPT_OK) { - dh_free(&pubkey); - return errno; - } - - /* now check if the out buffer is big enough */ - if (*outlen < (10 + PACKET_SIZE + pubkeysize + cipher_descriptor[cipher].block_length + len)) { - dh_free(&pubkey); - return CRYPT_BUFFER_OVERFLOW; - } - - /* make random key */ - blocksize = cipher_descriptor[cipher].block_length; - hashsize = hash_descriptor[hash].hashsize; - keysize = hashsize; - if ((errno = cipher_descriptor[cipher].keysize(&keysize)) != CRYPT_OK) { - dh_free(&pubkey); - return errno; - } - - x = sizeof(dh_shared); - if ((errno = dh_shared_secret(&pubkey, key, dh_shared, &x)) != CRYPT_OK) { - dh_free(&pubkey); - return errno; - } - dh_free(&pubkey); - - z = sizeof(skey); - if ((errno = hash_memory(hash, dh_shared, x, skey, &z)) != CRYPT_OK) { - return errno; - } - - /* make up IV */ - if (prng_descriptor[wprng].read(IV, cipher_descriptor[cipher].block_length, prng) != - cipher_descriptor[cipher].block_length) { - return CRYPT_ERROR_READPRNG; - } - - /* setup CTR mode */ - if ((errno = ctr_start(cipher, IV, skey, keysize, 0, &ctr)) != CRYPT_OK) { - return errno; - } - - /* output header */ - y = PACKET_SIZE; - - /* size of cipher name and the name itself */ - out[y++] = cipher_descriptor[cipher].ID; - - /* 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]; - } - - /* cipher IV */ - for (x = 0; x < blocksize; x++, y++) { - out[y] = IV[x]; - } - - /* length of ciphertext */ - STORE32L(len, out+y); - y += 4; - - /* encrypt the message */ - if ((errno = ctr_encrypt(in, out+y, len, &ctr)) != CRYPT_OK) { - return errno; - } - y += len; - - /* store header */ - packet_store_header(out, PACKET_SECT_DH, PACKET_SUB_ENCRYPTED, y); - -#ifdef CLEAN_STACK - /* clean up */ - zeromem(pub_expt, sizeof(pub_expt)); - zeromem(dh_shared, sizeof(dh_shared)); - zeromem(skey, sizeof(skey)); - zeromem(IV, sizeof(IV)); - zeromem(&ctr, sizeof(ctr)); -#endif - *outlen = y; - return CRYPT_OK; -} - -int dh_decrypt(const unsigned char *in, unsigned long len, - unsigned char *out, unsigned long *outlen, - dh_key *key) -{ - unsigned char shared_secret[1536], skey[MAXBLOCKSIZE]; - unsigned long x, y, z, res, hashsize, blocksize; - int hash, cipher, keysize, errno; - dh_key pubkey; - symmetric_CTR ctr; - - _ARGCHK(in != NULL); - _ARGCHK(out != NULL); - _ARGCHK(outlen != NULL); - _ARGCHK(key != NULL); - - /* right key type? */ - if (key->type != PK_PRIVATE) { - return CRYPT_PK_NOT_PRIVATE; - } - - /* is header correct? */ - if ((errno = packet_valid_header((unsigned char *)in, PACKET_SECT_DH, PACKET_SUB_ENCRYPTED)) != CRYPT_OK) { - return errno; - } - - /* now lets get the cipher name */ - y = PACKET_SIZE; - cipher = find_cipher_id(in[y++]); - if (cipher == -1) { - return CRYPT_INVALID_CIPHER; - } - - /* now lets get the hash name */ - hash = find_hash_id(in[y++]); - if (hash == -1) { - return CRYPT_INVALID_HASH; - } - - /* common values */ - blocksize = cipher_descriptor[cipher].block_length; - hashsize = hash_descriptor[hash].hashsize; - keysize = hashsize; - if ((errno = cipher_descriptor[cipher].keysize(&keysize)) != CRYPT_OK) { - return errno; - } - - /* get public key */ - LOAD32L(x, in+y); - y += 4; - if ((errno = dh_import(in+y, &pubkey)) != CRYPT_OK) { - return errno; - } - y += x; - - /* make shared key */ - x = sizeof(shared_secret); - if ((errno = dh_shared_secret(key, &pubkey, shared_secret, &x)) != CRYPT_OK) { - dh_free(&pubkey); - return errno; - } - dh_free(&pubkey); - - z = sizeof(skey); - if ((errno = hash_memory(hash, shared_secret, x, skey, &z)) != CRYPT_OK) { - return errno; - } - - /* setup CTR mode */ - if ((errno = ctr_start(cipher, in+y, skey, keysize, 0, &ctr)) != CRYPT_OK) { - res = errno; - goto done; - } - - /* skip over the IV */ - y += blocksize; - - /* get length */ - LOAD32L(len,in+y); - y += 4; - - /* buffer overflow? */ - if (len > *outlen) { - res = CRYPT_BUFFER_OVERFLOW; - goto done; - } - - /* decrypt message */ - if ((errno = ctr_decrypt(in+y, out, len, &ctr)) != CRYPT_OK) { - res = errno; - goto done; - } - *outlen = len; - - res = CRYPT_OK; -done: -#ifdef CLEAN_STACK - zeromem(shared_secret, sizeof(shared_secret)); - zeromem(skey, sizeof(skey)); - zeromem(&ctr, sizeof(ctr)); -#endif - return res; -} - -int dh_sign(const unsigned char *in, unsigned long inlen, - unsigned char *out, unsigned long *outlen, - int hash, prng_state *prng, int wprng, - dh_key *key) -{ - mp_int a, b, k, m, g, p, p1, tmp; - unsigned char buf[1536], md[MAXBLOCKSIZE]; - unsigned long x, y, z; - int res, errno; - - _ARGCHK(in != NULL); - _ARGCHK(out != NULL); - _ARGCHK(outlen != NULL); - _ARGCHK(key != NULL); - - /* check parameters */ - if (key->type != PK_PRIVATE) { - return CRYPT_PK_NOT_PRIVATE; - } - - /* is the IDX valid ? */ - if (!is_valid_idx(key->idx)) { - return CRYPT_PK_INVALID_TYPE; - } - - if ((errno = prng_is_valid(wprng)) != CRYPT_OK) { - return errno; - } - - if ((errno = hash_is_valid(hash)) != CRYPT_OK) { - return errno; - } - - /* hash the message */ - z = sizeof(md) - 1; - md[0] = 0; - if ((errno = hash_memory(hash, in, inlen, md+1, &z)) != CRYPT_OK) { - return errno; - } - - /* make up a random value k, - * since the order of the group is prime - * we need not check if gcd(k, r) is 1 - */ - buf[0] = 0; - if (prng_descriptor[wprng].read(buf+1, sets[key->idx].size-1, prng) != (unsigned long)(sets[key->idx].size-1)) { - return CRYPT_ERROR_READPRNG; - } - - /* init bignums */ - if (mp_init_multi(&a, &b, &k, &m, &p, &g, &p1, &tmp, NULL) != MP_OKAY) { - return CRYPT_MEM; - } - - /* load k and m */ - if (mp_read_raw(&m, md, 1+hash_descriptor[hash].hashsize) != MP_OKAY) { goto error; } - if (mp_read_raw(&k, buf, sets[key->idx].size) != MP_OKAY) { goto error; } - - /* load g, p and p1 */ - if (mp_read_radix(&g, sets[key->idx].base, 10) != MP_OKAY) { goto error; } - if (mp_read_radix(&p, sets[key->idx].prime, 10) != MP_OKAY) { goto error; } - if (mp_sub_d(&p, 1, &p1) != MP_OKAY) { goto error; } /* p1 = p-1 */ - if (mp_div_2(&p1, &p1) != MP_OKAY) { goto error; } /* p1 = (p-1)/2 */ - - /* now get a = g^k mod p */ - if (mp_exptmod(&g, &k, &p, &a) != MP_OKAY) { goto error; } /* a = g^k mod p */ - - /* now find M = xa + kb mod p1 or just b = (M - xa)/k mod p1 */ - if (mp_invmod(&k, &p1, &k) != MP_OKAY) { goto error; } /* k = 1/k mod p1 */ - if (mp_mulmod(&a, &key->x, &p1, &tmp) != MP_OKAY) { goto error; } /* tmp = xa */ - if (mp_submod(&m, &tmp, &p1, &tmp) != MP_OKAY) { goto error; } /* tmp = M - xa */ - if (mp_mulmod(&k, &tmp, &p1, &b) != MP_OKAY) { goto error; } /* b = (M - xa)/k */ - - /* store header */ - y = PACKET_SIZE; - - /* store length and name of hash */ - buf[y++] = hash_descriptor[hash].ID; /* store hash ID */ - - /* now store them both (a,b) */ - x = mp_raw_size(&a); /* get raw size of a */ - STORE32L(x, buf+y); y += 4; /* store size of a */ - mp_toraw(&a, buf+y); y += x; /* store a itself */ - - x = mp_raw_size(&b); /* get raw size of b */ - STORE32L(x, buf+y); y += 4; /* store size of b */ - mp_toraw(&b, buf+y); y += x; /* store b itself */ - - /* check if size too big */ - if (*outlen < y) { goto error; } - - /* store header */ - packet_store_header(buf, PACKET_SECT_DH, PACKET_SUB_SIGNED, y); - - /* store it */ - memcpy(out, buf, y); - *outlen = y; - -#ifdef CLEAN_STACK - zeromem(md, sizeof(md)); - zeromem(buf, sizeof(buf)); -#endif - - res = CRYPT_OK; - goto done; -error: - res = CRYPT_MEM; -done: - mp_clear_multi(&tmp, &p1, &g, &p, &m, &k, &b, &a, NULL); - return res; -} - -int dh_verify(const unsigned char *sig, const unsigned char *msg, - unsigned long inlen, int *stat, - dh_key *key) -{ - mp_int a, b, p, g, m, tmp; - unsigned char md[MAXBLOCKSIZE]; - unsigned long x, y, z; - int hash, res, errno; - - _ARGCHK(sig != NULL); - _ARGCHK(msg != NULL); - _ARGCHK(stat != NULL); - _ARGCHK(key != NULL); - - /* default to invalid */ - *stat = 0; - - /* header ok? */ - if ((errno = packet_valid_header((unsigned char *)sig, PACKET_SECT_DH, PACKET_SUB_SIGNED)) != CRYPT_OK) { - return errno; - } - - /* get hash out of packet */ - y = PACKET_SIZE; - hash = find_hash_id(sig[y++]); - - if (hash == -1) { - return CRYPT_INVALID_HASH; - } - - /* hash the message */ - md[0] = 0; - z = sizeof(md) - 1; - if ((errno = hash_memory(hash, msg, inlen, md+1, &z)) != CRYPT_OK) { - return errno; - } - - /* init all bignums */ - if (mp_init_multi(&a, &p, &b, &g, &m, &tmp, NULL) != MP_OKAY) { - return CRYPT_MEM; - } - - /* load a and b */ - LOAD32L(x, sig+y); - y += 4; - if (mp_read_raw(&a, (unsigned char *)sig+y, x) != MP_OKAY) { goto error; } - y += x; - - LOAD32L(x, sig+y); - y += 4; - if (mp_read_raw(&b, (unsigned char *)sig+y, x) != MP_OKAY) { goto error; } - y += x; - - /* load p and g */ - if (mp_read_radix(&p, sets[key->idx].prime, 10) != MP_OKAY) { goto error; } - if (mp_read_radix(&g, sets[key->idx].base, 10) != MP_OKAY) { goto error; } - - /* load m */ - if (mp_read_raw(&m, md, hash_descriptor[hash].hashsize + 1) != MP_OKAY) { goto error; } - - /* find g^m mod p */ - if (mp_exptmod(&g, &m, &p, &m) != MP_OKAY) { goto error; } /* m = g^m mod p */ - - /* find y^a * a^b */ - if (mp_exptmod(&key->y, &a, &p, &tmp) != MP_OKAY) { goto error; } /* tmp = y^a mod p */ - if (mp_exptmod(&a, &b, &p, &a) != MP_OKAY) { goto error; } /* a = a^b mod p */ - if (mp_mulmod(&a, &tmp, &p, &a) != MP_OKAY) { goto error; } /* a = y^a * a^b mod p */ - - /* y^a * a^b == g^m ??? */ - if (mp_cmp(&a, &m) == 0) { - *stat = 1; - } - - /* clean up */ - res = CRYPT_OK; - goto done; -error: - res = CRYPT_MEM; -done: - mp_clear_multi(&tmp, &m, &g, &p, &b, &a, NULL); -#ifdef CLEAN_STACK - zeromem(md, sizeof(md)); -#endif - return res; -} - -#endif - int dh_encrypt_key(const unsigned char *inkey, unsigned long keylen, unsigned char *out, unsigned long *len, prng_state *prng, int wprng, int hash, @@ -558,7 +129,7 @@ int dh_decrypt_key(const unsigned char *in, unsigned char *outkey, /* get public key */ LOAD32L(x, in+y); y += 4; - if ((errno = dh_import(in+y, &pubkey)) != CRYPT_OK) { + if ((errno = dh_import(in+y, x, &pubkey)) != CRYPT_OK) { return errno; } y += x; diff --git a/ecc.c b/ecc.c index 479e4e8..2cde908 100644 --- a/ecc.c +++ b/ecc.c @@ -636,16 +636,22 @@ done: #define INPUT_BIGNUM(num, in, x, y) \ { \ /* load value */ \ + if (y+4 > inlen) { \ + errno = CRYPT_INVALID_PACKET; \ + goto error; \ + } \ LOAD32L(x, in+y); \ y += 4; \ \ /* sanity check... */ \ - if (x > 1024) { \ + if (y+x > inlen) { \ + errno = CRYPT_INVALID_PACKET; \ goto error; \ } \ \ /* load it */ \ if (mp_read_raw(num, (unsigned char *)in+y, x) != MP_OKAY) {\ + errno = CRYPT_MEM; \ goto error; \ } \ y += x; \ @@ -701,10 +707,10 @@ int ecc_export(unsigned char *out, unsigned long *outlen, int type, ecc_key *key return CRYPT_OK; } -int ecc_import(const unsigned char *in, ecc_key *key) +int ecc_import(const unsigned char *in, unsigned long inlen, ecc_key *key) { unsigned long x, y, s; - int res, errno; + int errno; _ARGCHK(in != NULL); _ARGCHK(key != NULL); @@ -713,6 +719,10 @@ int ecc_import(const unsigned char *in, ecc_key *key) if ((errno = packet_valid_header((unsigned char *)in, PACKET_SECT_ECC, PACKET_SUB_KEY)) != CRYPT_OK) { return errno; } + + if (2+PACKET_SIZE > inlen) { + return CRYPT_INVALID_PACKET; + } /* init key */ if (mp_init_multi(&key->pubkey.x, &key->pubkey.y, &key->k, NULL) != MP_OKAY) { @@ -725,21 +735,21 @@ int ecc_import(const unsigned char *in, ecc_key *key) for (x = 0; (s > (unsigned long)sets[x].size) && (sets[x].size); x++); if (sets[x].size == 0) { - res = CRYPT_INVALID_KEYSIZE; - goto error2; + errno = CRYPT_INVALID_KEYSIZE; + goto error; } key->idx = x; /* type check both values */ if ((key->type != PK_PUBLIC) && (key->type != PK_PRIVATE)) { - res = CRYPT_INVALID_PACKET; - goto error2; + errno = CRYPT_INVALID_PACKET; + goto error; } /* is the key idx valid? */ if (!is_valid_idx(key->idx)) { - res = CRYPT_INVALID_PACKET; - goto error2; + errno = CRYPT_INVALID_PACKET; + goto error; } /* load x coordinate */ @@ -747,20 +757,19 @@ int ecc_import(const unsigned char *in, ecc_key *key) /* load y */ x = in[y++]; - if ((errno = expand_y_point(&key->pubkey, key->idx, x)) != CRYPT_OK) { res = errno; goto error2; } + if ((errno = expand_y_point(&key->pubkey, key->idx, x)) != CRYPT_OK) { + goto error; + } if (key->type == PK_PRIVATE) { /* load private key */ INPUT_BIGNUM(&key->k, in, x, y); } - res = CRYPT_OK; - goto done; + return CRYPT_OK; error: - res = CRYPT_MEM; -error2: mp_clear_multi(&key->pubkey.x, &key->pubkey.y, &key->k, NULL); done: - return res; + return errno; } int ecc_shared_secret(ecc_key *private_key, ecc_key *public_key, diff --git a/ecc_sys.c b/ecc_sys.c index 9ec5418..adcecdc 100644 --- a/ecc_sys.c +++ b/ecc_sys.c @@ -1,490 +1,3 @@ -#ifdef PK_PACKET - -int ecc_encrypt(const unsigned char *in, unsigned long len, - unsigned char *out, unsigned long *outlen, - prng_state *prng, int wprng, int cipher, int hash, - ecc_key *key) -{ - unsigned char pub_expt[512], ecc_shared[256], IV[MAXBLOCKSIZE], skey[MAXBLOCKSIZE]; - ecc_key pubkey; - unsigned long x, y, z, pubkeysize; - int keysize, blocksize, hashsize, errno; - symmetric_CTR ctr; - - _ARGCHK(in != NULL); - _ARGCHK(out != NULL); - _ARGCHK(outlen != NULL); - _ARGCHK(key != NULL); - - /* check that wprng/cipher/hash are not invalid */ - if ((errno = prng_is_valid(wprng)) != CRYPT_OK) { - return errno; - } - - if ((errno = cipher_is_valid(cipher)) != CRYPT_OK) { - return errno; - } - - if ((errno = hash_is_valid(hash)) != CRYPT_OK) { - return errno; - } - - /* make a random key and export the public copy */ - if ((errno = ecc_make_key(prng, wprng, ecc_get_size(key), &pubkey)) != CRYPT_OK) { - return errno; - } - - pubkeysize = sizeof(pub_expt); - if ((errno = ecc_export(pub_expt, &pubkeysize, PK_PUBLIC, &pubkey)) != CRYPT_OK) { - ecc_free(&pubkey); - return errno; - } - - /* now check if the out buffer is big enough */ - if (*outlen < (10 + PACKET_SIZE + pubkeysize + - cipher_descriptor[cipher].block_length + len)) { - ecc_free(&pubkey); - return CRYPT_BUFFER_OVERFLOW; - } - - /* make random key */ - blocksize = cipher_descriptor[cipher].block_length; - hashsize = hash_descriptor[hash].hashsize; - keysize = hashsize; - if ((errno = cipher_descriptor[cipher].keysize(&keysize)) != CRYPT_OK) { - ecc_free(&pubkey); - return errno; - } - x = sizeof(ecc_shared); - if ((errno = ecc_shared_secret(&pubkey, key, ecc_shared, &x)) != CRYPT_OK) { - ecc_free(&pubkey); - return errno; - } - ecc_free(&pubkey); - - z = sizeof(skey); - if ((errno = hash_memory(hash, ecc_shared, x, skey, &z)) != CRYPT_OK) { - return errno; - } - - /* make up IV */ - if (prng_descriptor[wprng].read(IV, cipher_descriptor[cipher].block_length, prng) != - (unsigned long)cipher_descriptor[cipher].block_length) { - return CRYPT_ERROR_READPRNG; - } - - /* setup CTR mode */ - if ((errno = ctr_start(cipher, IV, skey, keysize, 0, &ctr)) != CRYPT_OK) { - return errno; - } - - /* output header */ - y = PACKET_SIZE; - - /* size of cipher name and the name itself */ - out[y++] = cipher_descriptor[cipher].ID; - - /* size of hash name and the name itself */ - out[y++] = hash_descriptor[hash].ID; - - /* length of ECC pubkey and the key itself */ - STORE32L(pubkeysize, out+y); - y += 4; - for (x = 0; x < (unsigned)pubkeysize; x++, y++) { - out[y] = pub_expt[x]; - } - - /* cipher IV */ - for (x = 0; x < (unsigned)blocksize; x++, y++) { - out[y] = IV[x]; - } - - /* length of ciphertext */ - STORE32L(len, out+y); - y += 4; - - /* encrypt the message */ - if ((errno = ctr_encrypt(in, out+y, len, &ctr)) != CRYPT_OK) { - return errno; - } - y += len; - - /* store header */ - packet_store_header(out, PACKET_SECT_ECC, PACKET_SUB_ENCRYPTED, y); - -#ifdef CLEAN_STACK - /* clean up */ - zeromem(pub_expt, sizeof(pub_expt)); - zeromem(ecc_shared, sizeof(ecc_shared)); - zeromem(skey, sizeof(skey)); - zeromem(IV, sizeof(IV)); - zeromem(&ctr, sizeof(ctr)); -#endif - - *outlen = y; - return CRYPT_OK; -} - -int ecc_decrypt(const unsigned char *in, unsigned long len, - unsigned char *out, unsigned long *outlen, - ecc_key *key) -{ - unsigned char shared_secret[256], skey[MAXBLOCKSIZE]; - unsigned long x, y, z, res, hashsize, blocksize; - int cipher, hash, keysize, errno; - ecc_key pubkey; - symmetric_CTR ctr; - - _ARGCHK(in != NULL); - _ARGCHK(out != NULL); - _ARGCHK(outlen != NULL); - _ARGCHK(key != NULL); - - /* right key type? */ - if (key->type != PK_PRIVATE) { - return CRYPT_PK_NOT_PRIVATE; - } - - /* is header correct? */ - if ((errno = packet_valid_header((unsigned char *)in, PACKET_SECT_ECC, PACKET_SUB_ENCRYPTED)) != CRYPT_OK) { - return errno; - } - - /* now lets get the cipher name */ - y = PACKET_SIZE; - cipher = find_cipher_id(in[y++]); - if (cipher == -1) { - return CRYPT_INVALID_CIPHER; - } - - /* now lets get the hash name */ - hash = find_hash_id(in[y++]); - if (hash == -1) { - return CRYPT_INVALID_HASH; - } - - /* common values */ - blocksize = cipher_descriptor[cipher].block_length; - hashsize = hash_descriptor[hash].hashsize; - keysize = hashsize; - if ((errno = cipher_descriptor[cipher].keysize(&keysize)) != CRYPT_OK) { - return errno; - } - - /* get public key */ - LOAD32L(x, in+y); - y += 4; - if ((errno = ecc_import(in+y, &pubkey)) != CRYPT_OK) { - return errno; - } - y += x; - - /* make shared key */ - x = sizeof(shared_secret); - if ((errno = ecc_shared_secret(key, &pubkey, shared_secret, &x)) != CRYPT_OK) { - ecc_free(&pubkey); - return errno; - } - ecc_free(&pubkey); - - z = sizeof(skey); - if ((errno = hash_memory(hash, shared_secret, x, skey, &z)) != CRYPT_OK) { - res = errno; - goto done; - } - - /* setup CTR mode */ - if ((errno = ctr_start(cipher, in+y, skey, keysize, 0, &ctr)) != CRYPT_OK) { - res = errno; - goto done; - } - y += blocksize; - - /* get length */ - LOAD32L(len,in+y); - y += 4; - - /* buffer overflow? */ - if (len > *outlen) { - res = CRYPT_BUFFER_OVERFLOW; - goto done; - } - - /* decrypt message */ - if ((errno = ctr_decrypt(in+y, out, len, &ctr)) != CRYPT_OK) { - res = errno; - goto done; - } - *outlen = len; - - res = CRYPT_OK; -done: -#ifdef CLEAN_STACK - zeromem(shared_secret, sizeof(shared_secret)); - zeromem(skey, sizeof(skey)); - zeromem(&ctr, sizeof(ctr)); -#endif - return res; -} - -/* Signatures - * - * Signatures are performed using a slightly modified ElGamal protocol. - * In these notes uppercase letters are points and lowercase letters are - * scalars. The users private key is 'x' and public key is Y = xG. - * The order of the curve is 'r'. - * - * - * To sign a message 'm' the user does this - -1. Makes up a random 'k' and finds kG [basically makes up a ecc_key], we will let A = kG -2. Finds b such that b = (m - x)/k mod r -3. Outputs (A, b) as the signature - -To verify a user computes mG and compares that to (bA + Y). Note that (bA + Y) is equal to - -= ((m - x)/k)(kG) + xG -= (m - x)G + xG -= mG - -In theory, assuming the ECC Discrete Log is a hard problem an attacker -cannot find 'x' from (A, b). 'b' is perfectly decorrelated and reveals no -information. A reveals what kG is but not 'k' directly. Therefore, -assuming finding 'k' given kG is hard, finding 'x' from b is hard too. - -*/ - -int ecc_sign(const unsigned char *in, unsigned long inlen, - unsigned char *out, unsigned long *outlen, - int hash, prng_state *prng, int wprng, - ecc_key *key) -{ - ecc_key pubkey; - mp_int b, p; - unsigned char epubkey[256], er[256], md[MAXBLOCKSIZE]; - unsigned long x, y, z, pubkeysize, rsize; - int res, errno; - - _ARGCHK(in != NULL); - _ARGCHK(out != NULL); - _ARGCHK(outlen != NULL); - _ARGCHK(key != NULL); - - /* is this a private key? */ - if (key->type != PK_PRIVATE) { - return CRYPT_PK_NOT_PRIVATE; - } - - /* is the IDX valid ? */ - if (!is_valid_idx(key->idx)) { - return CRYPT_PK_INVALID_TYPE; - } - - if ((errno = prng_is_valid(wprng)) != CRYPT_OK) { - return errno; - } - - if ((errno = hash_is_valid(hash)) != CRYPT_OK) { - return errno; - } - - /* make up a key and export the public copy */ - if ((errno = ecc_make_key(prng, wprng, ecc_get_size(key), &pubkey)) != CRYPT_OK) { - return errno; - } - - pubkeysize = sizeof(epubkey); - if ((errno = ecc_export(epubkey, &pubkeysize, PK_PUBLIC, &pubkey)) != CRYPT_OK) { - ecc_free(&pubkey); - return errno; - } - - /* get the hash and load it as a bignum into 'b' */ - md[0] = 0; - z = sizeof(md)-1; - if ((errno = hash_memory(hash, in, inlen, md+1, &z)) != CRYPT_OK) { - ecc_free(&pubkey); - return errno; - } - - /* init the bignums */ - if (mp_init_multi(&b, &p, NULL) != MP_OKAY) { - ecc_free(&pubkey); - return CRYPT_MEM; - } - if (mp_read_radix(&p, sets[key->idx].order, 10) != MP_OKAY) { goto error; } - if (mp_read_raw(&b, md, 1+hash_descriptor[hash].hashsize) != MP_OKAY) { goto error; } - - /* find b = (m - x)/k */ - if (mp_invmod(&pubkey.k, &p, &pubkey.k) != MP_OKAY) { goto error; } /* k = 1/k */ - if (mp_submod(&b, &key->k, &p, &b) != MP_OKAY) { goto error; } /* b = m - x */ - if (mp_mulmod(&b, &pubkey.k, &p, &b) != MP_OKAY) { goto error; } /* b = (m - x)/k */ - - /* export it */ - rsize = mp_raw_size(&b); - if (rsize > sizeof(er)) { - goto error; - } - mp_toraw(&b, er); - - /* now lets check the outlen before we write */ - if (*outlen < (9 + PACKET_SIZE + rsize + pubkeysize)) { - res = CRYPT_BUFFER_OVERFLOW; - goto done1; - } - - /* lets output */ - y = PACKET_SIZE; - - /* length of hash name plus NULL */ - out[y++] = hash_descriptor[hash].ID; - - /* size of public key */ - STORE32L(pubkeysize, out+y); - y += 4; - - /* copy the public key */ - for (x = 0; x < pubkeysize; x++, y++) { - out[y] = epubkey[x]; - } - - /* size of 'r' */ - STORE32L(rsize, out+y); - y += 4; - - /* copy r */ - for (x = 0; x < rsize; x++, y++) { - out[y] = er[x]; - } - - /* store header */ - packet_store_header(out, PACKET_SECT_ECC, PACKET_SUB_SIGNED, y); - - /* clear memory */ - *outlen = y; - res = CRYPT_OK; - goto done1; -error: - res = CRYPT_MEM; -done1: - mp_clear_multi(&b, &p, NULL); - ecc_free(&pubkey); -#ifdef CLEAN_STACK - zeromem(er, sizeof(er)); - zeromem(epubkey, sizeof(epubkey)); - zeromem(md, sizeof(md)); -#endif - return res; -} - -/* verify that mG = (bA + Y) */ -int ecc_verify(const unsigned char *sig, const unsigned char *msg, - unsigned long inlen, int *stat, - ecc_key *key) -{ - ecc_point *mG; - ecc_key pubkey; - mp_int b, p, m; - unsigned long x, y, z; - int hash, res, errno; - unsigned char md[MAXBLOCKSIZE]; - - _ARGCHK(sig != NULL); - _ARGCHK(msg != NULL); - _ARGCHK(stat != NULL); - _ARGCHK(key != NULL); - - /* default to invalid signature */ - *stat = 0; - - /* is the message format correct? */ - if ((errno = packet_valid_header((unsigned char *)sig, PACKET_SECT_ECC, PACKET_SUB_SIGNED)) != CRYPT_OK) { - return errno; - } - - /* get hash name */ - y = PACKET_SIZE; - hash = find_hash_id(sig[y++]); - if (hash == -1) { - return CRYPT_INVALID_HASH; - } - - /* get size of public key */ - LOAD32L(x, sig+y); - y += 4; - - /* load the public key */ - if ((errno = ecc_import((unsigned char*)sig+y, &pubkey)) != CRYPT_OK) { - return errno; - } - y += x; - - /* load size of 'b' */ - LOAD32L(x, sig+y); - y += 4; - - /* init values */ - if (mp_init_multi(&b, &m, &p, NULL) != MP_OKAY) { - ecc_free(&pubkey); - return CRYPT_MEM; - } - - mG = new_point(); - if (mG == NULL) { - mp_clear_multi(&b, &m, &p, NULL); - ecc_free(&pubkey); - return CRYPT_MEM; - } - - /* load b */ - if (mp_read_raw(&b, (unsigned char *)sig+y, x) != MP_OKAY) { goto error; } - y += x; - - /* get m in binary a bignum */ - md[0] = 0; - z = sizeof(md)-1; - if ((errno = hash_memory(hash, msg, inlen, md+1, &z)) != CRYPT_OK) { - res = errno; - goto done1; - } - if (mp_read_raw(&m, md, hash_descriptor[hash].hashsize + 1) != MP_OKAY) { goto error; } - - /* load prime */ - if (mp_read_radix(&p, sets[key->idx].prime, 10) != MP_OKAY) { goto error; } - - /* get bA */ - if (ecc_mulmod(&b, &pubkey.pubkey, &pubkey.pubkey, &p, key->idx) != CRYPT_OK) { goto error; } - - /* get bA + Y */ - if (add_point(&pubkey.pubkey, &key->pubkey, &pubkey.pubkey, &p) != CRYPT_OK) { goto error; } - - /* get mG */ - if (mp_read_radix(&mG->x, sets[key->idx].Gx, 16) != MP_OKAY) { goto error; } - if (mp_read_radix(&mG->y, sets[key->idx].Gy, 16) != MP_OKAY) { goto error; } - if (ecc_mulmod(&m, mG, mG, &p, key->idx) != CRYPT_OK) { goto error; } - - /* compare mG to bA + Y */ - if (!mp_cmp(&mG->x, &pubkey.pubkey.x) && !mp_cmp(&mG->y, &pubkey.pubkey.y)) { - *stat = 1; - } - - /* clear up and return */ - res = CRYPT_OK; - goto done1; -error: - res = CRYPT_MEM; -done1: - del_point(mG); - ecc_free(&pubkey); - mp_clear_multi(&p, &m, &b, NULL); -#ifdef CLEAN_STACK - zeromem(md, sizeof(md)); -#endif - return CRYPT_OK; -} - -#endif - int ecc_encrypt_key(const unsigned char *inkey, unsigned long keylen, unsigned char *out, unsigned long *len, prng_state *prng, int wprng, int hash, @@ -619,7 +132,7 @@ int ecc_decrypt_key(const unsigned char *in, unsigned char *outkey, /* get public key */ LOAD32L(x, in+y); y += 4; - if ((errno = ecc_import(in+y, &pubkey)) != CRYPT_OK) { + if ((errno = ecc_import(in+y, x, &pubkey)) != CRYPT_OK) { return errno; } y += x; @@ -805,7 +318,7 @@ int ecc_verify_hash(const unsigned char *sig, const unsigned char *hash, y += 4; /* load the public key */ - if ((errno = ecc_import((unsigned char*)sig+y, &pubkey)) != CRYPT_OK) { + if ((errno = ecc_import((unsigned char*)sig+y, x, &pubkey)) != CRYPT_OK) { return errno; } y += x; diff --git a/keyring.c b/keyring.c index 4536d9b..d50c27f 100644 --- a/keyring.c +++ b/keyring.c @@ -361,7 +361,7 @@ int kr_export(pk_key *pk, unsigned long ID, int key_type, unsigned char *out, un } } -int kr_import(pk_key *pk, const unsigned char *in) +int kr_import(pk_key *pk, const unsigned char *in, unsigned long inlen) { _pk_key key; int system, key_type, errno; @@ -370,6 +370,10 @@ int kr_import(pk_key *pk, const unsigned char *in) _ARGCHK(pk != NULL); _ARGCHK(in != NULL); + if (inlen < 10) { + return CRYPT_INVALID_PACKET; + } + if (memcmp(in, key_magic, 4)) { return CRYPT_INVALID_PACKET; } @@ -382,19 +386,23 @@ int kr_import(pk_key *pk, const unsigned char *in) } zeromem(&key, sizeof(key)); + + /* size of remaining packet */ + inlen -= 10 + 3*MAXLEN; + switch (system) { case RSA_KEY: - if ((errno = rsa_import(in+10+3*MAXLEN, &(key.rsa))) != CRYPT_OK) { + if ((errno = rsa_import(in+10+3*MAXLEN, inlen, &(key.rsa))) != CRYPT_OK) { return errno; } break; case DH_KEY: - if ((errno = dh_import(in+10+3*MAXLEN, &(key.dh))) != CRYPT_OK) { + if ((errno = dh_import(in+10+3*MAXLEN, inlen, &(key.dh))) != CRYPT_OK) { return errno; } break; case ECC_KEY: - if ((errno = ecc_import(in+10+3*MAXLEN, &(key.ecc))) != CRYPT_OK) { + if ((errno = ecc_import(in+10+3*MAXLEN, inlen, &(key.ecc))) != CRYPT_OK) { return errno; } break; @@ -443,7 +451,7 @@ int kr_load(pk_key **pk, FILE *in, symmetric_CTR *ctr) } if (_read(buf, len, in, ctr) != len) { goto done2; } - if ((errno = kr_import(*pk, buf)) != CRYPT_OK) { + if ((errno = kr_import(*pk, buf, len)) != CRYPT_OK) { return errno; } } diff --git a/makefile b/makefile index e37456d..ec3a503 100644 --- a/makefile +++ b/makefile @@ -9,7 +9,7 @@ # a build. This is easy to remedy though, for those that have problems. # The version -VERSION=0.77 +VERSION=0.78 #Compiler and Linker Names CC=gcc @@ -39,6 +39,9 @@ CFLAGS += -c -I./ -Wall -Wsign-compare -W -Wno-unused -Werror \ #optimize for SIZE (comment out SPEED/DEBUG line as well) CFLAGS += -Os +#Use small code variants of functions when possible? (Slows it down!) +CFLAGS += -DSMALL_CODE + #compile for DEBUGGING #CFLAGS += -g3 @@ -74,6 +77,7 @@ CFLAGS += -DXTEA CFLAGS += -DTWOFISH CFLAGS += -DDES CFLAGS += -DCAST5 +CFLAGS += -DNOEKEON #You can also customize the Twofish code. All four combinations #of the flags are possible but only three of them make sense. @@ -98,14 +102,6 @@ CFLAGS += -DCAST5 # This speeds up the cipher somewhat. #CFLAGS += -DTWOFISH_TABLES -#Small code variant of the SAFER+ cipher, uses same RAM but less code space -#With this defined the cipher is slower. On my x86 with GCC 3.2 it required 50KB less space -CFLAGS += -DSAFERP_SMALL - -#Small Rijndael [saves 13KB on an x86] -#With this defined the cipher is slower (by 50Mbit/sec on an Athon XP) -CFLAGS += -DRIJNDAEL_SMALL - #Use fast PK routines. Basically this limits the size of the private key in the #DH system to 256 bits. The group order remains unchanged so the best #attacks are still GNFS (for DH upto 2560-bits) @@ -114,10 +110,6 @@ CFLAGS += -DRIJNDAEL_SMALL #security so its by default not turned on. USE AT YOUR RISK! #CFLAGS += -DFAST_PK -#Include the PK Packet functions (e.g. dh_encrypt) -#Does not affect the key/hash routines (e.g. ecc_sign_hash) -#CFLAGS += -DPK_PACKET - # Chaining modes CFLAGS += -DCFB CFLAGS += -DOFB @@ -174,7 +166,7 @@ INCPATH=/usr/include OBJECTS=keyring.o gf.o mem.o sprng.o ecc.o base64.o dh.o rsa.o \ bits.o yarrow.o cfb.o ofb.o ecb.o ctr.o cbc.o hash.o tiger.o sha1.o \ md5.o md4.o md2.o sha256.o sha512.o xtea.o aes.o serpent.o des.o \ -safer_tab.o safer.o safer+.o rc4.o rc2.o rc6.o rc5.o cast5.o blowfish.o crypt.o \ +safer_tab.o safer.o safer+.o rc4.o rc2.o rc6.o rc5.o cast5.o noekeon.o blowfish.o crypt.o \ ampi.o mpi.o prime.o twofish.o packet.o hmac.o strings.o TESTOBJECTS=demos/test.o diff --git a/makefile.ps2 b/makefile.ps2 index a7cc405..f09da3e 100644 --- a/makefile.ps2 +++ b/makefile.ps2 @@ -43,15 +43,18 @@ CFLAGS += -c -I./ -Wall -Wsign-compare -W -Wno-unused -Werror \ -DXMALLOC=$(XMALLOC) -DXCALLOC=$(XCALLOC) -DXFREE=$(XFREE) -DXCLOCK=$(XCLOCK) \ -DXCLOCKS_PER_SEC=$(XCLOCKS_PER_SEC) -#no file support, when defined the library will not have any functions that can read/write files -#(comment out to have file support) -CFLAGS += -DNO_FILE - #optimize for SPEED (comment out SIZE line as well) #CFLAGS += -O3 -fomit-frame-pointer -funroll-loops #optimize for SIZE (comment out SPEED line as well) -CFLAGS += -Os +CFLAGS += -Os + +#Use small code variants of functions when possible? (Slows it down!) +CFLAGS += -DSMALL_CODE + +#no file support, when defined the library will not have any functions that can read/write files +#(comment out to have file support) +CFLAGS += -DNO_FILE #These flags control how the library gets built. @@ -75,6 +78,7 @@ CFLAGS += -DXTEA CFLAGS += -DTWOFISH CFLAGS += -DDES CFLAGS += -DCAST5 +CFLAGS += -DNOEKEON #You can also customize the Twofish code. All four combinations #of the flags are possible but only three of them make sense. @@ -115,10 +119,6 @@ CFLAGS += -DRIJNDAEL_SMALL #security so its by default not turned on. USE AT YOUR RISK! #CFLAGS += -DFAST_PK -#Include the PK Packet functions (e.g. dh_encrypt) -#Does not affect the key/hash routines (e.g. ecc_sign_hash) -#CFLAGS += -DPK_PACKET - # Chaining modes CFLAGS += -DCFB CFLAGS += -DOFB @@ -156,11 +156,6 @@ CFLAGS += -DKR # include large integer math routines? (required by the PK code) CFLAGS += -DMPI -# Use a small prime table? It greatly reduces the size of prime.c at a little impact -# in speed. -# -CFLAGS += -DSMALL_PRIME_TAB - # include HMAC support CFLAGS += -DHMAC @@ -183,7 +178,7 @@ INCPATH=/usr/include OBJECTS=keyring.o gf.o mem.o sprng.o ecc.o base64.o dh.o rsa.o \ bits.o yarrow.o cfb.o ofb.o ecb.o ctr.o cbc.o hash.o tiger.o sha1.o \ md5.o md4.o md2.o sha256.o sha512.o xtea.o aes.o serpent.o des.o \ -safer_tab.o safer.o safer+.o rc4.o rc2.o rc6.o rc5.o cast5.o blowfish.o crypt.o \ +safer_tab.o safer.o safer+.o rc4.o rc2.o rc6.o rc5.o cast5.o noekeon.o blowfish.o crypt.o \ ampi.o mpi.o prime.o twofish.o packet.o hmac.o strings.o # PlayStation(tm) 2 C run-time startup module diff --git a/makefile.vc b/makefile.vc index 37d99af..e8deeb5 100644 --- a/makefile.vc +++ b/makefile.vc @@ -16,6 +16,9 @@ XCLOCKS_PER_SEC=CLOCKS_PER_SEC CFLAGS = /c /Ogisy1 /Gs /I. /W3 /DWIN32 /DXMALLOC=$(XMALLOC) /DXCALLOC=$(XCALLOC) /DXFREE=$(XFREE) /DXCLOCK=$(XCLOCK) /DXCLOCKS_PER_SEC=$(XCLOCKS_PER_SEC) +#Small code (smaller variants of some block ciphers) +CFLAGS += /DSMALL_CODE + #These flags control how the library gets built. #no file support, when defined the library will not have any functions that can read/write files @@ -48,6 +51,7 @@ CFLAGS += /DXTEA CFLAGS += /DTWOFISH CFLAGS += /DDES CFLAGS += /DCAST5 +CFLAGS += /DNOEKEON #You can also customize the Twofish code. All four combinations #of the flags are possible but only three of them make sense. @@ -72,14 +76,6 @@ CFLAGS += /DCAST5 # This speeds up the cipher somewhat. # CFLAGS += /DTWOFISH_TABLES -#Small code variant of the SAFER+ cipher, uses same RAM but less code space -#With this defined the cipher is slower. On my x86 with GCC 3.2 it required 50KB less space -CFLAGS += /DSAFERP_SMALL - -#Small Rijndael [saves 13KB on an x86] -#With this defined the cipher is slower (by 50Mbit/sec on an Athon XP) -CFLAGS += /DRIJNDAEL_SMALL - #Use fast PK routines. Basically this limits the size of the private key in the #DH system to 256 bits. The group order remains unchanged so the best #attacks are still GNFS (for DH upto 2560-bits) @@ -88,10 +84,6 @@ CFLAGS += /DRIJNDAEL_SMALL #security so its by default not turned on. USE AT YOUR RISK! #CFLAGS += /DFAST_PK -#Include the PK Packet functions (e.g. dh_encrypt) -#Does not affect the key/hash routines (e.g. ecc_sign_hash) -#CFLAGS += /DPK_PACKET - # Chaining modes CFLAGS += /DCFB CFLAGS += /DOFB @@ -129,11 +121,6 @@ CFLAGS += /DKR # include large integer math routines? (required by the PK code) CFLAGS += /DMPI -# Use a small prime table? It greatly reduces the size of prime.c at a little impact -# in speed. -# -CFLAGS += /DSMALL_PRIME_TAB - # include HMAC support CFLAGS += /DHMAC @@ -227,6 +214,8 @@ md2.obj: md2.c $(CC) $(CFLAGS) md2.c cast5.obj: cast5.c $(CC) $(CFLAGS) cast5.c +noekeon.obj: noekeon.c + $(CC) $(CFLAGS) noekeon.c demos/test.obj: demos/test.c $(CC) $(CFLAGS) demos/test.c @@ -236,11 +225,11 @@ demos/hashsum.obj: demos/hashsum.c tomcrypt.lib: keyring.obj gf.obj mem.obj sprng.obj ecc.obj base64.obj dh.obj rsa.obj bits.obj hmac.obj \ yarrow.obj cfb.obj ofb.obj ecb.obj ctr.obj cbc.obj hash.obj tiger.obj sha1.obj md2.obj md5.obj md4.obj sha256.obj sha512.obj xtea.obj \ -aes.obj serpent.obj safer_tab.obj safer.obj safer+.obj cast5.obj rc2.obj rc6.obj rc5.obj des.obj blowfish.obj crypt.obj ampi.obj \ +aes.obj serpent.obj safer_tab.obj safer.obj safer+.obj cast5.obj noekeon.obj rc2.obj rc6.obj rc5.obj des.obj blowfish.obj crypt.obj ampi.obj \ strings.obj mpi.obj prime.obj twofish.obj packet.obj $(AR) /out:tomcrypt.lib keyring.obj gf.obj mem.obj sprng.obj ecc.obj base64.obj dh.obj rsa.obj hmac.obj \ bits.obj yarrow.obj cfb.obj ofb.obj ecb.obj ctr.obj cbc.obj hash.obj tiger.obj sha1.obj md2.obj md5.obj md4.obj sha256.obj \ -strings.obj sha512.obj xtea.obj aes.obj serpent.obj safer_tab.obj safer.obj safer+.obj cast5.obj rc2.obj rc6.obj rc5.obj des.obj \ +strings.obj sha512.obj xtea.obj aes.obj serpent.obj safer_tab.obj safer.obj safer+.obj cast5.obj noekeon.obj rc2.obj rc6.obj rc5.obj des.obj \ blowfish.obj crypt.obj ampi.obj mpi.obj prime.obj twofish.obj packet.obj diff --git a/mycrypt.h b/mycrypt.h index 8216c00..02d6ee0 100644 --- a/mycrypt.h +++ b/mycrypt.h @@ -13,8 +13,8 @@ extern "C" { #endif /* version */ -#define CRYPT 0x0077 -#define SCRYPT "0.77" +#define CRYPT 0x0078 +#define SCRYPT "0.78" /* max size of either a cipher/hash block or symmetric key [largest of the two] */ #define MAXBLOCKSIZE 128 diff --git a/mycrypt_argchk.h b/mycrypt_argchk.h index 4ce83c8..9369a8e 100644 --- a/mycrypt_argchk.h +++ b/mycrypt_argchk.h @@ -10,23 +10,17 @@ * On embedded platforms you can change the fprintf() to be a routine that would display a message * somehow */ -#ifndef SONY_PS2 - -#define _ARGCHK(x) \ - if (!(x)) { \ - fprintf(stderr, "_ARGCHK '%s' failure on line %d of file %s\n", #x, __LINE__, __FILE__); \ - raise(SIGABRT); \ - } - + +#ifdef SMALL_CODE + extern void crypt_argchk(char *v, char *s, int d); + #define _ARGCHK(x) if (!(x)) { crypt_argchk(#x, __FILE__, __LINE__); } #else - -#define _ARGCHK(x) \ - if (!(x)) { \ - printf("_ARGCHK '%s' failure on line %d of file %s\n", #x, __LINE__, __FILE__); \ - raise(SIGABRT); \ - } - -#endif /* SONY_PS2 */ + #ifdef SONY_PS2 + #define _ARGCHK(x) if (!(x)) { printf("_ARGCHK '%s' failure on line %d of file %s\n", #x, __LINE__, __FILE__); raise(SIGABRT); } + #else + #define _ARGCHK(x) if (!(x)) { fprintf(stderr, "_ARGCHK '%s' failure on line %d of file %s\n", #x, __LINE__, __FILE__); raise(SIGABRT); } + #endif +#endif #elif ARGTYPE == 1 diff --git a/mycrypt_cipher.h b/mycrypt_cipher.h index e36d2a7..81ce762 100644 --- a/mycrypt_cipher.h +++ b/mycrypt_cipher.h @@ -94,6 +94,12 @@ struct cast5_key { }; #endif +#ifdef NOEKEON +struct noekeon_key { + unsigned long K[4], dK[4]; +}; +#endif + typedef union Symmetric_key { #ifdef DES struct des_key des; @@ -132,6 +138,9 @@ typedef union Symmetric_key { #ifdef CAST5 struct cast5_key cast5; #endif +#ifdef NOEKEON + struct noekeon_key noekeon; +#endif } symmetric_key; /* A block cipher ECB structure */ @@ -252,12 +261,20 @@ extern const struct _cipher_descriptor serpent_desc; #endif #ifdef RIJNDAEL + +/* make aes an alias */ +#define aes_setup rijndael_setup +#define aes_ecb_encrypt rijndael_ecb_encrypt +#define aes_ecb_decrypt rijndael_ecb_decrypt +#define aes_test rijndael_test +#define aes_keysize rijndael_keysize + extern int rijndael_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey); extern void rijndael_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *key); extern void rijndael_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *key); extern int rijndael_test(void); extern int rijndael_keysize(int *desired_keysize); -extern const struct _cipher_descriptor rijndael_desc; +extern const struct _cipher_descriptor rijndael_desc, aes_desc; #endif #ifdef XTEA @@ -303,6 +320,15 @@ extern int cast5_keysize(int *desired_keysize); extern const struct _cipher_descriptor cast5_desc; #endif +#ifdef NOEKEON +extern int noekeon_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey); +extern void noekeon_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *key); +extern void noekeon_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *key); +extern int noekeon_test(void); +extern int noekeon_keysize(int *desired_keysize); +extern const struct _cipher_descriptor noekeon_desc; +#endif + #ifdef ECB extern int ecb_start(int cipher, const unsigned char *key, int keylen, int num_rounds, symmetric_ECB *ecb); diff --git a/mycrypt_kr.h b/mycrypt_kr.h index e097a64..3edf7db 100644 --- a/mycrypt_kr.h +++ b/mycrypt_kr.h @@ -1,5 +1,9 @@ #ifdef KR +#if !defined(MRSA) || !defined(MDH) || !defined(MECC) + #error "Keyring code requires all three public key algorithms." +#endif + #define MAXLEN 256 enum { @@ -48,7 +52,7 @@ extern int kr_make_key(pk_key *pk, prng_state *prng, int wprng, const unsigned char *email, const unsigned char *description); extern int kr_export(pk_key *pk, unsigned long ID, int key_type, unsigned char *out, unsigned long *outlen); -extern int kr_import(pk_key *pk, const unsigned char *in); +extern int kr_import(pk_key *pk, const unsigned char *in, unsigned long inlen); extern int kr_load(pk_key **pk, FILE *in, symmetric_CTR *ctr); extern int kr_save(pk_key *pk, FILE *out, symmetric_CTR *ctr); diff --git a/mycrypt_pk.h b/mycrypt_pk.h index 941c8bf..b86bb7f 100644 --- a/mycrypt_pk.h +++ b/mycrypt_pk.h @@ -52,27 +52,6 @@ extern int rsa_signdepad(const unsigned char *in, unsigned long inlen, extern void rsa_free(rsa_key *key); -#ifdef PK_PACKET - -extern int rsa_encrypt(const unsigned char *in, unsigned long len, - unsigned char *out, unsigned long *outlen, - prng_state *prng, int wprng, int cipher, - rsa_key *key); - -extern int rsa_decrypt(const unsigned char *in, unsigned long len, - unsigned char *out, unsigned long *outlen, - rsa_key *key); - -extern int rsa_sign(const unsigned char *in, unsigned long inlen, - unsigned char *out, unsigned long *outlen, - int hash, rsa_key *key); - -extern int rsa_verify(const unsigned char *sig, const unsigned char *msg, - unsigned long inlen, int *stat, - rsa_key *key); - -#endif - extern int rsa_encrypt_key(const unsigned char *inkey, unsigned long inlen, unsigned char *outkey, unsigned long *outlen, prng_state *prng, int wprng, rsa_key *key); @@ -88,7 +67,7 @@ extern int rsa_verify_hash(const unsigned char *sig, const unsigned char *hash, int *stat, rsa_key *key); extern int rsa_export(unsigned char *out, unsigned long *outlen, int type, rsa_key *key); -extern int rsa_import(const unsigned char *in, rsa_key *key); +extern int rsa_import(const unsigned char *in, unsigned long inlen, rsa_key *key); #endif /* ---- DH Routines ---- */ @@ -107,33 +86,11 @@ extern int dh_make_key(prng_state *prng, int wprng, int keysize, dh_key *key); extern void dh_free(dh_key *key); extern int dh_export(unsigned char *out, unsigned long *outlen, int type, dh_key *key); -extern int dh_import(const unsigned char *in, dh_key *key); +extern int dh_import(const unsigned char *in, unsigned long inlen, dh_key *key); extern int dh_shared_secret(dh_key *private_key, dh_key *public_key, unsigned char *out, unsigned long *outlen); -#ifdef PK_PACKET - -extern int dh_encrypt(const unsigned char *in, unsigned long len, - unsigned char *out, unsigned long *outlen, - prng_state *prng, int wprng, int cipher, int hash, - dh_key *key); - -extern int dh_decrypt(const unsigned char *in, unsigned long len, - unsigned char *out, unsigned long *outlen, - dh_key *key); - -extern int dh_sign(const unsigned char *in, unsigned long inlen, - unsigned char *out, unsigned long *outlen, int hash, - prng_state *prng, int wprng, - dh_key *key); - -extern int dh_verify(const unsigned char *sig, const unsigned char *msg, - unsigned long inlen, int *stat, - dh_key *key); - -#endif - extern int dh_encrypt_key(const unsigned char *inkey, unsigned long keylen, unsigned char *out, unsigned long *len, prng_state *prng, int wprng, int hash, @@ -173,33 +130,11 @@ extern int ecc_make_key(prng_state *prng, int wprng, int keysize, ecc_key *key); extern void ecc_free(ecc_key *key); extern int ecc_export(unsigned char *out, unsigned long *outlen, int type, ecc_key *key); -extern int ecc_import(const unsigned char *in, ecc_key *key); +extern int ecc_import(const unsigned char *in, unsigned long inlen, ecc_key *key); extern int ecc_shared_secret(ecc_key *private_key, ecc_key *public_key, unsigned char *out, unsigned long *outlen); -#ifdef PK_PACKET - -extern int ecc_encrypt(const unsigned char *in, unsigned long len, - unsigned char *out, unsigned long *outlen, - prng_state *prng, int wprng, int cipher, int hash, - ecc_key *key); - -extern int ecc_decrypt(const unsigned char *in, unsigned long len, - unsigned char *out, unsigned long *outlen, - ecc_key *key); - -extern int ecc_sign(const unsigned char *in, unsigned long inlen, - unsigned char *out, unsigned long *outlen, int hash, - prng_state *prng, int wprng, - ecc_key *key); - -extern int ecc_verify(const unsigned char *sig, const unsigned char *msg, - unsigned long inlen, int *stat, - ecc_key *key); - -#endif - extern int ecc_encrypt_key(const unsigned char *inkey, unsigned long keylen, unsigned char *out, unsigned long *len, prng_state *prng, int wprng, int hash, diff --git a/noekeon.c b/noekeon.c new file mode 100644 index 0000000..ac44e6f --- /dev/null +++ b/noekeon.c @@ -0,0 +1,210 @@ +/* Implementation of the Noekeon block cipher by Tom St Denis */ +#include "mycrypt.h" + +#ifdef NOEKEON + +const struct _cipher_descriptor noekeon_desc = +{ + "noekeon", + 16, + 16, 16, 16, 16, + &noekeon_setup, + &noekeon_ecb_encrypt, + &noekeon_ecb_decrypt, + &noekeon_test, + &noekeon_keysize +}; + +static const unsigned long RC[] = { + 0x00000080, 0x0000001b, 0x00000036, 0x0000006c, + 0x000000d8, 0x000000ab, 0x0000004d, 0x0000009a, + 0x0000002f, 0x0000005e, 0x000000bc, 0x00000063, + 0x000000c6, 0x00000097, 0x00000035, 0x0000006a, + 0x000000d4 +}; + +static const unsigned long zero[] = { 0, 0, 0, 0 }; + +#define THETA(k, a, b, c, d) \ + temp = a^c; temp = temp ^ ROL(temp, 8) ^ ROR(temp, 8); \ + b ^= temp; d ^= temp; \ + a ^= k[0]; b ^= k[1]; \ + c ^= k[2]; d ^= k[3]; \ + temp = b^d; temp = temp ^ ROL(temp, 8) ^ ROR(temp, 8); \ + a ^= temp; c ^= temp; + +#define GAMMA(a, b, c, d) \ + b ^= ~(d|c); \ + a ^= c&b; \ + temp = d; d = a; a = temp;\ + c ^= a ^ b ^ d; \ + b ^= ~(d|c); \ + a ^= c&b; + +#define PI1(a, b, c, d) \ + a = ROL(a, 1); c = ROL(c, 5); d = ROL(d, 2); + +#define PI2(a, b, c, d) \ + a = ROR(a, 1); c = ROR(c, 5); d = ROR(d, 2); + +int noekeon_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey) +{ + unsigned long temp; + + _ARGCHK(key != NULL); + _ARGCHK(skey != NULL); + + if (keylen != 16) { + return CRYPT_INVALID_KEYSIZE; + } + + if (num_rounds != 16 && num_rounds != 0) { + return CRYPT_INVALID_ROUNDS; + } + + LOAD32L(skey->noekeon.K[0],&key[0]); + LOAD32L(skey->noekeon.K[1],&key[4]); + LOAD32L(skey->noekeon.K[2],&key[8]); + LOAD32L(skey->noekeon.K[3],&key[12]); + + LOAD32L(skey->noekeon.dK[0],&key[0]); + LOAD32L(skey->noekeon.dK[1],&key[4]); + LOAD32L(skey->noekeon.dK[2],&key[8]); + LOAD32L(skey->noekeon.dK[3],&key[12]); + + THETA(zero, skey->noekeon.dK[0], skey->noekeon.dK[1], skey->noekeon.dK[2], skey->noekeon.dK[3]); + + return CRYPT_OK; +} + +#ifdef CLEAN_STACK +static void _noekeon_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *key) +#else +void noekeon_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *key) +#endif +{ + unsigned long a,b,c,d,temp; + int r; + + _ARGCHK(key != NULL); + _ARGCHK(pt != NULL); + _ARGCHK(ct != NULL); + + LOAD32L(a,&pt[0]); LOAD32L(b,&pt[4]); + LOAD32L(c,&pt[8]); LOAD32L(d,&pt[12]); + +#define ROUND(i) \ + a ^= RC[r+i]; \ + THETA(key->noekeon.K, a,b,c,d); \ + PI1(a,b,c,d); \ + GAMMA(a,b,c,d); \ + PI2(a,b,c,d); + + for (r = 0; r < 16; r += 2) { + ROUND(0); + ROUND(1); + } + +#undef ROUND + + a ^= RC[16]; + THETA(key->noekeon.K, a, b, c, d); + + STORE32L(a,&ct[0]); STORE32L(b,&ct[4]); + STORE32L(c,&ct[8]); STORE32L(d,&ct[12]); +} + +#ifdef CLEAN_STACK +void noekeon_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *key) +{ + _noekeon_ecb_encrypt(pt, ct, key); + burn_stack(sizeof(unsigned long) * 5 + sizeof(int)); +} +#endif + +#ifdef CLEAN_STACK +static void _noekeon_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *key) +#else +void noekeon_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *key) +#endif +{ + unsigned long a,b,c,d, temp; + int r; + + _ARGCHK(key != NULL); + _ARGCHK(pt != NULL); + _ARGCHK(ct != NULL); + + LOAD32L(a,&ct[0]); LOAD32L(b,&ct[4]); + LOAD32L(c,&ct[8]); LOAD32L(d,&ct[12]); + +#define ROUND(i) \ + THETA(key->noekeon.dK, a,b,c,d); \ + a ^= RC[r-i]; \ + PI1(a,b,c,d); \ + GAMMA(a,b,c,d); \ + PI2(a,b,c,d); + + + for (r = 16; r > 0; r -= 2) { + ROUND(0); + ROUND(1); + } + +#undef ROUND + + THETA(key->noekeon.dK, a,b,c,d); + a ^= RC[0]; + STORE32L(a,&pt[0]); STORE32L(b, &pt[4]); + STORE32L(c,&pt[8]); STORE32L(d, &pt[12]); +} + +#ifdef CLEAN_STACK +void noekeon_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *key) +{ + _noekeon_ecb_decrypt(ct, pt, key); + burn_stack(sizeof(unsigned long) * 5 + sizeof(int)); +} +#endif + +int noekeon_test(void) +{ + static const unsigned char + key[] = + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }, + pt[] = + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }, + ct[] = + { 0x57, 0x9a, 0x6c, 0xe8, 0x91, 0x16, 0x52, 0x53, + 0x32, 0x00, 0xca, 0x0a, 0x17, 0x5d, 0x28, 0x0e }; + unsigned char tmp[2][16]; + int x, errno; + symmetric_key skey; + + if ((errno = noekeon_setup(key, 16, 0, &skey)) != CRYPT_OK) { + return errno; + } + + noekeon_ecb_encrypt(pt, tmp[0], &skey); + noekeon_ecb_decrypt(tmp[0], tmp[1], &skey); + + if (memcmp(tmp[0], ct, 16) || memcmp(tmp[1], pt, 16)) { + return CRYPT_FAIL_TESTVECTOR; + } + + return CRYPT_OK; +} + +int noekeon_keysize(int *desired_keysize) +{ + _ARGCHK(desired_keysize != NULL); + if (*desired_keysize < 16) { + return CRYPT_INVALID_KEYSIZE; + } else { + *desired_keysize = 16; + return CRYPT_OK; + } +} + +#endif + diff --git a/notes/tech0003.txt b/notes/tech0003.txt index cbe8751..5df3b15 100644 --- a/notes/tech0003.txt +++ b/notes/tech0003.txt @@ -33,14 +33,14 @@ RC2 | 256 | DES | 256 | 3DES | 768 | CAST5 | 132 | +Noekeon | 32 | ------------+-------------------------------/ Memory used per cipher on a 32-bit platform. [*] For Twofish with TWOFISH_SMALL defined [#] For all 64-bit SAFER ciphers. -Following this chart its ideal that in extremely low memory platforms that all of the ciphers are disabled and CAST5 is -left. CAST5 is a fairly fast cipher on all platforms which makes it ideally suited. It should be noted that the -SAFER and SAFER+ keys are formed of arrays of unsigned char. So in effect on platforms where "unsigned long" is -8 bytes SAFER would have the smallest key (CAST5 would come out to 264 bytes). In this case I would recommend -SAFER-SK128. \ No newline at end of file +Noekeon is a fairly fast cipher and uses very little memory. Ideally in low-ram platforms all other ciphers should be +left undefined and Noekeon should remain. While Noekeon is generally considered a secure block cipher (it is insecure +as a hash) CAST5 is perhaps a "runner-up" choice. CAST5 has been around longer (it is also known as CAST-128) and is +fairly fast as well. \ No newline at end of file diff --git a/rsa.c b/rsa.c index a4ea31c..ea4f86a 100644 --- a/rsa.c +++ b/rsa.c @@ -304,16 +304,22 @@ int rsa_depad(const unsigned char *in, unsigned long inlen, #define INPUT_BIGNUM(num, in, x, y) \ { \ /* load value */ \ + if (y + 4 > inlen) { \ + errno = CRYPT_INVALID_PACKET; \ + goto error2; \ + } \ LOAD32L(x, in+y); \ y += 4; \ \ /* sanity check... */ \ - if (x > 1024) { \ + if (y+x > inlen) { \ + errno = CRYPT_INVALID_PACKET; \ goto error2; \ } \ \ /* load it */ \ if (mp_read_raw(num, (unsigned char *)in+y, x) != MP_OKAY) {\ + errno = CRYPT_MEM; \ goto error2; \ } \ y += x; \ @@ -378,7 +384,7 @@ int rsa_export(unsigned char *out, unsigned long *outlen, int type, rsa_key *key return CRYPT_OK; } -int rsa_import(const unsigned char *in, rsa_key *key) +int rsa_import(const unsigned char *in, unsigned long inlen, rsa_key *key) { unsigned long x, y; int errno; @@ -390,6 +396,10 @@ int rsa_import(const unsigned char *in, rsa_key *key) if ((errno = packet_valid_header((unsigned char *)in, PACKET_SECT_RSA, PACKET_SUB_KEY)) != CRYPT_OK) { return errno; } + + if (inlen < 1+PACKET_SIZE) { + return CRYPT_INVALID_PACKET; + } /* init key */ if (mp_init_multi(&key->e, &key->d, &key->N, &key->dQ, &key->dP, &key->qP, @@ -426,7 +436,7 @@ int rsa_import(const unsigned char *in, rsa_key *key) error2: mp_clear_multi(&key->d, &key->e, &key->N, &key->dQ, &key->dP, &key->pQ, &key->qP, &key->p, &key->q, NULL); - return CRYPT_MEM; + return errno; } #include "rsa_sys.c" diff --git a/rsa_sys.c b/rsa_sys.c index 915e677..187deb2 100644 --- a/rsa_sys.c +++ b/rsa_sys.c @@ -1,350 +1,3 @@ -#ifdef PK_PACKET - -int rsa_encrypt(const unsigned char *in, unsigned long len, - unsigned char *out, unsigned long *outlen, - prng_state *prng, int wprng, int cipher, - rsa_key *key) -{ - unsigned char sym_IV[MAXBLOCKSIZE], sym_key[MAXBLOCKSIZE], rsa_in[4096], rsa_out[4096]; - symmetric_CTR ctr; - unsigned long x, y, blklen, rsa_size; - int keylen, errno;; - - _ARGCHK(in != NULL); - _ARGCHK(out != NULL); - _ARGCHK(outlen != NULL); - _ARGCHK(key != NULL); - - /* are the parameters valid? */ - if ((errno = prng_is_valid(wprng)) != CRYPT_OK) { - return errno; - } - - if ((errno = cipher_is_valid(cipher)) != CRYPT_OK) { - return errno; - } - - /* setup the CTR key */ - keylen = 32; /* default to 256-bit keys */ - if ((errno = cipher_descriptor[cipher].keysize(&keylen)) != CRYPT_OK) { - return errno; - } - - blklen = cipher_descriptor[cipher].block_length; - if (prng_descriptor[wprng].read(sym_key, keylen, prng) != (unsigned long)keylen) { - return CRYPT_ERROR_READPRNG; - } - - if (prng_descriptor[wprng].read(sym_IV, blklen, prng) != blklen) { - return CRYPT_ERROR_READPRNG; - } - - /* setup CTR mode */ - if ((errno = ctr_start(cipher, sym_IV, sym_key, keylen, 0, &ctr)) != CRYPT_OK) { - return errno; - } - - /* rsa_pad the symmetric key */ - y = sizeof(rsa_in); - if ((errno = rsa_pad(sym_key, keylen, rsa_in, &y, wprng, prng)) != CRYPT_OK) { - return errno; - } - - /* rsa encrypt it */ - rsa_size = sizeof(rsa_out); - if ((errno = rsa_exptmod(rsa_in, y, rsa_out, &rsa_size, PK_PUBLIC, key)) != CRYPT_OK) { - return errno; - } - - /* check size */ - if (*outlen < (PACKET_SIZE+9+rsa_size+blklen+len)) { - return CRYPT_BUFFER_OVERFLOW; - } - - /* now lets make the header */ - y = PACKET_SIZE; - out[y++] = cipher_descriptor[cipher].ID; - - /* store the size of the RSA value */ - STORE32L(rsa_size, (out+y)); - y += 4; - - /* store the rsa value */ - for (x = 0; x < rsa_size; x++, y++) { - out[y] = rsa_out[x]; - } - - /* store the IV used */ - for (x = 0; x < blklen; x++, y++) { - out[y] = sym_IV[x]; - } - - /* store the length */ - STORE32L(len, (out+y)); - y += 4; - - /* encrypt the message */ - if ((errno = ctr_encrypt(in, out+y, len, &ctr)) != CRYPT_OK) { - return errno; - } - - y += len; - - /* store the header */ - packet_store_header(out, PACKET_SECT_RSA, PACKET_SUB_ENCRYPTED, y); - -#ifdef CLEAN_STACK - /* clean up */ - zeromem(sym_key, sizeof(sym_key)); - zeromem(sym_IV, sizeof(sym_IV)); - zeromem(&ctr, sizeof(ctr)); - zeromem(rsa_in, sizeof(rsa_in)); - zeromem(rsa_out, sizeof(rsa_out)); -#endif - - *outlen = y; - return CRYPT_OK; -} - -int rsa_decrypt(const unsigned char *in, unsigned long len, - unsigned char *out, unsigned long *outlen, - rsa_key *key) -{ - unsigned char sym_IV[MAXBLOCKSIZE], sym_key[MAXBLOCKSIZE], rsa_in[4096], rsa_out[4096]; - symmetric_CTR ctr; - unsigned long x, y, z, keylen, blklen, rsa_size; - int cipher, errno; - - _ARGCHK(in != NULL); - _ARGCHK(out != NULL); - _ARGCHK(outlen != NULL); - _ARGCHK(key != NULL); - - /* right key type? */ - if (key->type != PK_PRIVATE && key->type != PK_PRIVATE_OPTIMIZED) { - return CRYPT_PK_NOT_PRIVATE; - } - - /* check the header */ - if ((errno = packet_valid_header((unsigned char *)in, PACKET_SECT_RSA, PACKET_SUB_ENCRYPTED)) != CRYPT_OK) { - return errno; - } - - /* grab cipher name */ - y = PACKET_SIZE; - cipher = find_cipher_id(in[y++]); - if (cipher == -1) { - return CRYPT_INVALID_CIPHER; - } - keylen = MIN(cipher_descriptor[cipher].max_key_length, 32); - blklen = cipher_descriptor[cipher].block_length; - - /* grab length of the rsa key */ - LOAD32L(rsa_size, (in+y)) - y += 4; - - /* read it in */ - for (x = 0; x < rsa_size; x++, y++) { - rsa_in[x] = in[y]; - } - - /* decrypt it */ - x = sizeof(rsa_out); - if ((errno = rsa_exptmod(rsa_in, rsa_size, rsa_out, &x, PK_PRIVATE, key)) != CRYPT_OK) { - return errno; - } - - /* depad it */ - z = sizeof(sym_key); - if ((errno = rsa_depad(rsa_out, x, sym_key, &z)) != CRYPT_OK) { - return errno; - } - - /* read the IV in */ - for (x = 0; x < blklen; x++, y++) { - sym_IV[x] = in[y]; - } - - /* setup CTR mode */ - if ((errno = ctr_start(cipher, sym_IV, sym_key, keylen, 0, &ctr)) != CRYPT_OK) { - return errno; - } - - /* get len */ - LOAD32L(len, (in+y)); - y += 4; - - /* check size */ - if (*outlen < len) { - return CRYPT_BUFFER_OVERFLOW; - } - - /* decrypt the message */ - if ((errno = ctr_decrypt(in+y, out, len, &ctr)) != CRYPT_OK) { - return errno; - } - -#ifdef CLEAN_STACK - /* clean up */ - zeromem(sym_key, sizeof(sym_key)); - zeromem(sym_IV, sizeof(sym_IV)); - zeromem(&ctr, sizeof(ctr)); - zeromem(rsa_in, sizeof(rsa_in)); - zeromem(rsa_out, sizeof(rsa_out)); -#endif - *outlen = len; - return CRYPT_OK; -} - -/* Signature Message Format -offset | length | Contents ----------------------------------------------------------------------- -0 | 1 | hash ID -1 | 4 | length of rsa_pad'ed signature -5 | p | the rsa_pad'ed signature -*/ - -int rsa_sign(const unsigned char *in, unsigned long inlen, - unsigned char *out, unsigned long *outlen, - int hash, rsa_key *key) -{ - unsigned long hashlen, rsa_size, x, y, z; - unsigned char rsa_in[4096], rsa_out[4096]; - int errno; - - _ARGCHK(in != NULL); - _ARGCHK(out != NULL); - _ARGCHK(outlen != NULL); - _ARGCHK(key != NULL); - - /* type of key? */ - if (key->type != PK_PRIVATE && key->type != PK_PRIVATE_OPTIMIZED) { - return CRYPT_PK_NOT_PRIVATE; - } - - /* are the parameters valid? */ - if ((errno = hash_is_valid(hash)) != CRYPT_OK) { - return errno; - } - - /* hash it */ - hashlen = hash_descriptor[hash].hashsize; - z = sizeof(rsa_in); - if ((errno = hash_memory(hash, in, inlen, rsa_in, &z)) != CRYPT_OK) { - return errno; - } - - /* pad it */ - x = sizeof(rsa_in); - if ((errno = rsa_signpad(rsa_in, hashlen, rsa_out, &x)) != CRYPT_OK) { - return errno; - } - - /* sign it */ - rsa_size = sizeof(rsa_in); - if ((errno = rsa_exptmod(rsa_out, x, rsa_in, &rsa_size, PK_PRIVATE, key)) != CRYPT_OK) { - return errno; - } - - /* check size */ - if (*outlen < (PACKET_SIZE+4+rsa_size)) { - return CRYPT_BUFFER_OVERFLOW; - } - - /* now lets output the message */ - y = PACKET_SIZE; - out[y++] = hash_descriptor[hash].ID; - - /* output the len */ - STORE32L(rsa_size, (out+y)); - y += 4; - - /* store the signature */ - for (x = 0; x < rsa_size; x++, y++) { - out[y] = rsa_in[x]; - } - - /* store header */ - packet_store_header(out, PACKET_SECT_RSA, PACKET_SUB_SIGNED, y); - -#ifdef CLEAN_STACK - /* clean up */ - zeromem(rsa_in, sizeof(rsa_in)); - zeromem(rsa_out, sizeof(rsa_out)); -#endif - *outlen = y; - return CRYPT_OK; -} - -int rsa_verify(const unsigned char *sig, const unsigned char *msg, - unsigned long inlen, int *stat, - rsa_key *key) -{ - unsigned long hashlen, rsa_size, x, y, z, w; - int hash, errno; - unsigned char rsa_in[4096], rsa_out[4096]; - - _ARGCHK(sig != NULL); - _ARGCHK(msg != NULL); - _ARGCHK(stat != NULL); - _ARGCHK(key != NULL); - - /* always be incorrect by default */ - *stat = 0; - - /* verify header */ - if ((errno = packet_valid_header((unsigned char *)sig, PACKET_SECT_RSA, PACKET_SUB_SIGNED)) != CRYPT_OK) { - return errno; - } - - /* grab hash name */ - y = PACKET_SIZE; - hash = find_hash_id(sig[y++]); - if (hash == -1) { - return CRYPT_INVALID_HASH; - } - hashlen = hash_descriptor[hash].hashsize; - - /* get the len */ - LOAD32L(rsa_size, (sig+y)); - y += 4; - - /* load the signature */ - for (x = 0; x < rsa_size; x++, y++) { - rsa_in[x] = sig[y]; - } - - /* exptmod it */ - x = sizeof(rsa_in); - if ((errno = rsa_exptmod(rsa_in, rsa_size, rsa_out, &x, PK_PUBLIC, key)) != CRYPT_OK) { - return errno; - } - - /* depad it */ - z = sizeof(rsa_in); - if ((errno = rsa_signdepad(rsa_out, x, rsa_in, &z)) != CRYPT_OK) { - return errno; - } - - /* check? */ - w = sizeof(rsa_out); - if ((errno = hash_memory(hash, msg, inlen, rsa_out, &w)) != CRYPT_OK) { - return errno; - } - - if ((z == hashlen) && (!memcmp(rsa_in, rsa_out, hashlen))) { - *stat = 1; - } - -#ifdef CLEAN_STACK - zeromem(rsa_in, sizeof(rsa_in)); - zeromem(rsa_out, sizeof(rsa_out)); -#endif - return CRYPT_OK; -} - -#endif - /* these are smaller routines written by Clay Culver. They do the same function as the rsa_encrypt/decrypt * except that they are used to RSA encrypt/decrypt a single value and not a packet. */ diff --git a/safer+.c b/safer+.c index 6c1086a..f2846a5 100644 --- a/safer+.c +++ b/safer+.c @@ -117,7 +117,7 @@ extern const unsigned char safer_ebox[], safer_lbox[]; iSHUF(b2, b); iPHT(b); \ iSHUF(b, b2); iPHT(b2); -#ifdef SAFERP_SMALL +#ifdef SMALL_CODE static void _round(unsigned char *b, int i, symmetric_key *skey) { diff --git a/xtea.c b/xtea.c index 38cb15c..969b650 100644 --- a/xtea.c +++ b/xtea.c @@ -133,7 +133,7 @@ int xtea_test(void) int xtea_keysize(int *desired_keysize) { - _ARGCHK(desired_keysize); + _ARGCHK(desired_keysize != NULL); if (*desired_keysize < 16) { return CRYPT_INVALID_KEYSIZE; } diff --git a/yarrow.c b/yarrow.c index 7ceab90..91db606 100644 --- a/yarrow.c +++ b/yarrow.c @@ -20,6 +20,8 @@ int yarrow_start(prng_state *prng) /* these are the default hash/cipher combo used */ #ifdef RIJNDAEL prng->yarrow.cipher = register_cipher(&rijndael_desc); +#elif defined(NOEKEON) + prng->yarrow.cipher = register_cipher(&noekeon_desc); #elif defined(BLOWFISH) prng->yarrow.cipher = register_cipher(&blowfish_desc); #elif defined(TWOFISH)