added libtomcrypt-0.78

This commit is contained in:
Tom St Denis 2003-03-03 01:01:40 +00:00 committed by Steffen Jaeckel
parent 5581d44fd4
commit 2ef59575df
27 changed files with 479 additions and 1621 deletions

16
aes.c
View File

@ -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)
{

14
changes
View File

@ -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.

18
crypt.c
View File

@ -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;
}
}

BIN
crypt.pdf

Binary file not shown.

220
crypt.tex
View File

@ -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}

View File

@ -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;
}

View File

@ -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));
}

20
dh.c
View File

@ -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;

431
dh_sys.c
View File

@ -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;

39
ecc.c
View File

@ -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,

491
ecc_sys.c
View File

@ -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;

View File

@ -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;
}
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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);

View File

@ -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,

210
noekeon.c Normal file
View File

@ -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

View File

@ -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.
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.

16
rsa.c
View File

@ -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"

347
rsa_sys.c
View File

@ -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.
*/

View File

@ -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)
{

2
xtea.c
View File

@ -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;
}

View File

@ -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)