added libtomcrypt-0.78
This commit is contained in:
parent
5581d44fd4
commit
2ef59575df
16
aes.c
16
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)
|
||||
{
|
||||
|
14
changes
14
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.
|
||||
|
18
crypt.c
18
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;
|
||||
}
|
||||
}
|
||||
|
220
crypt.tex
220
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}
|
||||
|
@ -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;
|
||||
}
|
||||
|
35
demos/test.c
35
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));
|
||||
}
|
||||
|
20
dh.c
20
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;
|
||||
|
431
dh_sys.c
431
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;
|
||||
|
39
ecc.c
39
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,
|
||||
|
491
ecc_sys.c
491
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;
|
||||
|
18
keyring.c
18
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;
|
||||
}
|
||||
}
|
||||
|
20
makefile
20
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
|
||||
|
25
makefile.ps2
25
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
|
||||
|
27
makefile.vc
27
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
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
71
mycrypt_pk.h
71
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,
|
||||
|
210
noekeon.c
Normal file
210
noekeon.c
Normal 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
|
||||
|
@ -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
16
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"
|
||||
|
347
rsa_sys.c
347
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.
|
||||
*/
|
||||
|
2
safer+.c
2
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)
|
||||
{
|
||||
|
2
xtea.c
2
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;
|
||||
}
|
||||
|
2
yarrow.c
2
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)
|
||||
|
Loading…
Reference in New Issue
Block a user