added libtomcrypt-0.98

This commit is contained in:
Tom St Denis 2004-08-06 16:42:41 +00:00 committed by Steffen Jaeckel
parent a21f63bbd8
commit 69f289d6dc
39 changed files with 1658 additions and 223 deletions

44
changes
View File

@ -1,3 +1,45 @@
August 6th, 2004
v0.98 -- Update to hmac_init to free all allocated memory on error
-- Update to PRNG API to fix import/export functions of Fortuna and Yarrow
-- Added test functions to PRNG api, RC4 now conforms ;-) [was a minor issue]
-- Added the SOBER-128 PRNG based off of code donated by Greg Rose.
-- Added Tech Note #4 [notes/tech0004.txt]
-- Changed RC4 back [due to request]. It will now XOR the output so you can use it like
a stream cipher easily.
-- Update Fortuna's export() to emit a hash of each pool. This means that the accumulated
entropy that was spread over all the pools isn't entirely lost when you export/import.
-- Zhi Chen suggested a comment for rsa_encrypt_key() to let users know [easily] that it was
PKCS #1 v2.0 padding. (updated other rsa_* functions)
-- Cleaned up Noekeon to remove unrolling [wasn't required, was messy and actually slower with GCC/ICC]
-- Updated RC4 so that when you feed it >256 bytes of entropy it quietly ignores additional
bytes. Also removed the % from the key setup to speed it up a bit.
-- Added cipher/hash/prng tests to x86_prof to help catch bugs while testing
-- Made the PRNG "done" return int, fixed sprng_done to not require prng* to be non-null
-- Spruced up mycrypt_custom.h to trap more errors and also help prevent LTMSSE from being defined
on non-i386 platforms by accident.
-- Added RSA/ECC/DH speed tests to x86_prof and cleaned it up to build with zero warnings
-- Changed Fortuna to count only entropy [not the 2 byte header] added to pool[0] into the
reseed mechanism.
-- Added "export_size" member to prng_descriptor tables so you can know in advance the size of
the exported state for any given PRNG.
-- Ported over patch on LTM 0.30 [not ready to release LTM 0.31] that fixes bug in mp_mul()/mp_div()
that used to result in negative zeroes when you multiplied zero by a negative integer.
(patch due to "Wolfgang Ehrhardt" <Wolfgang.Ehrhardt@munich.netsurf.de>)
-- Fixed rsa_*decrypt_key() and rsa_*verify_hash() to default to invalid "stat" or "res". This way
if any of the higher level functions fail [before you get to the padding] the result will be in
a known state]. Applied to both v2 and v1.5 padding helpers.
-- Added MACs to x86_prof
-- Fixed up "warnings" in x86_prof and tv_gen
-- Added a "profiled" target back [for GCC 3.4 and ICC v8]. Doesn't seem to help but might be worth
tinkering with.
-- Beefed up load/store test in demos/test
++ New note, in order to use the optimized LOAD/STORE macros your platform
must support unaligned 32/64 bit load/stores. The x86s support this
but some [ARM for instance] do not. If your platform cannot perform
unaligned operations you must use the endian neutral code which is safe for
any sort of platform.
July 23rd, 2004 July 23rd, 2004
v0.97b -- Added PKCS #1 v1.5 RSA encrypt/sign helpers (like rsa_sign_hash, etc...) v0.97b -- Added PKCS #1 v1.5 RSA encrypt/sign helpers (like rsa_sign_hash, etc...)
-- Added missing prng check to rsa_decrypt_key() [not critical as I don't use -- Added missing prng check to rsa_decrypt_key() [not critical as I don't use
@ -62,7 +104,7 @@ v0.96 -- Removed GF and Keyring code
-- Changed PSS/OAEP API slightly to be more consistent with other PK functions (order of arguments) -- Changed PSS/OAEP API slightly to be more consistent with other PK functions (order of arguments)
-- rsa_exptmod() now pads with leading zeroes as per I2OSP. -- rsa_exptmod() now pads with leading zeroes as per I2OSP.
-- added error checking to yarrow code -- added error checking to yarrow code
-- Mike Frysinger pointed out that tommath.h from this distro will overwrite tommath.h -- pointed out that tommath.h from this distro will overwrite tommath.h
from libtommath. I changed this to ltc_tommath.h to avoid any such problems. from libtommath. I changed this to ltc_tommath.h to avoid any such problems.
-- Fixed bug in PSS encoder/decoder that didn't handle the MSB properly -- Fixed bug in PSS encoder/decoder that didn't handle the MSB properly
-- refactored AES, now sports an "encrypt only" descriptor which uses half as much code space. -- refactored AES, now sports an "encrypt only" descriptor which uses half as much code space.

44
crypt.c
View File

@ -141,6 +141,26 @@ const char *crypt_build_settings =
" CTR\n" " CTR\n"
#endif #endif
"\nMACs:\n"
#if defined(HMAC)
" HMAC\n"
#endif
#if defined(OMAC)
" OMAC\n"
#endif
#if defined(PMAC)
" PMAC\n"
#endif
"\nENC + AUTH modes:\n"
#if defined(EAX_MODE)
" EAX_MODE\n"
#endif
#if defined(OCB_MODE)
" OCB_MODE\n"
#endif
"\nPRNG:\n" "\nPRNG:\n"
#if defined(YARROW) #if defined(YARROW)
" Yarrow\n" " Yarrow\n"
@ -151,6 +171,12 @@ const char *crypt_build_settings =
#if defined(RC4) #if defined(RC4)
" RC4\n" " RC4\n"
#endif #endif
#if defined(FORTUNA)
" Fortuna\n"
#endif
#if defined(SOBER128)
" SOBER128\n"
#endif
"\nPK Algs:\n" "\nPK Algs:\n"
#if defined(MRSA) #if defined(MRSA)
@ -197,21 +223,6 @@ const char *crypt_build_settings =
#if defined(MPI) #if defined(MPI)
" MPI " " MPI "
#endif #endif
#if defined(HMAC)
" HMAC "
#endif
#if defined(OMAC)
" OMAC "
#endif
#if defined(PMAC)
" PMAC "
#endif
#if defined(EAX_MODE)
" EAX_MODE "
#endif
#if defined(OCB_MODE)
" OCB_MODE "
#endif
#if defined(TRY_UNRANDOM_FIRST) #if defined(TRY_UNRANDOM_FIRST)
" TRY_UNRANDOM_FIRST " " TRY_UNRANDOM_FIRST "
#endif #endif
@ -229,6 +240,9 @@ const char *crypt_build_settings =
#endif #endif
#if defined(NO_FILE) #if defined(NO_FILE)
" NO_FILE " " NO_FILE "
#endif
#if defined(LTMSSE)
" LTMSSE "
#endif #endif
"\n" "\n"
"\n\n\n" "\n\n\n"

161
crypt.tex
View File

@ -47,7 +47,7 @@
\def\gap{\vspace{0.5ex}} \def\gap{\vspace{0.5ex}}
\makeindex \makeindex
\begin{document} \begin{document}
\title{LibTomCrypt \\ Version 0.97b} \title{LibTomCrypt \\ Version 0.98}
\author{Tom St Denis \\ \author{Tom St Denis \\
\\ \\
tomstdenis@iahu.ca \\ tomstdenis@iahu.ca \\
@ -1687,12 +1687,15 @@ int pmac_test(void);
Which returns {\bf CRYPT\_OK} if the code passes otherwise it returns an error code. Which returns {\bf CRYPT\_OK} if the code passes otherwise it returns an error code.
\chapter{Pseudo-Random Number Generators} \chapter{Pseudo-Random Number Generators}
\section{Core Functions} \section{Core Functions}
The library provides an array of core functions for Pseudo-Random Number Generators (PRNGs) as well. A cryptographic PRNG is The library provides an array of core functions for Pseudo-Random Number Generators (PRNGs) as well. A cryptographic PRNG is
used to expand a shorter bit string into a longer bit string. PRNGs are used wherever random data is required such as Public Key (PK) used to expand a shorter bit string into a longer bit string. PRNGs are used wherever random data is required such as Public Key (PK)
key generation. There is a universal structure called ``prng\_state''. To initialize a PRNG call: key generation. There is a universal structure called ``prng\_state''. To initialize a PRNG call:
\index{PRNG start}
\begin{verbatim} \begin{verbatim}
int XXX_start(prng_state *prng); int XXX_start(prng_state *prng);
\end{verbatim} \end{verbatim}
@ -1700,6 +1703,7 @@ int XXX_start(prng_state *prng);
This will setup the PRNG for future use and not seed it. In order This will setup the PRNG for future use and not seed it. In order
for the PRNG to be cryptographically useful you must give it entropy. Ideally you'd have some OS level source to tap for the PRNG to be cryptographically useful you must give it entropy. Ideally you'd have some OS level source to tap
like in UNIX (see section 5.3). To add entropy to the PRNG call: like in UNIX (see section 5.3). To add entropy to the PRNG call:
\index{PRNG add\_entropy}
\begin{verbatim} \begin{verbatim}
int XXX_add_entropy(const unsigned char *in, unsigned long len, int XXX_add_entropy(const unsigned char *in, unsigned long len,
prng_state *prng); prng_state *prng);
@ -1707,17 +1711,77 @@ int XXX_add_entropy(const unsigned char *in, unsigned long len,
Which returns {\bf CRYPTO\_OK} if the entropy was accepted. Once you think you have enough entropy you call another Which returns {\bf CRYPTO\_OK} if the entropy was accepted. Once you think you have enough entropy you call another
function to put the entropy into action. function to put the entropy into action.
\index{PRNG ready}
\begin{verbatim} \begin{verbatim}
int XXX_ready(prng_state *prng); int XXX_ready(prng_state *prng);
\end{verbatim} \end{verbatim}
Which returns {\bf CRYPTO\_OK} if it is ready. Finally to actually read bytes call: Which returns {\bf CRYPTO\_OK} if it is ready. Finally to actually read bytes call:
\index{PRNG read}
\begin{verbatim} \begin{verbatim}
unsigned long XXX_read(unsigned char *out, unsigned long len, unsigned long XXX_read(unsigned char *out, unsigned long len,
prng_state *prng); prng_state *prng);
\end{verbatim} \end{verbatim}
Which returns the number of bytes read from the PRNG. Which returns the number of bytes read from the PRNG. When you are finished with a PRNG state you call
the following.
\index{PRNG done}
\begin{verbatim}
void XXX_done(prng_state *prng);
\end{verbatim}
This will terminate a PRNG state and free any memory (if any) allocated. To export a PRNG state
so that you can later resume the PRNG call the following.
\index{PRNG export}
\begin{verbatim}
int XXX_export(unsigned char *out, unsigned long *outlen,
prng_state *prng);
\end{verbatim}
This will write a ``PRNG state'' to the buffer ``out'' of length ``outlen'' bytes. The idea of
the export is meant to be used as a ``seed file''. That is, when the program starts up there will not likely
be that much entropy available. To import a state to seed a PRNG call the following function.
\index{PRNG import}
\begin{verbatim}
int XXX_import(const unsigned char *in, unsigned long inlen,
prng_state *prng);
\end{verbatim}
This will call the start and add\_entropy functions of the given PRNG. It will use the state in
``in'' of length ``inlen'' as the initial seed. You must pass the same seed length as was exported
by the corresponding export function.
Note that importing a state will not ``resume'' the PRNG from where it left off. That is, if you export
a state, emit (say) 8 bytes and then import the previously exported state the next 8 bytes will not
specifically equal the 8 bytes you generated previously.
When a program is first executed the normal course of operation is
\begin{enumerate}
\item Gather entropy from your sources for a given period of time or number of events.
\item Start, use your entropy via add\_entropy and ready the PRNG yourself.
\end{enumerate}
When your program is finished you simply call the export function and save the state to a medium (disk,
flash memory, etc). The next time your application starts up you can detect the state, feed it to the
import function and go on your way. It is ideal that (as soon as possible) after startup you export a
fresh state. This helps in the case that the program aborts or the machine is powered down without
being given a chance to exit properly.
Note that even if you have a state to import it is important to add new entropy to the state. However,
there is less pressure to do so.
To test a PRNG for operational conformity call the following functions.
\index{PRNG test}
\begin{verbatim}
int XXX_test(void);
\end{verbatim}
This will return \textbf{CRYPT\_OK} if PRNG is operating properly.
\subsection{Remarks} \subsection{Remarks}
@ -1728,8 +1792,8 @@ checking is guaranteed to see if the entropy is sufficient or if the PRNG is eve
\subsection{Example} \subsection{Example}
Below is a simple snippet to read 10 bytes from yarrow. Its important to note that this snippet is {\bf NOT} secure since Below is a simple snippet to read 10 bytes from yarrow. Its important to note that this snippet is
the entropy added is not random. {\bf NOT} secure since the entropy added is not random.
\begin{verbatim} \begin{verbatim}
#include <mycrypt.h> #include <mycrypt.h>
@ -1762,10 +1826,15 @@ PRNGs have descriptors too (surprised?). Stored in the structure ``prng\_descrip
\begin{verbatim} \begin{verbatim}
struct _prng_descriptor { struct _prng_descriptor {
char *name; char *name;
int export_size; /* size in bytes of exported state */
int (*start) (prng_state *); int (*start) (prng_state *);
int (*add_entropy)(const unsigned char *, unsigned long, prng_state *); int (*add_entropy)(const unsigned char *, unsigned long, prng_state *);
int (*ready) (prng_state *); int (*ready) (prng_state *);
unsigned long (*read)(unsigned char *, unsigned long len, prng_state *); unsigned long (*read)(unsigned char *, unsigned long len, prng_state *);
void (*done)(prng_state *);
int (*export)(unsigned char *, unsigned long *, prng_state *);
int (*import)(const unsigned char *, unsigned long, prng_state *);
int (*test)(void);
}; };
\end{verbatim} \end{verbatim}
@ -1779,16 +1848,82 @@ int register_prng(const struct _prng_descriptor *prng);
int unregister_prng(const struct _prng_descriptor *prng); int unregister_prng(const struct _prng_descriptor *prng);
\end{verbatim} \end{verbatim}
\subsubsection{PRNGs Provided} \subsection{PRNGs Provided}
Currently Yarrow (yarrow\_desc), RC4 (rc4\_desc) and the secure RNG (sprng\_desc) are provided as PRNGs within the \begin{figure}[here]
library. \begin{center}
\begin{small}
\begin{tabular}{|c|c|l|}
\hline \textbf{Name} & \textbf{Descriptor} & \textbf{Usage} \\
\hline Yarrow & yarrow\_desc & Fast short-term PRNG \\
\hline Fortuna & fortuna\_desc & Fast long-term PRNG (recommended) \\
\hline RC4 & rc4\_desc & Stream Cipher \\
\hline SOBER-128 & sober128\_desc & Stream Cipher (also very fast PRNG) \\
\hline
\end{tabular}
\end{small}
\end{center}
\caption{List of Provided PRNGs}
\end{figure}
RC4 is provided with a PRNG interface because it is a stream cipher and not well suited for the symmetric block cipher \subsubsection{Yarrow}
interface. You provide the key for RC4 via the rc4\_add\_entropy() function. By calling rc4\_ready() the key will be used Yarrow is fast PRNG meant to collect an unspecified amount of entropy from sources
to setup the RC4 state for encryption or decryption. The rc4\_read() function has been modified from RC4 since it will (keyboard, mouse, interrupts, etc) and produce an unbounded string of random bytes.
XOR the output of the RC4 keystream generator against the input buffer you provide. The following snippet will demonstrate
how to encrypt a buffer with RC4:
\textit{Note:} This PRNG is still secure for most taskings but is no longer recommended. Users
should use Fortuna instead.
\subsubsection{Fortuna}
Fortuna is a fast attack tolerant and more thoroughly designed PRNG suitable for long term
usage. It is faster than the default implementation of Yarrow\footnote{Yarrow has been implemented
to work with most cipher and hash combos based on which you have chosen to build into the library.} while
providing more security.
Fortuna is slightly less flexible than Yarrow in the sense that it only works with the AES block cipher
and SHA--256 hash function. Technically Fortuna will work with any block cipher that accepts a 256--bit
key and any hash that produces at least a 256--bit output. However, to make the implementation simpler
it has been fixed to those choices.
Fortuna is more secure than Yarrow in the sense that attackers who learn parts of the entropy being
added to the PRNG learn far less about the state than that of Yarrow. Without getting into to many
details Fortuna has the ability to recover from state determination attacks where the attacker starts
to learn information from the PRNGs output about the internal state. Yarrow on the other hand cannot
recover from that problem until new entropy is added to the pool and put to use through the ready() function.
\subsubsection{RC4}
RC4 is an old stream cipher that can also double duty as a PRNG in a pinch. You ``key'' it by
calling add\_entropy() and setup the key by calling ready(). You can only add upto 256 bytes via
add\_entropy().
When you read from RC4 the output of the RC4 algorithm is XOR'd against your buffer you provide. In this
manner you can use rc4\_read() as an encrypt (and decrypt) function.
You really shouldn't use RC4 anymore. This isn't because RC4 is weak (though biases are known to exist) just
simply that faster alternatives exist.
\subsubsection{SOBER-128}
SOBER-128 is a stream cipher designed by the QUALCOMM Australia team. Like RC4 you ``key'' it by
calling add\_entropy(). There is no need to call ready() for this PRNG as it does not do anything.
Note that this cipher has several oddities about how it operates. The first time you call
add\_entropy() that sets the cipher's key. Every other time you call the same function it sets
the cipher's IV variable. The IV mechanism allows you to encrypt several messages with the same
key and not re--use the same key material.
Unlike Yarrow and Fortuna all of the entropy (and hence security) of this algorithm rests in the data
you pass it on the first call to add\_entropy(). All buffers sent to add\_entropy() must have a length
that is a multiple of four bytes.
Like RC4 the output of SOBER--128 is XOR'ed against the buffer you provide it. In this manner you can use
sober128\_read() as an encrypt (and decrypt) function.
Since SOBER-128 has a fixed keying scheme and is very fast (faster than RC4) the ideal usage of SOBER-128 is to
key it from the output of Fortuna (or Yarrow) and use it to encrypt messages. It is also ideal for
simulations which need a high quality (and fast) stream of bytes.
\subsubsection{Example Usage}
\begin{small} \begin{small}
\begin{verbatim} \begin{verbatim}
#include <mycrypt.h> #include <mycrypt.h>

View File

@ -5,6 +5,9 @@
int cipher_hash_test(void) int cipher_hash_test(void)
{ {
int x; int x;
unsigned char buf[4096];
unsigned long n;
prng_state nprng;
/* test ciphers */ /* test ciphers */
for (x = 0; cipher_descriptor[x].name != NULL; x++) { for (x = 0; cipher_descriptor[x].name != NULL; x++) {
@ -16,5 +19,23 @@ int cipher_hash_test(void)
DO(hash_descriptor[x].test()); DO(hash_descriptor[x].test());
} }
/* test prngs (test, import/export */
for (x = 0; prng_descriptor[x].name != NULL; x++) {
DO(prng_descriptor[x].test());
DO(prng_descriptor[x].start(&nprng));
DO(prng_descriptor[x].add_entropy("helloworld12", 12, &nprng));
DO(prng_descriptor[x].ready(&nprng));
n = sizeof(buf);
DO(prng_descriptor[x].export(buf, &n, &nprng));
prng_descriptor[x].done(&nprng);
DO(prng_descriptor[x].import(buf, n, &nprng));
DO(prng_descriptor[x].ready(&nprng));
if (prng_descriptor[x].read(buf, 100, &nprng) != 100) {
fprintf(stderr, "Error reading from imported PRNG!\n");
exit(EXIT_FAILURE);
}
prng_descriptor[x].done(&nprng);
}
return 0; return 0;
} }

View File

@ -1,43 +1,44 @@
#include "test.h" #include "test.h"
/* Test store/load macros with offsets */
int store_test(void) int store_test(void)
{ {
unsigned char buf[8]; unsigned char buf[24];
unsigned long L; unsigned long L, L1;
ulong64 LL; int y;
ulong64 LL, LL1;
L = 0x12345678UL; L = 0x12345678UL;
STORE32L (L, &buf[0]); for (y = 0; y < 4; y++) {
L = 0; STORE32L(L, buf + y);
LOAD32L (L, &buf[0]); LOAD32L(L1, buf + y);
if (L != 0x12345678UL) { if (L1 != L) {
printf ("LOAD/STORE32 Little don't work"); fprintf(stderr, "\n32L failed at offset %d\n", y);
return 1; return 1;
} }
LL = CONST64 (0x01020304050607); STORE32H(L, buf + y);
STORE64L (LL, &buf[0]); LOAD32H(L1, buf + y);
LL = 0; if (L1 != L) {
LOAD64L (LL, &buf[0]) fprintf(stderr, "\n32H failed at offset %d\n", y);
if (LL != CONST64 (0x01020304050607)) {
printf ("LOAD/STORE64 Little don't work");
return 1; return 1;
} }
}
L = 0x12345678UL;
STORE32H (L, &buf[0]);
L = 0;
LOAD32H (L, &buf[0]);
if (L != 0x12345678UL) {
printf ("LOAD/STORE32 High don't work, %08lx", L);
return 1;
}
LL = CONST64 (0x01020304050607); LL = CONST64 (0x01020304050607);
STORE64H (LL, &buf[0]); for (y = 0; y < 8; y++) {
LL = 0; STORE64L(LL, buf + y);
LOAD64H (LL, &buf[0]) LOAD64L(LL1, buf + y);
if (LL != CONST64 (0x01020304050607)) { if (LL1 != LL) {
printf ("LOAD/STORE64 High don't work"); fprintf(stderr, "\n64L failed at offset %d\n", y);
return 1; return 1;
} }
STORE64H(LL, buf + y);
LOAD64H(LL1, buf + y);
if (LL1 != LL) {
fprintf(stderr, "\n64H failed at offset %d\n", y);
return 1;
}
}
return 0; return 0;
} }

View File

@ -112,15 +112,21 @@ void register_algs(void)
register_hash (&whirlpool_desc); register_hash (&whirlpool_desc);
#endif #endif
if (register_prng(&yarrow_desc) == -1) { #ifdef YARROW
printf("Error registering yarrow PRNG\n"); register_prng(&yarrow_desc);
exit(-1); #endif
} #ifdef FORTUNA
register_prng(&fortuna_desc);
if (register_prng(&sprng_desc) == -1) { #endif
printf("Error registering sprng PRNG\n"); #ifdef RC4
exit(-1); register_prng(&rc4_desc);
} #endif
#ifdef SPRNG
register_prng(&sprng_desc);
#endif
#ifdef SOBER128
register_prng(&sober128_desc);
#endif
} }
/* sort tests based on their requirement/services. Helps make sure dependencies are tested first */ /* sort tests based on their requirement/services. Helps make sure dependencies are tested first */

View File

@ -203,7 +203,7 @@ void cipher_gen(void)
void hmac_gen(void) void hmac_gen(void)
{ {
unsigned char key[MAXBLOCKSIZE], output[MAXBLOCKSIZE], *input; unsigned char key[MAXBLOCKSIZE], output[MAXBLOCKSIZE], *input;
int x, y, z, kl, err; int x, y, z, err;
FILE *out; FILE *out;
unsigned long len; unsigned long len;

View File

@ -191,16 +191,26 @@ void reg_algs(void)
register_hash (&whirlpool_desc); register_hash (&whirlpool_desc);
#endif #endif
#ifndef YARROW
#error This demo requires Yarrow.
#endif
register_prng(&yarrow_desc); register_prng(&yarrow_desc);
#ifdef FORTUNA
register_prng(&fortuna_desc); register_prng(&fortuna_desc);
#endif
#ifdef RC4
register_prng(&rc4_desc); register_prng(&rc4_desc);
#endif
#ifdef SOBER128
register_prng(&sober128_desc);
#endif
rng_make_prng(128, find_prng("yarrow"), &prng, NULL); rng_make_prng(128, find_prng("yarrow"), &prng, NULL);
} }
int time_keysched(void) int time_keysched(void)
{ {
unsigned long x, i, y1; unsigned long x, y1;
ulong64 t1, c1; ulong64 t1, c1;
symmetric_key skey; symmetric_key skey;
int kl; int kl;
@ -241,7 +251,7 @@ int time_cipher(void)
symmetric_key skey; symmetric_key skey;
void (*func) (const unsigned char *, unsigned char *, symmetric_key *); void (*func) (const unsigned char *, unsigned char *, symmetric_key *);
unsigned char key[MAXBLOCKSIZE], pt[MAXBLOCKSIZE]; unsigned char key[MAXBLOCKSIZE], pt[MAXBLOCKSIZE];
int err;
printf ("\n\nECB Time Trials for the Symmetric Ciphers:\n"); printf ("\n\nECB Time Trials for the Symmetric Ciphers:\n");
no_results = 0; no_results = 0;
@ -249,6 +259,12 @@ int time_cipher(void)
cipher_descriptor[x].setup (key, cipher_descriptor[x].min_key_length, 0, cipher_descriptor[x].setup (key, cipher_descriptor[x].min_key_length, 0,
&skey); &skey);
/* sanity check on cipher */
if ((err = cipher_descriptor[x].test()) != CRYPT_OK) {
fprintf(stderr, "\n\nERROR: Cipher %s failed self-test %s\n", cipher_descriptor[x].name, error_to_string(err));
exit(EXIT_FAILURE);
}
#define DO1 func(pt,pt,&skey); #define DO1 func(pt,pt,&skey);
#define DO2 DO1 DO1 #define DO2 DO1 DO1
@ -303,13 +319,20 @@ int time_hash(void)
unsigned long x, y1, len; unsigned long x, y1, len;
ulong64 t1, t2, c1, c2; ulong64 t1, t2, c1, c2;
hash_state md; hash_state md;
int (*func)(hash_state *, const unsigned char *, unsigned long); int (*func)(hash_state *, const unsigned char *, unsigned long), err;
unsigned char pt[MAXBLOCKSIZE]; unsigned char pt[MAXBLOCKSIZE];
printf ("\n\nHASH Time Trials for:\n"); printf ("\n\nHASH Time Trials for:\n");
no_results = 0; no_results = 0;
for (x = 0; hash_descriptor[x].name != NULL; x++) { for (x = 0; hash_descriptor[x].name != NULL; x++) {
/* sanity check on hash */
if ((err = hash_descriptor[x].test()) != CRYPT_OK) {
fprintf(stderr, "\n\nERROR: Hash %s failed self-test %s\n", hash_descriptor[x].name, error_to_string(err));
exit(EXIT_FAILURE);
}
hash_descriptor[x].init(&md); hash_descriptor[x].init(&md);
#define DO1 func(&md,pt,len); #define DO1 func(&md,pt,len);
@ -365,7 +388,7 @@ void time_mult(void)
t1 = (t_read() - t1)>>1; t1 = (t_read() - t1)>>1;
if (t1 < t2) t2 = t1; if (t1 < t2) t2 = t1;
} }
printf("%3d digits: %9llu cycles\n", x, t2); printf("%3lu digits: %9llu cycles\n", x, t2);
} }
mp_clear_multi(&a,&b,&c,NULL); mp_clear_multi(&a,&b,&c,NULL);
@ -395,7 +418,7 @@ void time_sqr(void)
t1 = (t_read() - t1)>>1; t1 = (t_read() - t1)>>1;
if (t1 < t2) t2 = t1; if (t1 < t2) t2 = t1;
} }
printf("%3d digits: %9llu cycles\n", x, t2); printf("%3lu digits: %9llu cycles\n", x, t2);
} }
mp_clear_multi(&a,&b,NULL); mp_clear_multi(&a,&b,NULL);
@ -407,20 +430,27 @@ void time_prng(void)
{ {
ulong64 t1, t2; ulong64 t1, t2;
unsigned char buf[4096]; unsigned char buf[4096];
prng_state prng; prng_state tprng;
unsigned long x, y; unsigned long x, y;
int err;
printf("Timing PRNGs:\n"); printf("Timing PRNGs (cycles/byte output, cycles add_entropy (32 bytes) :\n");
for (x = 0; prng_descriptor[x].name != NULL; x++) { for (x = 0; prng_descriptor[x].name != NULL; x++) {
prng_descriptor[x].start(&prng);
/* sanity check on prng */
if ((err = prng_descriptor[x].test()) != CRYPT_OK) {
fprintf(stderr, "\n\nERROR: PRNG %s failed self-test %s\n", prng_descriptor[x].name, error_to_string(err));
exit(EXIT_FAILURE);
}
prng_descriptor[x].start(&tprng);
zeromem(buf, 256); zeromem(buf, 256);
prng_descriptor[x].add_entropy(buf, 256, &prng); prng_descriptor[x].add_entropy(buf, 256, &tprng);
prng_descriptor[x].ready(&prng); prng_descriptor[x].ready(&tprng);
t2 = -1; t2 = -1;
#define DO1 prng_descriptor[x].read(buf, 4096, &prng); #define DO1 if (prng_descriptor[x].read(buf, 4096, &tprng) != 4096) { printf("\n\nERROR READ != 4096\n\n"); exit(EXIT_FAILURE); }
#define DO2 DO1 DO1 #define DO2 DO1 DO1
for (y = 0; y < 10000; y++) { for (y = 0; y < 10000; y++) {
t_start(); t_start();
t1 = t_read(); t1 = t_read();
@ -428,14 +458,255 @@ void time_prng(void)
t1 = (t_read() - t1)>>1; t1 = (t_read() - t1)>>1;
if (t1 < t2) t2 = t1; if (t1 < t2) t2 = t1;
} }
printf("%20s: %llu\n", prng_descriptor[x].name, t2>>12); printf("%20s: %5llu ", prng_descriptor[x].name, t2>>12);
}
#undef DO2 #undef DO2
#undef DO1 #undef DO1
#define DO1 prng_descriptor[x].start(&tprng); prng_descriptor[x].add_entropy(buf, 32, &tprng); prng_descriptor[x].ready(&tprng); prng_descriptor[x].done(&tprng);
#define DO2 DO1 DO1
for (y = 0; y < 10000; y++) {
t_start();
t1 = t_read();
DO2;
t1 = (t_read() - t1)>>1;
if (t1 < t2) t2 = t1;
}
printf("%5llu\n", t2);
#undef DO2
#undef DO1
}
} }
/* time various RSA operations */
void time_rsa(void)
{
rsa_key key;
ulong64 t1, t2;
unsigned char buf[2][4096];
unsigned long x, y, z, zzz;
int err, zz;
for (x = 1024; x <= 2048; x += 512) {
t2 = 0;
for (y = 0; y < 16; y++) {
t_start();
t1 = t_read();
if ((err = rsa_make_key(&prng, find_prng("yarrow"), x/8, 65537, &key)) != CRYPT_OK) {
fprintf(stderr, "\n\nrsa_make_key says %s, wait...no it should say %s...damn you!\n", error_to_string(err), error_to_string(CRYPT_OK));
exit(EXIT_FAILURE);
}
t1 = t_read() - t1;
t2 += t1;
if (y < 15) {
rsa_free(&key);
}
}
t2 >>= 4;
printf("RSA-%lu make_key took %15llu cycles\n", x, t2);
t2 = 0;
for (y = 0; y < 16; y++) {
t_start();
t1 = t_read();
z = sizeof(buf[1]);
if ((err = rsa_encrypt_key(buf[0], 32, buf[1], &z, "testprog", 8, &prng,
find_prng("yarrow"), find_hash("sha1"),
&key)) != CRYPT_OK) {
fprintf(stderr, "\n\nrsa_encrypt_key says %s, wait...no it should say %s...damn you!\n", error_to_string(err), error_to_string(CRYPT_OK));
exit(EXIT_FAILURE);
}
t1 = t_read() - t1;
t2 += t1;
}
t2 >>= 4;
printf("RSA-%lu encrypt_key took %15llu cycles\n", x, t2);
t2 = 0;
for (y = 0; y < 16; y++) {
t_start();
t1 = t_read();
zzz = sizeof(buf[0]);
if ((err = rsa_decrypt_key(buf[1], z, buf[0], &zzz, "testprog", 8, &prng,
find_prng("yarrow"), find_hash("sha1"),
&zz, &key)) != CRYPT_OK) {
fprintf(stderr, "\n\nrsa_decrypt_key says %s, wait...no it should say %s...damn you!\n", error_to_string(err), error_to_string(CRYPT_OK));
exit(EXIT_FAILURE);
}
t1 = t_read() - t1;
t2 += t1;
}
t2 >>= 4;
printf("RSA-%lu decrypt_key took %15llu cycles\n", x, t2);
rsa_free(&key);
}
}
/* time various ECC operations */
void time_ecc(void)
{
ecc_key key;
ulong64 t1, t2;
unsigned char buf[2][4096];
unsigned long i, x, y, z;
int err;
static unsigned long sizes[] = {160/8, 256/8, 521/8, 100000};
for (x = sizes[i=0]; x < 100000; x = sizes[++i]) {
t2 = 0;
for (y = 0; y < 16; y++) {
t_start();
t1 = t_read();
if ((err = ecc_make_key(&prng, find_prng("yarrow"), x, &key)) != CRYPT_OK) {
fprintf(stderr, "\n\necc_make_key says %s, wait...no it should say %s...damn you!\n", error_to_string(err), error_to_string(CRYPT_OK));
exit(EXIT_FAILURE);
}
t1 = t_read() - t1;
t2 += t1;
if (y < 15) {
ecc_free(&key);
}
}
t2 >>= 4;
printf("ECC-%lu make_key took %15llu cycles\n", x*8, t2);
t2 = 0;
for (y = 0; y < 16; y++) {
t_start();
t1 = t_read();
z = sizeof(buf[1]);
if ((err = ecc_encrypt_key(buf[0], 20, buf[1], &z, &prng, find_prng("yarrow"), find_hash("sha1"),
&key)) != CRYPT_OK) {
fprintf(stderr, "\n\necc_encrypt_key says %s, wait...no it should say %s...damn you!\n", error_to_string(err), error_to_string(CRYPT_OK));
exit(EXIT_FAILURE);
}
t1 = t_read() - t1;
t2 += t1;
}
t2 >>= 4;
printf("ECC-%lu encrypt_key took %15llu cycles\n", x*8, t2);
ecc_free(&key);
}
}
/* time various DH operations */
void time_dh(void)
{
dh_key key;
ulong64 t1, t2;
unsigned char buf[2][4096];
unsigned long i, x, y, z;
int err;
static unsigned long sizes[] = {768/8, 1024/8, 1536/8, 2048/8, 3072/8, 4096/8, 100000};
for (x = sizes[i=0]; x < 100000; x = sizes[++i]) {
t2 = 0;
for (y = 0; y < 16; y++) {
t_start();
t1 = t_read();
if ((err = dh_make_key(&prng, find_prng("yarrow"), x, &key)) != CRYPT_OK) {
fprintf(stderr, "\n\ndh_make_key says %s, wait...no it should say %s...damn you!\n", error_to_string(err), error_to_string(CRYPT_OK));
exit(EXIT_FAILURE);
}
t1 = t_read() - t1;
t2 += t1;
if (y < 15) {
dh_free(&key);
}
}
t2 >>= 4;
printf("DH-%4lu make_key took %15llu cycles\n", x*8, t2);
t2 = 0;
for (y = 0; y < 16; y++) {
t_start();
t1 = t_read();
z = sizeof(buf[1]);
if ((err = dh_encrypt_key(buf[0], 20, buf[1], &z, &prng, find_prng("yarrow"), find_hash("sha1"),
&key)) != CRYPT_OK) {
fprintf(stderr, "\n\ndh_encrypt_key says %s, wait...no it should say %s...damn you!\n", error_to_string(err), error_to_string(CRYPT_OK));
exit(EXIT_FAILURE);
}
t1 = t_read() - t1;
t2 += t1;
}
t2 >>= 4;
printf("DH-%4lu encrypt_key took %15llu cycles\n", x*8, t2);
dh_free(&key);
}
}
#define MAC_SIZE 32
void time_macs(void)
{
unsigned char *buf, key[16], tag[16];
ulong64 t1, t2;
unsigned long x, z;
int err, cipher_idx, hash_idx;
printf("\nMAC Timings (cycles/byte on %dKB blocks):\n", MAC_SIZE);
buf = XMALLOC(MAC_SIZE*1024);
if (buf == NULL) {
fprintf(stderr, "\n\nout of heap yo\n\n");
exit(EXIT_FAILURE);
}
cipher_idx = find_cipher("aes");
hash_idx = find_hash("md5");
yarrow_read(buf, MAC_SIZE*1024, &prng);
yarrow_read(key, 16, &prng);
t2 = -1;
for (x = 0; x < 10000; x++) {
t_start();
t1 = t_read();
z = 16;
if ((err = omac_memory(cipher_idx, key, 16, buf, MAC_SIZE*1024, tag, &z)) != CRYPT_OK) {
fprintf(stderr, "\n\nomac error... %s\n", error_to_string(err));
exit(EXIT_FAILURE);
}
t1 = t_read() - t1;
if (t1 < t2) t2 = t1;
}
printf("OMAC-AES\t\t%9llu\n", t2/(MAC_SIZE*1024));
t2 = -1;
for (x = 0; x < 10000; x++) {
t_start();
t1 = t_read();
z = 16;
if ((err = pmac_memory(cipher_idx, key, 16, buf, MAC_SIZE*1024, tag, &z)) != CRYPT_OK) {
fprintf(stderr, "\n\npmac error... %s\n", error_to_string(err));
exit(EXIT_FAILURE);
}
t1 = t_read() - t1;
if (t1 < t2) t2 = t1;
}
printf("PMAC-AES\t\t%9llu\n", t2/(MAC_SIZE*1024));
t2 = -1;
for (x = 0; x < 10000; x++) {
t_start();
t1 = t_read();
z = 16;
if ((err = hmac_memory(hash_idx, key, 16, buf, MAC_SIZE*1024, tag, &z)) != CRYPT_OK) {
fprintf(stderr, "\n\nhmac error... %s\n", error_to_string(err));
exit(EXIT_FAILURE);
}
t1 = t_read() - t1;
if (t1 < t2) t2 = t1;
}
printf("HMAC-MD5\t\t%9llu\n", t2/(MAC_SIZE*1024));
XFREE(buf);
}
int main(void) int main(void)
{ {
@ -446,10 +717,14 @@ int main(void)
// init_timer(); // init_timer();
time_mult(); time_mult();
time_sqr(); time_sqr();
time_rsa();
time_dh();
time_ecc();
time_prng(); time_prng();
time_cipher(); time_cipher();
time_keysched(); time_keysched();
time_hash(); time_hash();
time_macs();
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }

Binary file not shown.

133
fortuna.c
View File

@ -19,16 +19,30 @@ we reseed automatically when len(pool0) >= 64 or every FORTUNA_WD calls to the r
#ifdef FORTUNA #ifdef FORTUNA
/* requries SHA256 and AES */
#if !(defined(RIJNDAEL) && defined(SHA256))
#error FORTUNA requires SHA256 and RIJNDAEL (AES)
#endif
#ifndef FORTUNA_POOLS
#warning FORTUNA_POOLS was not previously defined (old headers?)
#define FORTUNA_POOLS 32
#endif
#if FORTUNA_POOLS < 4 || FORTUNA_POOLS > 32
#error FORTUNA_POOLS must be in [4..32]
#endif
const struct _prng_descriptor fortuna_desc = { const struct _prng_descriptor fortuna_desc = {
"fortuna", "fortuna", 1024,
&fortuna_start, &fortuna_start,
&fortuna_add_entropy, &fortuna_add_entropy,
&fortuna_ready, &fortuna_ready,
&fortuna_read, &fortuna_read,
&fortuna_done, &fortuna_done,
&fortuna_export, &fortuna_export,
&fortuna_import &fortuna_import,
&fortuna_test
}; };
/* update the IV */ /* update the IV */
@ -47,7 +61,7 @@ static void fortuna_update_iv(prng_state *prng)
/* reseed the PRNG */ /* reseed the PRNG */
static int fortuna_reseed(prng_state *prng) static int fortuna_reseed(prng_state *prng)
{ {
unsigned char tmp[32]; unsigned char tmp[MAXBLOCKSIZE];
hash_state md; hash_state md;
int err, x; int err, x;
@ -59,7 +73,7 @@ static int fortuna_reseed(prng_state *prng)
return err; return err;
} }
for (x = 0; x < 32; x++) { for (x = 0; x < FORTUNA_POOLS; x++) {
if (x == 0 || ((prng->fortuna.reset_cnt >> (x-1)) & 1) == 0) { if (x == 0 || ((prng->fortuna.reset_cnt >> (x-1)) & 1) == 0) {
/* terminate this hash */ /* terminate this hash */
if ((err = sha256_done(&prng->fortuna.pool[x], tmp)) != CRYPT_OK) { if ((err = sha256_done(&prng->fortuna.pool[x], tmp)) != CRYPT_OK) {
@ -105,7 +119,7 @@ int fortuna_start(prng_state *prng)
_ARGCHK(prng != NULL); _ARGCHK(prng != NULL);
/* initialize the pools */ /* initialize the pools */
for (x = 0; x < 32; x++) { for (x = 0; x < FORTUNA_POOLS; x++) {
sha256_init(&prng->fortuna.pool[x]); sha256_init(&prng->fortuna.pool[x]);
} }
prng->fortuna.pool_idx = prng->fortuna.pool0_len = prng->fortuna.reset_cnt = prng->fortuna.pool_idx = prng->fortuna.pool0_len = prng->fortuna.reset_cnt =
@ -144,9 +158,11 @@ int fortuna_add_entropy(const unsigned char *buf, unsigned long len, prng_state
return err; return err;
} }
if (prng->fortuna.pool_idx == 0) { if (prng->fortuna.pool_idx == 0) {
prng->fortuna.pool0_len += len + 2; prng->fortuna.pool0_len += len;
}
if (++(prng->fortuna.pool_idx) == FORTUNA_POOLS) {
prng->fortuna.pool_idx = 0;
} }
prng->fortuna.pool_idx = (prng->fortuna.pool_idx + 1) & 31;
return CRYPT_OK; return CRYPT_OK;
} }
@ -160,7 +176,7 @@ unsigned long fortuna_read(unsigned char *dst, unsigned long len, prng_state *pr
{ {
unsigned char tmp[16]; unsigned char tmp[16];
int err; int err;
unsigned long tlen, n; unsigned long tlen;
_ARGCHK(dst != NULL); _ARGCHK(dst != NULL);
_ARGCHK(prng != NULL); _ARGCHK(prng != NULL);
@ -174,17 +190,20 @@ unsigned long fortuna_read(unsigned char *dst, unsigned long len, prng_state *pr
/* now generate the blocks required */ /* now generate the blocks required */
tlen = len; tlen = len;
while (len > 0) {
if (len >= 16) { /* handle whole blocks without the extra memcpy */
while (len >= 16) {
/* encrypt the IV and store it */ /* encrypt the IV and store it */
rijndael_ecb_encrypt(prng->fortuna.IV, dst, &prng->fortuna.skey); rijndael_ecb_encrypt(prng->fortuna.IV, dst, &prng->fortuna.skey);
dst += 16; dst += 16;
len -= 16; len -= 16;
} else { fortuna_update_iv(prng);
}
/* left over bytes? */
if (len > 0) {
rijndael_ecb_encrypt(prng->fortuna.IV, tmp, &prng->fortuna.skey); rijndael_ecb_encrypt(prng->fortuna.IV, tmp, &prng->fortuna.skey);
XMEMCPY(dst, tmp, len); XMEMCPY(dst, tmp, len);
len = 0;
}
fortuna_update_iv(prng); fortuna_update_iv(prng);
} }
@ -201,33 +220,77 @@ unsigned long fortuna_read(unsigned char *dst, unsigned long len, prng_state *pr
return tlen; return tlen;
} }
void fortuna_done(prng_state *prng) int fortuna_done(prng_state *prng)
{ {
int err, x;
unsigned char tmp[32];
_ARGCHK(prng != NULL); _ARGCHK(prng != NULL);
/* terminate all the hashes */
for (x = 0; x < FORTUNA_POOLS; x++) {
if ((err = sha256_done(&(prng->fortuna.pool[x]), tmp)) != CRYPT_OK) {
return err;
}
}
/* call cipher done when we invent one ;-) */ /* call cipher done when we invent one ;-) */
#ifdef CLEAN_STACK
zeromem(tmp, sizeof(tmp));
#endif
return CRYPT_OK;
} }
int fortuna_export(unsigned char *out, unsigned long *outlen, prng_state *prng) int fortuna_export(unsigned char *out, unsigned long *outlen, prng_state *prng)
{ {
int x; int x, err;
hash_state *md;
_ARGCHK(out != NULL); _ARGCHK(out != NULL);
_ARGCHK(outlen != NULL); _ARGCHK(outlen != NULL);
_ARGCHK(prng != NULL); _ARGCHK(prng != NULL);
/* we'll write 2048 bytes for s&g's */ /* we'll write bytes for s&g's */
if (*outlen < 2048) { if (*outlen < 32*FORTUNA_POOLS) {
return CRYPT_BUFFER_OVERFLOW; return CRYPT_BUFFER_OVERFLOW;
} }
for (x = 0; x < 32; x++) { md = XMALLOC(sizeof(hash_state));
if (fortuna_read(out+x*64, 64, prng) != 64) { if (md == NULL) {
return CRYPT_ERROR_READPRNG; return CRYPT_MEM;
} }
}
*outlen = 2048;
return CRYPT_OK; /* to emit the state we copy each pool, terminate it then hash it again so
* an attacker who sees the state can't determine the current state of the PRNG
*/
for (x = 0; x < FORTUNA_POOLS; x++) {
/* copy the PRNG */
XMEMCPY(md, &(prng->fortuna.pool[x]), sizeof(*md));
/* terminate it */
if ((err = sha256_done(md, out+x*32)) != CRYPT_OK) {
goto __ERR;
}
/* now hash it */
sha256_init(md);
if ((err = sha256_process(md, out+x*32, 32)) != CRYPT_OK) {
goto __ERR;
}
if ((err = sha256_done(md, out+x*32)) != CRYPT_OK) {
goto __ERR;
}
}
*outlen = 32*FORTUNA_POOLS;
err = CRYPT_OK;
__ERR:
#ifdef CLEAN_STACK
zeromem(md, sizeof(*md));
#endif
XFREE(md);
return err;
} }
int fortuna_import(const unsigned char *in, unsigned long inlen, prng_state *prng) int fortuna_import(const unsigned char *in, unsigned long inlen, prng_state *prng)
@ -237,19 +300,33 @@ int fortuna_import(const unsigned char *in, unsigned long inlen, prng_state *prn
_ARGCHK(in != NULL); _ARGCHK(in != NULL);
_ARGCHK(prng != NULL); _ARGCHK(prng != NULL);
if (inlen != 2048) { if (inlen != 32*FORTUNA_POOLS) {
return CRYPT_INVALID_ARG; return CRYPT_INVALID_ARG;
} }
if ((err = fortuna_start(prng)) != CRYPT_OK) { if ((err = fortuna_start(prng)) != CRYPT_OK) {
return err; return err;
} }
for (x = 0; x < 32; x++) { for (x = 0; x < FORTUNA_POOLS; x++) {
if ((err = fortuna_add_entropy(in+x*64, 64, &prng)) != CRYPT_OK) { if ((err = fortuna_add_entropy(in+x*32, 32, prng)) != CRYPT_OK) {
return err; return err;
} }
} }
return fortuna_ready(&prng); return err;
}
int fortuna_test(void)
{
#ifndef LTC_TEST
return CRYPT_NOP;
#else
int err;
if ((err = sha256_test()) != CRYPT_OK) {
return err;
}
return rijndael_test();
#endif
} }
#endif #endif

View File

@ -64,17 +64,17 @@ int hmac_done(hmac_state *hmac, unsigned char *hashOut, unsigned long *outlen)
return CRYPT_MEM; return CRYPT_MEM;
} }
// Get the hash of the first HMAC vector plus the data /* Get the hash of the first HMAC vector plus the data */
if ((err = hash_descriptor[hash].done(&hmac->md, isha)) != CRYPT_OK) { if ((err = hash_descriptor[hash].done(&hmac->md, isha)) != CRYPT_OK) {
goto __ERR; goto __ERR;
} }
// Create the second HMAC vector vector for step (3) /* Create the second HMAC vector vector for step (3) */
for(i=0; i < HMAC_BLOCKSIZE; i++) { for(i=0; i < HMAC_BLOCKSIZE; i++) {
buf[i] = hmac->key[i] ^ 0x5C; buf[i] = hmac->key[i] ^ 0x5C;
} }
// Now calculate the "outer" hash for step (5), (6), and (7) /* Now calculate the "outer" hash for step (5), (6), and (7) */
hash_descriptor[hash].init(&hmac->md); hash_descriptor[hash].init(&hmac->md);
if ((err = hash_descriptor[hash].process(&hmac->md, buf, HMAC_BLOCKSIZE)) != CRYPT_OK) { if ((err = hash_descriptor[hash].process(&hmac->md, buf, HMAC_BLOCKSIZE)) != CRYPT_OK) {
goto __ERR; goto __ERR;
@ -86,7 +86,7 @@ int hmac_done(hmac_state *hmac, unsigned char *hashOut, unsigned long *outlen)
goto __ERR; goto __ERR;
} }
// copy to output /* copy to output */
for (i = 0; i < hashsize && i < *outlen; i++) { for (i = 0; i < hashsize && i < *outlen; i++) {
hashOut[i] = buf[i]; hashOut[i] = buf[i];
} }

View File

@ -68,9 +68,9 @@ int hmac_init(hmac_state *hmac, int hash, const unsigned char *key, unsigned lon
return CRYPT_MEM; return CRYPT_MEM;
} }
// (1) make sure we have a large enough key /* (1) make sure we have a large enough key */
if(keylen > HMAC_BLOCKSIZE) { if(keylen > HMAC_BLOCKSIZE) {
z = (unsigned long)HMAC_BLOCKSIZE; z = HMAC_BLOCKSIZE;
if ((err = hash_memory(hash, key, keylen, hmac->key, &z)) != CRYPT_OK) { if ((err = hash_memory(hash, key, keylen, hmac->key, &z)) != CRYPT_OK) {
goto __ERR; goto __ERR;
} }
@ -85,15 +85,21 @@ int hmac_init(hmac_state *hmac, int hash, const unsigned char *key, unsigned lon
} }
} }
// Create the initial vector for step (3) /* Create the initial vector for step (3) */
for(i=0; i < HMAC_BLOCKSIZE; i++) { for(i=0; i < HMAC_BLOCKSIZE; i++) {
buf[i] = hmac->key[i] ^ 0x36; buf[i] = hmac->key[i] ^ 0x36;
} }
// Pre-pend that to the hash data /* Pre-pend that to the hash data */
hash_descriptor[hash].init(&hmac->md); hash_descriptor[hash].init(&hmac->md);
err = hash_descriptor[hash].process(&hmac->md, buf, HMAC_BLOCKSIZE); if ((err = hash_descriptor[hash].process(&hmac->md, buf, HMAC_BLOCKSIZE)) != CRYPT_OK) {
goto __ERR;
}
goto done;
__ERR: __ERR:
/* free the key since we failed */
XFREE(hmac->key);
done:
#ifdef CLEAN_STACK #ifdef CLEAN_STACK
zeromem(buf, HMAC_BLOCKSIZE); zeromem(buf, HMAC_BLOCKSIZE);
#endif #endif

View File

@ -291,6 +291,7 @@ Key First"
} }
if(memcmp(digest, cases[i].digest, (size_t)hash_descriptor[hash].hashsize) != 0) { if(memcmp(digest, cases[i].digest, (size_t)hash_descriptor[hash].hashsize) != 0) {
failed++;
#if 0 #if 0
unsigned int j; unsigned int j;
printf("\nHMAC-%s test #%d:\n", cases[i].algo, cases[i].num); printf("\nHMAC-%s test #%d:\n", cases[i].algo, cases[i].num);
@ -303,9 +304,8 @@ Key First"
printf("%2x ", cases[i].digest[j]); printf("%2x ", cases[i].digest[j]);
} }
printf("\n"); printf("\n");
return CRYPT_ERROR;
#endif #endif
failed++;
//return CRYPT_ERROR;
} else { } else {
/* printf("HMAC-%s test #%d: Passed\n", cases[i].algo, cases[i].num); */ /* printf("HMAC-%s test #%d: Passed\n", cases[i].algo, cases[i].num); */
} }

View File

@ -4,7 +4,7 @@
# Modified by Clay Culver # Modified by Clay Culver
# The version # The version
VERSION=0.97b VERSION=0.98
# Compiler and Linker Names # Compiler and Linker Names
#CC=gcc #CC=gcc
@ -63,7 +63,7 @@ crypt_find_cipher_id.o crypt_find_prng.o crypt_prng_is_valid.o \
crypt_unregister_cipher.o crypt_cipher_is_valid.o crypt_find_hash.o \ crypt_unregister_cipher.o crypt_cipher_is_valid.o crypt_find_hash.o \
crypt_hash_descriptor.o crypt_register_cipher.o crypt_unregister_hash.o \ crypt_hash_descriptor.o crypt_register_cipher.o crypt_unregister_hash.o \
\ \
fortuna.o sprng.o yarrow.o rc4.o rng_get_bytes.o rng_make_prng.o \ sober128.o fortuna.o sprng.o yarrow.o rc4.o rng_get_bytes.o rng_make_prng.o \
\ \
rand_prime.o is_prime.o \ rand_prime.o is_prime.o \
\ \
@ -171,10 +171,10 @@ small: library $(SMALLOBJECTS)
$(CC) $(SMALLOBJECTS) $(LIBNAME) -o $(SMALL) $(WARN) $(CC) $(SMALLOBJECTS) $(LIBNAME) -o $(SMALL) $(WARN)
x86_prof: library $(PROFS) x86_prof: library $(PROFS)
$(CC) $(PROFS) $(LIBNAME) -o $(PROF) $(CC) $(PROFS) $(LIBNAME) $(EXTRALIBS) -o $(PROF)
tv_gen: library $(TVS) tv_gen: library $(TVS)
$(CC) $(TVS) $(LIBNAME) -o $(TV) $(CC) $(TVS) $(LIBNAME) $(EXTRALIBS) -o $(TV)
#This rule installs the library and the header files. This must be run #This rule installs the library and the header files. This must be run
#as root in order to have a high enough permission to write to the correct #as root in order to have a high enough permission to write to the correct
@ -215,13 +215,21 @@ docdvi: crypt.tex
echo hello > crypt.ind echo hello > crypt.ind
latex crypt > /dev/null latex crypt > /dev/null
latex crypt > /dev/null latex crypt > /dev/null
makeindex.idx crypt makeindex crypt.idx
latex crypt > /dev/null latex crypt > /dev/null
#pretty build #pretty build
pretty: pretty:
perl pretty.build perl pretty.build
#for GCC 3.4+
profiled:
make clean
make CFLAGS="$(CFLAGS) -fprofile-generate" EXTRALIBS=-lgcov x86_prof
./x86_prof
rm *.o *.a x86_prof
make CFLAGS="$(CFLAGS) -fprofile-use" EXTRALIBS=-lgcov x86_prof
#beta #beta
beta: clean beta: clean
cd .. ; rm -rf crypt* libtomcrypt-$(VERSION)-beta ; mkdir libtomcrypt-$(VERSION)-beta ; \ cd .. ; rm -rf crypt* libtomcrypt-$(VERSION)-beta ; mkdir libtomcrypt-$(VERSION)-beta ; \

View File

@ -28,7 +28,7 @@ crypt_find_cipher_id.o crypt_find_prng.o crypt_prng_is_valid.o \
crypt_unregister_cipher.o crypt_cipher_is_valid.o crypt_find_hash.o \ crypt_unregister_cipher.o crypt_cipher_is_valid.o crypt_find_hash.o \
crypt_hash_descriptor.o crypt_register_cipher.o crypt_unregister_hash.o \ crypt_hash_descriptor.o crypt_register_cipher.o crypt_unregister_hash.o \
\ \
sprng.o fortuna.o yarrow.o rc4.o rng_get_bytes.o rng_make_prng.o \ sprng.o fortuna.o sober128.o yarrow.o rc4.o rng_get_bytes.o rng_make_prng.o \
\ \
rand_prime.o is_prime.o \ rand_prime.o is_prime.o \
\ \

View File

@ -79,7 +79,7 @@ crypt_find_cipher_id.o crypt_find_prng.o crypt_prng_is_valid.o \
crypt_unregister_cipher.o crypt_cipher_is_valid.o crypt_find_hash.o \ crypt_unregister_cipher.o crypt_cipher_is_valid.o crypt_find_hash.o \
crypt_hash_descriptor.o crypt_register_cipher.o crypt_unregister_hash.o \ crypt_hash_descriptor.o crypt_register_cipher.o crypt_unregister_hash.o \
\ \
sprng.o fortuna.o yarrow.o rc4.o rng_get_bytes.o rng_make_prng.o \ sober128.o fortuna.o sprng.o yarrow.o rc4.o rng_get_bytes.o rng_make_prng.o \
\ \
rand_prime.o is_prime.o \ rand_prime.o is_prime.o \
\ \
@ -188,6 +188,13 @@ x86_prof: library $(PROFS)
tv_gen: library $(TVS) tv_gen: library $(TVS)
$(CC) $(TVS) $(LIBNAME) -o $(TV) $(CC) $(TVS) $(LIBNAME) -o $(TV)
profiled:
make clean
make CFLAGS="$(CFLAGS) -prof_gen" x86_prof
./x86_prof
rm *.o *.a x86_prof
make CFLAGS="$(CFLAGS) -prof_use" x86_prof
#This rule installs the library and the header files. This must be run #This rule installs the library and the header files. This must be run
#as root in order to have a high enough permission to write to the correct #as root in order to have a high enough permission to write to the correct

View File

@ -18,7 +18,7 @@ crypt_find_cipher_id.obj crypt_find_prng.obj crypt_prng_is_valid.obj
crypt_unregister_cipher.obj crypt_cipher_is_valid.obj crypt_find_hash.obj \ crypt_unregister_cipher.obj crypt_cipher_is_valid.obj crypt_find_hash.obj \
crypt_hash_descriptor.obj crypt_register_cipher.obj crypt_unregister_hash.obj \ crypt_hash_descriptor.obj crypt_register_cipher.obj crypt_unregister_hash.obj \
\ \
sprng.obj fortuna.obj yarrow.obj rc4.obj rng_get_bytes.obj rng_make_prng.obj \ sprng.obj fortuna.obj sober128.obj yarrow.obj rc4.obj rng_get_bytes.obj rng_make_prng.obj \
\ \
rand_prime.obj is_prime.obj \ rand_prime.obj is_prime.obj \
\ \

2
mpi.c
View File

@ -4703,7 +4703,7 @@ int mp_mul (mp_int * a, mp_int * b, mp_int * c)
res = s_mp_mul (a, b, c); res = s_mp_mul (a, b, c);
} }
} }
c->sign = neg; c->sign = (c->used == 0) ? MP_ZPOS : neg;
return res; return res;
} }

View File

@ -1,6 +1,4 @@
/* Defines the _ARGCHK macro used within the library */ /* Defines the _ARGCHK macro used within the library */
/* ch1-01-1 */
/* ARGTYPE is defined in mycrypt_cfg.h */ /* ARGTYPE is defined in mycrypt_cfg.h */
#if ARGTYPE == 0 #if ARGTYPE == 0
@ -20,5 +18,4 @@
#define _ARGCHK(x) #define _ARGCHK(x)
#endif #endif
/* ch1-01-1 */

View File

@ -20,12 +20,16 @@ void XFREE(void *p);
void *XMEMCPY(void *dest, const void *src, size_t n); void *XMEMCPY(void *dest, const void *src, size_t n);
int XMEMCMP(const void *s1, const void *s2, size_t n); int XMEMCMP(const void *s1, const void *s2, size_t n);
/* ch1-01-1 */
/* type of argument checking, 0=default, 1=fatal and 2=none */ /* type of argument checking, 0=default, 1=fatal and 2=none */
#define ARGTYPE 0 #define ARGTYPE 0
/* ch1-01-1 */
/* Controls endianess and size of registers. Leave uncommented to get platform neutral [slower] code */ /* Controls endianess and size of registers. Leave uncommented to get platform neutral [slower] code
*
* Note: in order to use the optimized macros your platform must support unaligned 32 and 64 bit read/writes.
* The x86 platforms allow this but some others [ARM for instance] do not. On those platforms you **MUST**
* use the portable [slower] macros.
*/
/* detect x86-32 machines somewhat */ /* detect x86-32 machines somewhat */
#if defined(INTEL_CC) || (defined(_MSC_VER) && defined(WIN32)) || (defined(__GNUC__) && (defined(__DJGPP__) || defined(__CYGWIN__) || defined(__MINGW32__) || defined(__i386__))) #if defined(INTEL_CC) || (defined(_MSC_VER) && defined(WIN32)) || (defined(__GNUC__) && (defined(__DJGPP__) || defined(__CYGWIN__) || defined(__MINGW32__) || defined(__i386__)))
#define ENDIAN_LITTLE #define ENDIAN_LITTLE
@ -52,12 +56,6 @@ int XMEMCMP(const void *s1, const void *s2, size_t n);
#define ENDIAN_NEUTRAL #define ENDIAN_NEUTRAL
#endif #endif
#ifdef YARROW
#ifndef CTR
#error YARROW requires CTR chaining mode to be defined!
#endif
#endif
/* packet code */ /* packet code */
#if defined(MRSA) || defined(MDH) || defined(MECC) #if defined(MRSA) || defined(MDH) || defined(MECC)
#define PACKET #define PACKET

View File

@ -82,18 +82,29 @@
/* Various tidbits of modern neatoness */ /* Various tidbits of modern neatoness */
#define BASE64 #define BASE64
/* Yarrow */
#define YARROW #define YARROW
// which descriptor of AES to use? // which descriptor of AES to use?
// 0 = rijndael_enc 1 = aes_enc, 2 = rijndael [full], 3 = aes [full] // 0 = rijndael_enc 1 = aes_enc, 2 = rijndael [full], 3 = aes [full]
#define YARROW_AES 0 #define YARROW_AES 0
#if defined(YARROW) && !defined(CTR)
#error YARROW requires CTR chaining mode to be defined!
#endif
#define SPRNG #define SPRNG
#define RC4 #define RC4
/* Fortuna */ /* Fortuna PRNG */
#define FORTUNA #define FORTUNA
/* reseed every N calls to the read function */ /* reseed every N calls to the read function */
#define FORTUNA_WD 1024 #define FORTUNA_WD 10
/* number of pools (4..32) can save a bit of ram by lowering the count */
#define FORTUNA_POOLS 32
/* Greg's SOBER128 PRNG ;-0 */
#define SOBER128
#define DEVRANDOM #define DEVRANDOM
#define TRY_URANDOM_FIRST #define TRY_URANDOM_FIRST
@ -139,6 +150,12 @@
/* Use SSE2 optimizations in LTM? Requires GCC or ICC and a P4 or K8 processor */ /* Use SSE2 optimizations in LTM? Requires GCC or ICC and a P4 or K8 processor */
// #define LTMSSE // #define LTMSSE
/* prevents the code from being "unportable" at least to non i386 platforms */
#if defined(LTMSSE) && !( (defined(__GNUC__) && defined(__i386__)) || defined(INTEL_CC))
#warning LTMSSE is only available for GNU CC (i386) or Intel CC
#undef LTMSSE
#endif
/* PKCS #1 and #5 stuff */ /* PKCS #1 and #5 stuff */
#define PKCS_1 #define PKCS_1
#define PKCS_5 #define PKCS_5

View File

@ -11,7 +11,7 @@ struct rc4_prng {
}; };
struct fortuna_prng { struct fortuna_prng {
hash_state pool[32]; /* the 32 pools */ hash_state pool[FORTUNA_POOLS]; /* the pools */
symmetric_key skey; symmetric_key skey;
@ -25,21 +25,44 @@ struct fortuna_prng {
ulong64 reset_cnt; /* number of times we have reset */ ulong64 reset_cnt; /* number of times we have reset */
}; };
struct sober128_prng {
ulong32 R[17], /* Working storage for the shift register */
initR[17], /* saved register contents */
konst, /* key dependent constant */
sbuf; /* partial word encryption buffer */
int nbuf, /* number of part-word stream bits buffered */
flag, /* first add_entropy call or not? */
set; /* did we call add_entropy to set key? */
};
typedef union Prng_state { typedef union Prng_state {
#ifdef YARROW
struct yarrow_prng yarrow; struct yarrow_prng yarrow;
#endif
#ifdef RC4
struct rc4_prng rc4; struct rc4_prng rc4;
#endif
#ifdef FORTUNA
struct fortuna_prng fortuna; struct fortuna_prng fortuna;
#endif
#ifdef SOBER128
struct sober128_prng sober128;
#endif
} prng_state; } prng_state;
extern struct _prng_descriptor { extern struct _prng_descriptor {
char *name; char *name;
int export_size; /* size in bytes of exported state */
int (*start)(prng_state *); int (*start)(prng_state *);
int (*add_entropy)(const unsigned char *, unsigned long, prng_state *); int (*add_entropy)(const unsigned char *, unsigned long, prng_state *);
int (*ready)(prng_state *); int (*ready)(prng_state *);
unsigned long (*read)(unsigned char *, unsigned long, prng_state *); unsigned long (*read)(unsigned char *, unsigned long, prng_state *);
void (*done)(prng_state *); int (*done)(prng_state *);
int (*export)(unsigned char *, unsigned long *, prng_state *); int (*export)(unsigned char *, unsigned long *, prng_state *);
int (*import)(const unsigned char *, unsigned long, prng_state *); int (*import)(const unsigned char *, unsigned long, prng_state *);
int (*test)(void);
} prng_descriptor[]; } prng_descriptor[];
#ifdef YARROW #ifdef YARROW
@ -47,9 +70,10 @@ extern struct _prng_descriptor {
int yarrow_add_entropy(const unsigned char *buf, unsigned long len, prng_state *prng); int yarrow_add_entropy(const unsigned char *buf, unsigned long len, prng_state *prng);
int yarrow_ready(prng_state *prng); int yarrow_ready(prng_state *prng);
unsigned long yarrow_read(unsigned char *buf, unsigned long len, prng_state *prng); unsigned long yarrow_read(unsigned char *buf, unsigned long len, prng_state *prng);
void yarrow_done(prng_state *prng); int yarrow_done(prng_state *prng);
int yarrow_export(unsigned char *out, unsigned long *outlen, prng_state *prng); int yarrow_export(unsigned char *out, unsigned long *outlen, prng_state *prng);
int yarrow_import(const unsigned char *in, unsigned long inlen, prng_state *prng); int yarrow_import(const unsigned char *in, unsigned long inlen, prng_state *prng);
int yarrow_test(void);
extern const struct _prng_descriptor yarrow_desc; extern const struct _prng_descriptor yarrow_desc;
#endif #endif
@ -58,9 +82,10 @@ extern struct _prng_descriptor {
int fortuna_add_entropy(const unsigned char *buf, unsigned long len, prng_state *prng); int fortuna_add_entropy(const unsigned char *buf, unsigned long len, prng_state *prng);
int fortuna_ready(prng_state *prng); int fortuna_ready(prng_state *prng);
unsigned long fortuna_read(unsigned char *buf, unsigned long len, prng_state *prng); unsigned long fortuna_read(unsigned char *buf, unsigned long len, prng_state *prng);
void fortuna_done(prng_state *prng); int fortuna_done(prng_state *prng);
int fortuna_export(unsigned char *out, unsigned long *outlen, prng_state *prng); int fortuna_export(unsigned char *out, unsigned long *outlen, prng_state *prng);
int fortuna_import(const unsigned char *in, unsigned long inlen, prng_state *prng); int fortuna_import(const unsigned char *in, unsigned long inlen, prng_state *prng);
int fortuna_test(void);
extern const struct _prng_descriptor fortuna_desc; extern const struct _prng_descriptor fortuna_desc;
#endif #endif
@ -69,9 +94,10 @@ extern struct _prng_descriptor {
int rc4_add_entropy(const unsigned char *buf, unsigned long len, prng_state *prng); int rc4_add_entropy(const unsigned char *buf, unsigned long len, prng_state *prng);
int rc4_ready(prng_state *prng); int rc4_ready(prng_state *prng);
unsigned long rc4_read(unsigned char *buf, unsigned long len, prng_state *prng); unsigned long rc4_read(unsigned char *buf, unsigned long len, prng_state *prng);
void rc4_done(prng_state *prng); int rc4_done(prng_state *prng);
int rc4_export(unsigned char *out, unsigned long *outlen, prng_state *prng); int rc4_export(unsigned char *out, unsigned long *outlen, prng_state *prng);
int rc4_import(const unsigned char *in, unsigned long inlen, prng_state *prng); int rc4_import(const unsigned char *in, unsigned long inlen, prng_state *prng);
int rc4_test(void);
extern const struct _prng_descriptor rc4_desc; extern const struct _prng_descriptor rc4_desc;
#endif #endif
@ -80,26 +106,36 @@ extern struct _prng_descriptor {
int sprng_add_entropy(const unsigned char *buf, unsigned long len, prng_state *prng); int sprng_add_entropy(const unsigned char *buf, unsigned long len, prng_state *prng);
int sprng_ready(prng_state *prng); int sprng_ready(prng_state *prng);
unsigned long sprng_read(unsigned char *buf, unsigned long len, prng_state *prng); unsigned long sprng_read(unsigned char *buf, unsigned long len, prng_state *prng);
void sprng_done(prng_state *prng); int sprng_done(prng_state *prng);
int sprng_export(unsigned char *out, unsigned long *outlen, prng_state *prng); int sprng_export(unsigned char *out, unsigned long *outlen, prng_state *prng);
int sprng_import(const unsigned char *in, unsigned long inlen, prng_state *prng); int sprng_import(const unsigned char *in, unsigned long inlen, prng_state *prng);
int sprng_test(void);
extern const struct _prng_descriptor sprng_desc; extern const struct _prng_descriptor sprng_desc;
#endif #endif
#ifdef SOBER128
int sober128_start(prng_state *prng);
int sober128_add_entropy(const unsigned char *buf, unsigned long len, prng_state *prng);
int sober128_ready(prng_state *prng);
unsigned long sober128_read(unsigned char *buf, unsigned long len, prng_state *prng);
int sober128_done(prng_state *prng);
int sober128_export(unsigned char *out, unsigned long *outlen, prng_state *prng);
int sober128_import(const unsigned char *in, unsigned long inlen, prng_state *prng);
int sober128_test(void);
extern const struct _prng_descriptor sober128_desc;
#endif
int find_prng(const char *name); int find_prng(const char *name);
int register_prng(const struct _prng_descriptor *prng); int register_prng(const struct _prng_descriptor *prng);
int unregister_prng(const struct _prng_descriptor *prng); int unregister_prng(const struct _prng_descriptor *prng);
int prng_is_valid(int idx); int prng_is_valid(int idx);
/* Slow RNG you **might** be able to use to seed a PRNG with. Be careful as this /* Slow RNG you **might** be able to use to seed a PRNG with. Be careful as this
* might not work on all platforms as planned * might not work on all platforms as planned
*/ */
/* ch2-02-1 */ unsigned long rng_get_bytes(unsigned char *buf,
unsigned long rng_get_bytes(unsigned char *buf,
unsigned long len, unsigned long len,
void (*callback)(void)); void (*callback)(void));
/* ch2-02-1 */
int rng_make_prng(int bits, int wprng, prng_state *prng, void (*callback)(void)); int rng_make_prng(int bits, int wprng, prng_state *prng, void (*callback)(void));

View File

@ -33,7 +33,6 @@ static const ulong32 RC[] = {
0x000000d4UL 0x000000d4UL
}; };
#define kTHETA(a, b, c, d) \ #define kTHETA(a, b, c, d) \
temp = a^c; temp = temp ^ ROL(temp, 8) ^ ROR(temp, 8); \ temp = a^c; temp = temp ^ ROL(temp, 8) ^ ROR(temp, 8); \
b ^= temp; d ^= temp; \ b ^= temp; d ^= temp; \
@ -97,9 +96,7 @@ void noekeon_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_k
#endif #endif
{ {
ulong32 a,b,c,d,temp; ulong32 a,b,c,d,temp;
#ifdef SMALL_CODE
int r; int r;
#endif
_ARGCHK(key != NULL); _ARGCHK(key != NULL);
_ARGCHK(pt != NULL); _ARGCHK(pt != NULL);
@ -115,16 +112,9 @@ void noekeon_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_k
GAMMA(a,b,c,d); \ GAMMA(a,b,c,d); \
PI2(a,b,c,d); PI2(a,b,c,d);
#ifdef SMALL_CODE
for (r = 0; r < 16; ++r) { for (r = 0; r < 16; ++r) {
ROUND(r); ROUND(r);
} }
#else
ROUND( 0); ROUND( 1); ROUND( 2); ROUND( 3);
ROUND( 4); ROUND( 5); ROUND( 6); ROUND( 7);
ROUND( 8); ROUND( 9); ROUND(10); ROUND(11);
ROUND(12); ROUND(13); ROUND(14); ROUND(15);
#endif
#undef ROUND #undef ROUND
@ -150,9 +140,7 @@ void noekeon_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_k
#endif #endif
{ {
ulong32 a,b,c,d, temp; ulong32 a,b,c,d, temp;
#ifdef SMALL_CODE
int r; int r;
#endif
_ARGCHK(key != NULL); _ARGCHK(key != NULL);
_ARGCHK(pt != NULL); _ARGCHK(pt != NULL);
@ -169,16 +157,9 @@ void noekeon_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_k
GAMMA(a,b,c,d); \ GAMMA(a,b,c,d); \
PI2(a,b,c,d); PI2(a,b,c,d);
#ifdef SMALL_CODE
for (r = 16; r > 0; --r) { for (r = 16; r > 0; --r) {
ROUND(r); ROUND(r);
} }
#else
ROUND(16); ROUND(15); ROUND(14); ROUND(13);
ROUND(12); ROUND(11); ROUND(10); ROUND( 9);
ROUND( 8); ROUND( 7); ROUND( 6); ROUND( 5);
ROUND( 4); ROUND( 3); ROUND( 2); ROUND( 1);
#endif
#undef ROUND #undef ROUND

91
notes/tech0004.txt Normal file
View File

@ -0,0 +1,91 @@
Tech Note 0004
Using Yarrow, Fortuna and SOBER-128
Tom St Denis
Introduction
------------
This tech note explains how to use three of the more useful pseudo random number generators and their
own little "issues". While all of the PRNGs have the same API and are roughly used in the same
manner their effectiveness really depends on the user knowing how they work.
Yarrow
------
Yarrow is by far the simplest of the PRNGs. It gathers bits of entropy by hashing the pool state
plus the additional bits storing the message digest back in the pool. E.g.
pool = hash(pool || newbits)
Simply dump bits into the PRNG via yarrow_add_entropy() and call yarrow_ready() when you want to
put them to use. This PRNG while simple is not entirely safe. An attacker who learns the state
of the pool and can control future events can control the PRNG. This requires an active attacker but
isn't entire impossible.
The pool is then used as a key for a cipher that is used in CTR mode.
Yarrow is mostly meant for short-term programs [e.g. like file utils]. This particular implementation
is not meant for long-term usage.
Fortuna
-------
Fortuna was designed by Niels Fergusson and Bruce Schneier [Bruce is also the guy who invented Yarrow]. It
operates on a more defensive level than Yarrow. Instead of 1 entropy pool it has 32 and the new entropy
is spread [round robin] in all of the pools.
That is, each call to fortuna_add_entropy() puts the bits in the next [in the sequenece] pool of entropy.
Effective bits are added to the pool by sending them through a hash [but not terminating the hash].
Here's the main catch though. When the PRNG must be reseeded [so that you can extract bits from it] only
certain pools are used. More precisely the i'th pool is used every 2**i'th reseeding. For example, pool[0]
is always used. pool[1] is used every second reseeding, pool[2] every fourth.
The pools are hashed together along with the current key and the result is the new key for a cipher which
operates in CTR mode [more about that in a sec].
Now this may seem odd at first however there is a good reason behind it. An attacker who learns pool[0] won't
strictly know the other pools. So the recovery rate of is not 0. In fact pool[0] can be completely
compromised and the PRNG will still eventually recover. The value FORTUNA_WD is the "WatchDog" counter.
Every FORTUNA_WD calls to fortuna_read will invoke the reseed operation. By default this is set to 10 which
means after 10 calls the PRNG will reseed itself.
The pools are combined with the running cipher key [256 bits] so that a cipher in CTR mode can produce
the stream. Unlike Yarrow the cipher is re-keyed after every call to fortuna_read() [so one big call
would be faster than many smaller calls]. This prevents too much data being encrypted under the same
key [and mitigates a flaw in CTR mode that the same block can't be emitted twice under the same key].
Fortuna is really meant for a kernel-level PRNG. The more sources [and often] you feed into it the
healthier it will be. It's also meant to be used for long term purposes. Since it can recover from
compromises it is harder to control it.
SOBER-128
------
SOBER-128 is actually a stream cipher but like most ciphers can easily be modelled in the context of a PRNG.
This PRNG is extremely fast [4 cycles/byte on a P4] and was designed by a well known cryptographer [Greg Rose].
SOBER-128 doesn't really "act" like the other two PRNGs. It's meant to be seeded once and then read as
required. In such a sense it isn't a "system PRNG" but useful short term purposes. In particular
the sober128_read() function actually XORs against the input buffer you specify. This allows the
read() function to be used as an "encrypt" function as well.
You can only key SOBER-128 once [by calling sober128_add_entropy()]. Once it it is keyed subsequent
calls to add_entropy() will be considered a "re-IV" operation. Changing the IV allows you to use same
initial key and not produce the same output stream. It also lets you differentiate packets. E.g. each
packet has it's own IV.
All inputs to sober128_add_entropy() must have a length that is a multiple of four.
Overall
-------
Since SOBER-128 is *much* faster than the other two PRNGs a good setup would be to use Fortuna as your
system-wide PRNG and use SOBER-128 [key'ed from Fortuna] for encrypting streams or as a PRNG for
simulations.
Yarrow is still a good candidate but only for "short lived" programs. However, since Fortuna is faster
[by about 10 cycles/byte on a P4] I'd use Fortuna anyways...
Tom

View File

@ -21,8 +21,9 @@ foreach my $filename (glob "*.c") {
if (!($filename =~ "sha384.c")) { if (!($filename =~ "sha384.c")) {
if (!($filename =~ "dh_sys.c")) { if (!($filename =~ "dh_sys.c")) {
if (!($filename =~ "ecc_sys.c")) { if (!($filename =~ "ecc_sys.c")) {
if (!($filename =~ "sober128tab.c")) {
++$count; ++$count;
}}}}}}} }}}}}}}}
} }
print "Source files to build: $count\nBuilding...\n"; print "Source files to build: $count\nBuilding...\n";
my $i = 0; my $i = 0;
@ -36,6 +37,7 @@ foreach my $filename (glob "*.c") {
if (!($filename =~ "sha384.c")) { if (!($filename =~ "sha384.c")) {
if (!($filename =~ "dh_sys.c")) { if (!($filename =~ "dh_sys.c")) {
if (!($filename =~ "ecc_sys.c")) { if (!($filename =~ "ecc_sys.c")) {
if (!($filename =~ "sober128tab.c")) {
printf("Building %3.2f%%, ", (++$i/$count)*100.0); printf("Building %3.2f%%, ", (++$i/$count)*100.0);
if ($i % 4 == 0) { print "/, "; } if ($i % 4 == 0) { print "/, "; }
if ($i % 4 == 1) { print "-, "; } if ($i % 4 == 1) { print "-, "; }
@ -71,7 +73,7 @@ foreach my $filename (glob "*.c") {
my $delay = time - $starttime; my $delay = time - $starttime;
$rate = $i/$delay; $rate = $i/$delay;
} }
}}}}}}} }}}}}}}}
} }
# finish building the library # finish building the library

115
rc4.c
View File

@ -14,14 +14,15 @@
const struct _prng_descriptor rc4_desc = const struct _prng_descriptor rc4_desc =
{ {
"rc4", "rc4", 32,
&rc4_start, &rc4_start,
&rc4_add_entropy, &rc4_add_entropy,
&rc4_ready, &rc4_ready,
&rc4_read, &rc4_read,
&rc4_done, &rc4_done,
&rc4_export, &rc4_export,
&rc4_import &rc4_import,
&rc4_test
}; };
int rc4_start(prng_state *prng) int rc4_start(prng_state *prng)
@ -39,8 +40,15 @@ int rc4_add_entropy(const unsigned char *buf, unsigned long len, prng_state *prn
_ARGCHK(buf != NULL); _ARGCHK(buf != NULL);
_ARGCHK(prng != NULL); _ARGCHK(prng != NULL);
/* trim as required */
if (prng->rc4.x + len > 256) { if (prng->rc4.x + len > 256) {
return CRYPT_INVALID_KEYSIZE; if (prng->rc4.x == 256) {
/* I can't possibly accept another byte, ok maybe a mint wafer... */
return CRYPT_OK;
} else {
/* only accept part of it */
len = 256 - prng->rc4.x;
}
} }
while (len--) { while (len--) {
@ -53,26 +61,30 @@ int rc4_add_entropy(const unsigned char *buf, unsigned long len, prng_state *prn
int rc4_ready(prng_state *prng) int rc4_ready(prng_state *prng)
{ {
unsigned char key[256], tmp; unsigned char key[256], tmp, *s;
int keylen, x, y; int keylen, x, y, j;
_ARGCHK(prng != NULL); _ARGCHK(prng != NULL);
/* extract the key */ /* extract the key */
XMEMCPY(key, prng->rc4.buf, 256); s = prng->rc4.buf;
XMEMCPY(key, s, 256);
keylen = prng->rc4.x; keylen = prng->rc4.x;
/* make RC4 perm and shuffle */ /* make RC4 perm and shuffle */
for (x = 0; x < 256; x++) { for (x = 0; x < 256; x++) {
prng->rc4.buf[x] = x; s[x] = x;
} }
for (x = y = 0; x < 256; x++) { for (j = x = y = 0; x < 256; x++) {
y = (y + prng->rc4.buf[x] + key[x % keylen]) & 255; y = (y + prng->rc4.buf[x] + key[j++]) & 255;
tmp = prng->rc4.buf[x]; prng->rc4.buf[x] = prng->rc4.buf[y]; prng->rc4.buf[y] = tmp; if (j == keylen) {
j = 0;
} }
prng->rc4.x = x; tmp = s[x]; s[x] = s[y]; s[y] = tmp;
prng->rc4.y = y; }
prng->rc4.x = 0;
prng->rc4.y = 0;
#ifdef CLEAN_STACK #ifdef CLEAN_STACK
zeromem(key, sizeof(key)); zeromem(key, sizeof(key));
@ -83,8 +95,7 @@ int rc4_ready(prng_state *prng)
unsigned long rc4_read(unsigned char *buf, unsigned long len, prng_state *prng) unsigned long rc4_read(unsigned char *buf, unsigned long len, prng_state *prng)
{ {
int x, y; unsigned char x, y, *s, tmp;
unsigned char *s, tmp;
unsigned long n; unsigned long n;
_ARGCHK(buf != NULL); _ARGCHK(buf != NULL);
@ -99,31 +110,99 @@ unsigned long rc4_read(unsigned char *buf, unsigned long len, prng_state *prng)
y = (y + s[x]) & 255; y = (y + s[x]) & 255;
tmp = s[x]; s[x] = s[y]; s[y] = tmp; tmp = s[x]; s[x] = s[y]; s[y] = tmp;
tmp = (s[x] + s[y]) & 255; tmp = (s[x] + s[y]) & 255;
*buf++ = s[tmp]; *buf++ ^= s[tmp];
} }
prng->rc4.x = x; prng->rc4.x = x;
prng->rc4.y = y; prng->rc4.y = y;
return n; return n;
} }
void rc4_done(prng_state *prng) int rc4_done(prng_state *prng)
{ {
_ARGCHK(prng != NULL); _ARGCHK(prng != NULL);
return CRYPT_OK;
} }
int rc4_export(unsigned char *out, unsigned long *outlen, prng_state *prng) int rc4_export(unsigned char *out, unsigned long *outlen, prng_state *prng)
{ {
_ARGCHK(outlen != NULL); _ARGCHK(outlen != NULL);
_ARGCHK(out != NULL);
_ARGCHK(prng != NULL);
if (*outlen < 32) {
return CRYPT_BUFFER_OVERFLOW;
}
if (rc4_read(out, 32, prng) != 32) {
return CRYPT_ERROR_READPRNG;
}
*outlen = 32;
*outlen = 0;
return CRYPT_OK; return CRYPT_OK;
} }
int rc4_import(const unsigned char *in, unsigned long inlen, prng_state *prng) int rc4_import(const unsigned char *in, unsigned long inlen, prng_state *prng)
{ {
return CRYPT_OK; int err;
_ARGCHK(in != NULL);
_ARGCHK(prng != NULL);
if (inlen != 32) {
return CRYPT_INVALID_ARG;
}
if ((err = rc4_start(prng)) != CRYPT_OK) {
return err;
}
return rc4_add_entropy(in, 32, prng);
} }
int rc4_test(void)
{
#ifndef LTC_TEST
return CRYPT_NOP;
#else
static const struct {
unsigned char key[8], pt[8], ct[8];
} tests[] = {
{
{ 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef },
{ 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef },
{ 0x75, 0xb7, 0x87, 0x80, 0x99, 0xe0, 0xc5, 0x96 }
}
};
prng_state prng;
unsigned char dst[8];
int err, x;
for (x = 0; x < (int)(sizeof(tests)/sizeof(tests[0])); x++) {
if ((err = rc4_start(&prng)) != CRYPT_OK) {
return err;
}
if ((err = rc4_add_entropy(tests[x].key, 8, &prng)) != CRYPT_OK) {
return err;
}
if ((err = rc4_ready(&prng)) != CRYPT_OK) {
return err;
}
XMEMCPY(dst, tests[x].pt, 8);
if (rc4_read(dst, 8, &prng) != 8) {
return CRYPT_ERROR_READPRNG;
}
rc4_done(&prng);
if (memcmp(dst, tests[x].ct, 8)) {
#if 0
int y;
printf("\n\nRC4 failed, I got:\n");
for (y = 0; y < 8; y++) printf("%02x ", dst[y]);
printf("\n");
#endif
return CRYPT_FAIL_TESTVECTOR;
}
}
return CRYPT_OK;
#endif
}
#endif #endif

View File

@ -13,7 +13,7 @@
#ifdef MRSA #ifdef MRSA
/* decrypt then OAEP depad */ /* (PKCS #1 v2.0) decrypt then OAEP depad */
int rsa_decrypt_key(const unsigned char *in, unsigned long inlen, int rsa_decrypt_key(const unsigned char *in, unsigned long inlen,
unsigned char *outkey, unsigned long *keylen, unsigned char *outkey, unsigned long *keylen,
const unsigned char *lparam, unsigned long lparamlen, const unsigned char *lparam, unsigned long lparamlen,
@ -30,6 +30,9 @@ int rsa_decrypt_key(const unsigned char *in, unsigned long inlen,
_ARGCHK(key != NULL); _ARGCHK(key != NULL);
_ARGCHK(res != NULL); _ARGCHK(res != NULL);
/* default to invalid */
*res = 0;
/* valid hash/prng ? */ /* valid hash/prng ? */
if ((err = prng_is_valid(prng_idx)) != CRYPT_OK) { if ((err = prng_is_valid(prng_idx)) != CRYPT_OK) {
return err; return err;

View File

@ -13,7 +13,7 @@
#ifdef MRSA #ifdef MRSA
/* OAEP pad then encrypt */ /* (PKCS #1 v2.0) OAEP pad then encrypt */
int rsa_encrypt_key(const unsigned char *inkey, unsigned long inlen, int rsa_encrypt_key(const unsigned char *inkey, unsigned long inlen,
unsigned char *outkey, unsigned long *outlen, unsigned char *outkey, unsigned long *outlen,
const unsigned char *lparam, unsigned long lparamlen, const unsigned char *lparam, unsigned long lparamlen,

View File

@ -13,6 +13,7 @@
#ifdef MRSA #ifdef MRSA
/* Export an RSA key */
int rsa_export(unsigned char *out, unsigned long *outlen, int type, rsa_key *key) int rsa_export(unsigned char *out, unsigned long *outlen, int type, rsa_key *key)
{ {
unsigned long y, z; unsigned long y, z;

View File

@ -14,6 +14,7 @@
#ifdef MRSA #ifdef MRSA
/* compute an RSA modular exponentiation */
int rsa_exptmod(const unsigned char *in, unsigned long inlen, int rsa_exptmod(const unsigned char *in, unsigned long inlen,
unsigned char *out, unsigned long *outlen, int which, unsigned char *out, unsigned long *outlen, int which,
prng_state *prng, int prng_idx, prng_state *prng, int prng_idx,

View File

@ -69,7 +69,7 @@ int rsa_make_key(prng_state *prng, int wprng, int size, long e, rsa_key *key)
if ((err = mp_invmod(&key->e, &tmp1, &key->d)) != MP_OKAY) { goto error2; } /* key->d = 1/e mod lcm(p-1,q-1) */ if ((err = mp_invmod(&key->e, &tmp1, &key->d)) != MP_OKAY) { goto error2; } /* key->d = 1/e mod lcm(p-1,q-1) */
if ((err = mp_mul(&p, &q, &key->N)) != MP_OKAY) { goto error2; } /* key->N = pq */ if ((err = mp_mul(&p, &q, &key->N)) != MP_OKAY) { goto error2; } /* key->N = pq */
/* optimize for CRT now */ /* optimize for CRT now */
/* find d mod q-1 and d mod p-1 */ /* find d mod q-1 and d mod p-1 */
if ((err = mp_sub_d(&p, 1, &tmp1)) != MP_OKAY) { goto error2; } /* tmp1 = q-1 */ if ((err = mp_sub_d(&p, 1, &tmp1)) != MP_OKAY) { goto error2; } /* tmp1 = q-1 */
if ((err = mp_sub_d(&q, 1, &tmp2)) != MP_OKAY) { goto error2; } /* tmp2 = p-1 */ if ((err = mp_sub_d(&q, 1, &tmp2)) != MP_OKAY) { goto error2; } /* tmp2 = p-1 */

View File

@ -13,7 +13,7 @@
#ifdef MRSA #ifdef MRSA
/* PSS pad then sign */ /* (PKCS #1, v2.0) PSS pad then sign */
int rsa_sign_hash(const unsigned char *msghash, unsigned long msghashlen, int rsa_sign_hash(const unsigned char *msghash, unsigned long msghashlen,
unsigned char *sig, unsigned long *siglen, unsigned char *sig, unsigned long *siglen,
prng_state *prng, int prng_idx, prng_state *prng, int prng_idx,

View File

@ -27,6 +27,9 @@ int rsa_v15_decrypt_key(const unsigned char *in, unsigned long inlen,
_ARGCHK(key != NULL); _ARGCHK(key != NULL);
_ARGCHK(res != NULL); _ARGCHK(res != NULL);
/* default to invalid */
*res = 0;
/* valid prng ? */ /* valid prng ? */
if ((err = prng_is_valid(prng_idx)) != CRYPT_OK) { if ((err = prng_is_valid(prng_idx)) != CRYPT_OK) {
return err; return err;

View File

@ -13,7 +13,7 @@
#ifdef MRSA #ifdef MRSA
/* design then PKCS v1.5 depad */ /* de-sign then PKCS v1.5 depad */
int rsa_v15_verify_hash(const unsigned char *sig, unsigned long siglen, int rsa_v15_verify_hash(const unsigned char *sig, unsigned long siglen,
const unsigned char *msghash, unsigned long msghashlen, const unsigned char *msghash, unsigned long msghashlen,
prng_state *prng, int prng_idx, prng_state *prng, int prng_idx,
@ -29,6 +29,9 @@ int rsa_v15_verify_hash(const unsigned char *sig, unsigned long siglen,
_ARGCHK(stat != NULL); _ARGCHK(stat != NULL);
_ARGCHK(key != NULL); _ARGCHK(key != NULL);
/* default to invalid */
*stat = 0;
/* valid hash ? */ /* valid hash ? */
if ((err = hash_is_valid(hash_idx)) != CRYPT_OK) { if ((err = hash_is_valid(hash_idx)) != CRYPT_OK) {
return err; return err;

View File

@ -13,7 +13,7 @@
#ifdef MRSA #ifdef MRSA
/* design then PSS depad */ /* (PKCS #1, v2.0) de-sign then PSS depad */
int rsa_verify_hash(const unsigned char *sig, unsigned long siglen, int rsa_verify_hash(const unsigned char *sig, unsigned long siglen,
const unsigned char *msghash, unsigned long msghashlen, const unsigned char *msghash, unsigned long msghashlen,
prng_state *prng, int prng_idx, prng_state *prng, int prng_idx,
@ -29,6 +29,9 @@ int rsa_verify_hash(const unsigned char *sig, unsigned long siglen,
_ARGCHK(stat != NULL); _ARGCHK(stat != NULL);
_ARGCHK(key != NULL); _ARGCHK(key != NULL);
/* default to invalid */
*stat = 0;
/* valid hash ? */ /* valid hash ? */
if ((err = hash_is_valid(hash_idx)) != CRYPT_OK) { if ((err = hash_is_valid(hash_idx)) != CRYPT_OK) {
return err; return err;

444
sober128.c Normal file
View File

@ -0,0 +1,444 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis
*
* LibTomCrypt is a library that provides various cryptographic
* algorithms in a highly modular and flexible manner.
*
* The library is free for all purposes without any express
* guarantee it works.
*
* Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org
*/
#include "mycrypt.h"
/* Implementation of SOBER-128 by Tom St Denis.
* Based on s128fast.c reference code supplied by Greg Rose of QUALCOMM.
*/
#ifdef SOBER128
#include "sober128tab.c"
const struct _prng_descriptor sober128_desc =
{
"sober128", 64,
&sober128_start,
&sober128_add_entropy,
&sober128_ready,
&sober128_read,
&sober128_done,
&sober128_export,
&sober128_import,
&sober128_test
};
/* don't change these... */
#define N 17
#define FOLD N /* how many iterations of folding to do */
#define INITKONST 0x6996c53a /* value of KONST to use during key loading */
#define KEYP 15 /* where to insert key words */
#define FOLDP 4 /* where to insert non-linear feedback */
#define B(x,i) ((unsigned char)(((x) >> (8*i)) & 0xFF))
static ulong32 BYTE2WORD(unsigned char *b)
{
ulong32 t;
LOAD32L(t, b);
return t;
}
#define WORD2BYTE(w, b) STORE32L(b, w)
static void XORWORD(ulong32 w, unsigned char *b)
{
ulong32 t;
LOAD32L(t, b);
t ^= w;
STORE32L(t, b);
}
/* give correct offset for the current position of the register,
* where logically R[0] is at position "zero".
*/
#define OFF(zero, i) (((zero)+(i)) % N)
/* step the LFSR */
/* After stepping, "zero" moves right one place */
#define STEP(R,z) \
R[OFF(z,0)] = R[OFF(z,15)] ^ R[OFF(z,4)] ^ (R[OFF(z,0)] << 8) ^ Multab[(R[OFF(z,0)] >> 24) & 0xFF];
static void cycle(ulong32 *R)
{
ulong32 t;
int i;
STEP(R,0);
t = R[0];
for (i = 1; i < N; ++i) {
R[i-1] = R[i];
}
R[N-1] = t;
}
/* Return a non-linear function of some parts of the register.
*/
#define NLFUNC(c,z) \
{ \
t = c->R[OFF(z,0)] + c->R[OFF(z,16)]; \
t ^= Sbox[(t >> 24) & 0xFF]; \
t = ROR(t, 8); \
t = ((t + c->R[OFF(z,1)]) ^ c->konst) + c->R[OFF(z,6)]; \
t ^= Sbox[(t >> 24) & 0xFF]; \
t = t + c->R[OFF(z,13)]; \
}
static ulong32 nltap(struct sober128_prng *c)
{
ulong32 t;
NLFUNC(c, 0);
return t;
}
/* initialise to known state
*/
int sober128_start(prng_state *prng)
{
int i;
struct sober128_prng *c;
_ARGCHK(prng != NULL);
c = &(prng->sober128);
/* Register initialised to Fibonacci numbers */
c->R[0] = 1;
c->R[1] = 1;
for (i = 2; i < N; ++i) {
c->R[i] = c->R[i-1] + c->R[i-2];
}
c->konst = INITKONST;
/* next add_entropy will be the key */
c->flag = 1;
c->set = 0;
return CRYPT_OK;
}
/* Save the current register state
*/
static void s128_savestate(struct sober128_prng *c)
{
int i;
for (i = 0; i < N; ++i) {
c->initR[i] = c->R[i];
}
}
/* initialise to previously saved register state
*/
static void s128_reloadstate(struct sober128_prng *c)
{
int i;
for (i = 0; i < N; ++i) {
c->R[i] = c->initR[i];
}
}
/* Initialise "konst"
*/
static void s128_genkonst(struct sober128_prng *c)
{
ulong32 newkonst;
do {
cycle(c->R);
newkonst = nltap(c);
} while ((newkonst & 0xFF000000) == 0);
c->konst = newkonst;
}
/* Load key material into the register
*/
#define ADDKEY(k) \
c->R[KEYP] += (k);
#define XORNL(nl) \
c->R[FOLDP] ^= (nl);
/* nonlinear diffusion of register for key */
#define DROUND(z) STEP(c->R,z); NLFUNC(c,(z+1)); c->R[OFF((z+1),FOLDP)] ^= t;
static void s128_diffuse(struct sober128_prng *c)
{
ulong32 t;
/* relies on FOLD == N == 17! */
DROUND(0);
DROUND(1);
DROUND(2);
DROUND(3);
DROUND(4);
DROUND(5);
DROUND(6);
DROUND(7);
DROUND(8);
DROUND(9);
DROUND(10);
DROUND(11);
DROUND(12);
DROUND(13);
DROUND(14);
DROUND(15);
DROUND(16);
}
int sober128_add_entropy(const unsigned char *buf, unsigned long len, prng_state *prng)
{
struct sober128_prng *c;
ulong32 i, k;
_ARGCHK(buf != NULL);
_ARGCHK(prng != NULL);
c = &(prng->sober128);
if (c->flag == 1) {
/* this is the first call to the add_entropy so this input is the key */
/* len must be multiple of 4 bytes */
if ((len & 3) != 0) {
return CRYPT_INVALID_KEYSIZE;
}
for (i = 0; i < len; i += 4) {
k = BYTE2WORD((unsigned char *)&buf[i]);
ADDKEY(k);
cycle(c->R);
XORNL(nltap(c));
}
/* also fold in the length of the key */
ADDKEY(len);
/* now diffuse */
s128_diffuse(c);
s128_genkonst(c);
s128_savestate(c);
c->nbuf = 0;
c->flag = 0;
c->set = 1;
} else {
/* ok we are adding an IV then... */
s128_reloadstate(c);
/* len must be multiple of 4 bytes */
if ((len & 3) != 0) {
return CRYPT_INVALID_KEYSIZE;
}
for (i = 0; i < len; i += 4) {
k = BYTE2WORD((unsigned char *)&buf[i]);
ADDKEY(k);
cycle(c->R);
XORNL(nltap(c));
}
/* also fold in the length of the key */
ADDKEY(len);
/* now diffuse */
s128_diffuse(c);
c->nbuf = 0;
}
return CRYPT_OK;
}
int sober128_ready(prng_state *prng)
{
return prng->sober128.set == 1 ? CRYPT_OK : CRYPT_ERROR;
}
/* XOR pseudo-random bytes into buffer
*/
#define SROUND(z) STEP(c->R,z); NLFUNC(c,(z+1)); XORWORD(t, buf+(z*4));
unsigned long sober128_read(unsigned char *buf, unsigned long nbytes, prng_state *prng)
{
struct sober128_prng *c;
ulong32 t, tlen;
_ARGCHK(buf != NULL);
_ARGCHK(prng != NULL);
c = &(prng->sober128);
t = 0;
tlen = nbytes;
/* handle any previously buffered bytes */
while (c->nbuf != 0 && nbytes != 0) {
*buf++ ^= c->sbuf & 0xFF;
c->sbuf >>= 8;
c->nbuf -= 8;
--nbytes;
}
#ifndef SMALL_CODE
/* do lots at a time, if there's enough to do */
while (nbytes >= N*4) {
SROUND(0);
SROUND(1);
SROUND(2);
SROUND(3);
SROUND(4);
SROUND(5);
SROUND(6);
SROUND(7);
SROUND(8);
SROUND(9);
SROUND(10);
SROUND(11);
SROUND(12);
SROUND(13);
SROUND(14);
SROUND(15);
SROUND(16);
buf += 4*N;
nbytes -= 4*N;
}
#endif
/* do small or odd size buffers the slow way */
while (4 <= nbytes) {
cycle(c->R);
t = nltap(c);
XORWORD(t, buf);
buf += 4;
nbytes -= 4;
}
/* handle any trailing bytes */
if (nbytes != 0) {
cycle(c->R);
c->sbuf = nltap(c);
c->nbuf = 32;
while (c->nbuf != 0 && nbytes != 0) {
*buf++ ^= c->sbuf & 0xFF;
c->sbuf >>= 8;
c->nbuf -= 8;
--nbytes;
}
}
return tlen;
}
int sober128_done(prng_state *prng)
{
_ARGCHK(prng != NULL);
return CRYPT_OK;
}
int sober128_export(unsigned char *out, unsigned long *outlen, prng_state *prng)
{
_ARGCHK(outlen != NULL);
_ARGCHK(out != NULL);
_ARGCHK(prng != NULL);
if (*outlen < 64) {
return CRYPT_BUFFER_OVERFLOW;
}
if (sober128_read(out, 64, prng) != 64) {
return CRYPT_ERROR_READPRNG;
}
*outlen = 64;
return CRYPT_OK;
}
int sober128_import(const unsigned char *in, unsigned long inlen, prng_state *prng)
{
int err;
_ARGCHK(in != NULL);
_ARGCHK(prng != NULL);
if (inlen != 64) {
return CRYPT_INVALID_ARG;
}
if ((err = sober128_start(prng)) != CRYPT_OK) {
return err;
}
if ((err = sober128_add_entropy(in, 64, prng)) != CRYPT_OK) {
return err;
}
return sober128_ready(prng);
}
int sober128_test(void)
{
#ifndef LTC_TEST
return CRYPT_NOP;
#else
static const struct {
int keylen, ivlen, len;
unsigned char key[16], iv[4], out[20];
} tests[] = {
{
16, 4, 20,
/* key */
{ 't', 'e', 's', 't', ' ', 'k', 'e', 'y',
' ', '1', '2', '8', 'b', 'i', 't', 's' },
/* IV */
{ 0x00, 0x00, 0x00, 0x0 },
/* expected output */
{ 0x43, 0x50, 0x0c, 0xcf, 0x89, 0x91, 0x9f, 0x1d,
0xaa, 0x37, 0x74, 0x95, 0xf4, 0xb4, 0x58, 0xc2,
0x40, 0x37, 0x8b, 0xbb }
}
};
prng_state prng;
unsigned char dst[20];
int err, x;
for (x = 0; x < (int)(sizeof(tests)/sizeof(tests[0])); x++) {
if ((err = sober128_start(&prng)) != CRYPT_OK) {
return err;
}
if ((err = sober128_add_entropy(tests[x].key, tests[x].keylen, &prng)) != CRYPT_OK) {
return err;
}
/* add IV */
if ((err = sober128_add_entropy(tests[x].iv, tests[x].ivlen, &prng)) != CRYPT_OK) {
return err;
}
/* ready up */
if ((err = sober128_ready(&prng)) != CRYPT_OK) {
return err;
}
memset(dst, 0, tests[x].len);
if (sober128_read(dst, tests[x].len, &prng) != (unsigned long)tests[x].len) {
return CRYPT_ERROR_READPRNG;
}
sober128_done(&prng);
if (memcmp(dst, tests[x].out, tests[x].len)) {
#if 0
printf("\n\nSOBER128 failed, I got:\n");
for (y = 0; y < tests[x].len; y++) printf("%02x ", dst[y]);
printf("\n");
#endif
return CRYPT_FAIL_TESTVECTOR;
}
}
return CRYPT_OK;
#endif
};
#endif

154
sober128tab.c Normal file
View File

@ -0,0 +1,154 @@
/* $ID$ */
/* @(#)TuringMultab.h 1.3 (QUALCOMM) 02/09/03 */
/* Multiplication table for Turing using 0xD02B4367 */
static const ulong32 Multab[256] = {
0x00000000, 0xD02B4367, 0xED5686CE, 0x3D7DC5A9,
0x97AC41D1, 0x478702B6, 0x7AFAC71F, 0xAAD18478,
0x631582EF, 0xB33EC188, 0x8E430421, 0x5E684746,
0xF4B9C33E, 0x24928059, 0x19EF45F0, 0xC9C40697,
0xC62A4993, 0x16010AF4, 0x2B7CCF5D, 0xFB578C3A,
0x51860842, 0x81AD4B25, 0xBCD08E8C, 0x6CFBCDEB,
0xA53FCB7C, 0x7514881B, 0x48694DB2, 0x98420ED5,
0x32938AAD, 0xE2B8C9CA, 0xDFC50C63, 0x0FEE4F04,
0xC154926B, 0x117FD10C, 0x2C0214A5, 0xFC2957C2,
0x56F8D3BA, 0x86D390DD, 0xBBAE5574, 0x6B851613,
0xA2411084, 0x726A53E3, 0x4F17964A, 0x9F3CD52D,
0x35ED5155, 0xE5C61232, 0xD8BBD79B, 0x089094FC,
0x077EDBF8, 0xD755989F, 0xEA285D36, 0x3A031E51,
0x90D29A29, 0x40F9D94E, 0x7D841CE7, 0xADAF5F80,
0x646B5917, 0xB4401A70, 0x893DDFD9, 0x59169CBE,
0xF3C718C6, 0x23EC5BA1, 0x1E919E08, 0xCEBADD6F,
0xCFA869D6, 0x1F832AB1, 0x22FEEF18, 0xF2D5AC7F,
0x58042807, 0x882F6B60, 0xB552AEC9, 0x6579EDAE,
0xACBDEB39, 0x7C96A85E, 0x41EB6DF7, 0x91C02E90,
0x3B11AAE8, 0xEB3AE98F, 0xD6472C26, 0x066C6F41,
0x09822045, 0xD9A96322, 0xE4D4A68B, 0x34FFE5EC,
0x9E2E6194, 0x4E0522F3, 0x7378E75A, 0xA353A43D,
0x6A97A2AA, 0xBABCE1CD, 0x87C12464, 0x57EA6703,
0xFD3BE37B, 0x2D10A01C, 0x106D65B5, 0xC04626D2,
0x0EFCFBBD, 0xDED7B8DA, 0xE3AA7D73, 0x33813E14,
0x9950BA6C, 0x497BF90B, 0x74063CA2, 0xA42D7FC5,
0x6DE97952, 0xBDC23A35, 0x80BFFF9C, 0x5094BCFB,
0xFA453883, 0x2A6E7BE4, 0x1713BE4D, 0xC738FD2A,
0xC8D6B22E, 0x18FDF149, 0x258034E0, 0xF5AB7787,
0x5F7AF3FF, 0x8F51B098, 0xB22C7531, 0x62073656,
0xABC330C1, 0x7BE873A6, 0x4695B60F, 0x96BEF568,
0x3C6F7110, 0xEC443277, 0xD139F7DE, 0x0112B4B9,
0xD31DD2E1, 0x03369186, 0x3E4B542F, 0xEE601748,
0x44B19330, 0x949AD057, 0xA9E715FE, 0x79CC5699,
0xB008500E, 0x60231369, 0x5D5ED6C0, 0x8D7595A7,
0x27A411DF, 0xF78F52B8, 0xCAF29711, 0x1AD9D476,
0x15379B72, 0xC51CD815, 0xF8611DBC, 0x284A5EDB,
0x829BDAA3, 0x52B099C4, 0x6FCD5C6D, 0xBFE61F0A,
0x7622199D, 0xA6095AFA, 0x9B749F53, 0x4B5FDC34,
0xE18E584C, 0x31A51B2B, 0x0CD8DE82, 0xDCF39DE5,
0x1249408A, 0xC26203ED, 0xFF1FC644, 0x2F348523,
0x85E5015B, 0x55CE423C, 0x68B38795, 0xB898C4F2,
0x715CC265, 0xA1778102, 0x9C0A44AB, 0x4C2107CC,
0xE6F083B4, 0x36DBC0D3, 0x0BA6057A, 0xDB8D461D,
0xD4630919, 0x04484A7E, 0x39358FD7, 0xE91ECCB0,
0x43CF48C8, 0x93E40BAF, 0xAE99CE06, 0x7EB28D61,
0xB7768BF6, 0x675DC891, 0x5A200D38, 0x8A0B4E5F,
0x20DACA27, 0xF0F18940, 0xCD8C4CE9, 0x1DA70F8E,
0x1CB5BB37, 0xCC9EF850, 0xF1E33DF9, 0x21C87E9E,
0x8B19FAE6, 0x5B32B981, 0x664F7C28, 0xB6643F4F,
0x7FA039D8, 0xAF8B7ABF, 0x92F6BF16, 0x42DDFC71,
0xE80C7809, 0x38273B6E, 0x055AFEC7, 0xD571BDA0,
0xDA9FF2A4, 0x0AB4B1C3, 0x37C9746A, 0xE7E2370D,
0x4D33B375, 0x9D18F012, 0xA06535BB, 0x704E76DC,
0xB98A704B, 0x69A1332C, 0x54DCF685, 0x84F7B5E2,
0x2E26319A, 0xFE0D72FD, 0xC370B754, 0x135BF433,
0xDDE1295C, 0x0DCA6A3B, 0x30B7AF92, 0xE09CECF5,
0x4A4D688D, 0x9A662BEA, 0xA71BEE43, 0x7730AD24,
0xBEF4ABB3, 0x6EDFE8D4, 0x53A22D7D, 0x83896E1A,
0x2958EA62, 0xF973A905, 0xC40E6CAC, 0x14252FCB,
0x1BCB60CF, 0xCBE023A8, 0xF69DE601, 0x26B6A566,
0x8C67211E, 0x5C4C6279, 0x6131A7D0, 0xB11AE4B7,
0x78DEE220, 0xA8F5A147, 0x958864EE, 0x45A32789,
0xEF72A3F1, 0x3F59E096, 0x0224253F, 0xD20F6658,
};
/* $ID$ */
/* Sbox for SOBER-128 */
/*
* This is really the combination of two SBoxes; the least significant
* 24 bits comes from:
* 8->32 Sbox generated by Millan et. al. at Queensland University of
* Technology. See: E. Dawson, W. Millan, L. Burnett, G. Carter,
* "On the Design of 8*32 S-boxes". Unpublished report, by the
* Information Systems Research Centre,
* Queensland University of Technology, 1999.
*
* The most significant 8 bits are the Skipjack "F table", which can be
* found at http://csrc.nist.gov/CryptoToolkit/skipjack/skipjack.pdf .
* In this optimised table, though, the intent is to XOR the word from
* the table selected by the high byte with the input word. Thus, the
* high byte is actually the Skipjack F-table entry XORED with its
* table index.
*/
static const ulong32 Sbox[256] = {
0xa3aa1887, 0xd65e435c, 0x0b65c042, 0x800e6ef4,
0xfc57ee20, 0x4d84fed3, 0xf066c502, 0xf354e8ae,
0xbb2ee9d9, 0x281f38d4, 0x1f829b5d, 0x735cdf3c,
0x95864249, 0xbc2e3963, 0xa1f4429f, 0xf6432c35,
0xf7f40325, 0x3cc0dd70, 0x5f973ded, 0x9902dc5e,
0xda175b42, 0x590012bf, 0xdc94d78c, 0x39aab26b,
0x4ac11b9a, 0x8c168146, 0xc3ea8ec5, 0x058ac28f,
0x52ed5c0f, 0x25b4101c, 0x5a2db082, 0x370929e1,
0x2a1843de, 0xfe8299fc, 0x202fbc4b, 0x833915dd,
0x33a803fa, 0xd446b2de, 0x46233342, 0x4fcee7c3,
0x3ad607ef, 0x9e97ebab, 0x507f859b, 0xe81f2e2f,
0xc55b71da, 0xd7e2269a, 0x1339c3d1, 0x7ca56b36,
0xa6c9def2, 0xb5c9fc5f, 0x5927b3a3, 0x89a56ddf,
0xc625b510, 0x560f85a7, 0xace82e71, 0x2ecb8816,
0x44951e2a, 0x97f5f6af, 0xdfcbc2b3, 0xce4ff55d,
0xcb6b6214, 0x2b0b83e3, 0x549ea6f5, 0x9de041af,
0x792f1f17, 0xf73b99ee, 0x39a65ec0, 0x4c7016c6,
0x857709a4, 0xd6326e01, 0xc7b280d9, 0x5cfb1418,
0xa6aff227, 0xfd548203, 0x506b9d96, 0xa117a8c0,
0x9cd5bf6e, 0xdcee7888, 0x61fcfe64, 0xf7a193cd,
0x050d0184, 0xe8ae4930, 0x88014f36, 0xd6a87088,
0x6bad6c2a, 0x1422c678, 0xe9204de7, 0xb7c2e759,
0x0200248e, 0x013b446b, 0xda0d9fc2, 0x0414a895,
0x3a6cc3a1, 0x56fef170, 0x86c19155, 0xcf7b8a66,
0x551b5e69, 0xb4a8623e, 0xa2bdfa35, 0xc4f068cc,
0x573a6acd, 0x6355e936, 0x03602db9, 0x0edf13c1,
0x2d0bb16d, 0x6980b83c, 0xfeb23763, 0x3dd8a911,
0x01b6bc13, 0xf55579d7, 0xf55c2fa8, 0x19f4196e,
0xe7db5476, 0x8d64a866, 0xc06e16ad, 0xb17fc515,
0xc46feb3c, 0x8bc8a306, 0xad6799d9, 0x571a9133,
0x992466dd, 0x92eb5dcd, 0xac118f50, 0x9fafb226,
0xa1b9cef3, 0x3ab36189, 0x347a19b1, 0x62c73084,
0xc27ded5c, 0x6c8bc58f, 0x1cdde421, 0xed1e47fb,
0xcdcc715e, 0xb9c0ff99, 0x4b122f0f, 0xc4d25184,
0xaf7a5e6c, 0x5bbf18bc, 0x8dd7c6e0, 0x5fb7e420,
0x521f523f, 0x4ad9b8a2, 0xe9da1a6b, 0x97888c02,
0x19d1e354, 0x5aba7d79, 0xa2cc7753, 0x8c2d9655,
0x19829da1, 0x531590a7, 0x19c1c149, 0x3d537f1c,
0x50779b69, 0xed71f2b7, 0x463c58fa, 0x52dc4418,
0xc18c8c76, 0xc120d9f0, 0xafa80d4d, 0x3b74c473,
0xd09410e9, 0x290e4211, 0xc3c8082b, 0x8f6b334a,
0x3bf68ed2, 0xa843cc1b, 0x8d3c0ff3, 0x20e564a0,
0xf8f55a4f, 0x2b40f8e7, 0xfea7f15f, 0xcf00fe21,
0x8a6d37d6, 0xd0d506f1, 0xade00973, 0xefbbde36,
0x84670fa8, 0xfa31ab9e, 0xaedab618, 0xc01f52f5,
0x6558eb4f, 0x71b9e343, 0x4b8d77dd, 0x8cb93da6,
0x740fd52d, 0x425412f8, 0xc5a63360, 0x10e53ad0,
0x5a700f1c, 0x8324ed0b, 0xe53dc1ec, 0x1a366795,
0x6d549d15, 0xc5ce46d7, 0xe17abe76, 0x5f48e0a0,
0xd0f07c02, 0x941249b7, 0xe49ed6ba, 0x37a47f78,
0xe1cfffbd, 0xb007ca84, 0xbb65f4da, 0xb59f35da,
0x33d2aa44, 0x417452ac, 0xc0d674a7, 0x2d61a46a,
0xdc63152a, 0x3e12b7aa, 0x6e615927, 0xa14fb118,
0xa151758d, 0xba81687b, 0xe152f0b3, 0x764254ed,
0x34c77271, 0x0a31acab, 0x54f94aec, 0xb9e994cd,
0x574d9e81, 0x5b623730, 0xce8a21e8, 0x37917f0b,
0xe8a9b5d6, 0x9697adf8, 0xf3d30431, 0x5dcac921,
0x76b35d46, 0xaa430a36, 0xc2194022, 0x22bca65e,
0xdaec70ba, 0xdfaea8cc, 0x777bae8b, 0x242924d5,
0x1f098a5a, 0x4b396b81, 0x55de2522, 0x435c1cb8,
0xaeb8fe1d, 0x9db3c697, 0x5b164f83, 0xe0c16376,
0xa319224c, 0xd0203b35, 0x433ac0fe, 0x1466a19a,
0x45f0b24f, 0x51fda998, 0xc0d52d71, 0xfa0896a8,
0xf9e6053f, 0xa4b0d300, 0xd499cbcc, 0xb95e3d40,
};

15
sprng.c
View File

@ -19,15 +19,15 @@
const struct _prng_descriptor sprng_desc = const struct _prng_descriptor sprng_desc =
{ {
"sprng", "sprng", 0,
&sprng_start, &sprng_start,
&sprng_add_entropy, &sprng_add_entropy,
&sprng_ready, &sprng_ready,
&sprng_read, &sprng_read,
&sprng_done, &sprng_done,
&sprng_export, &sprng_export,
&sprng_import &sprng_import,
&sprng_test
}; };
int sprng_start(prng_state *prng) int sprng_start(prng_state *prng)
@ -51,9 +51,9 @@ unsigned long sprng_read(unsigned char *buf, unsigned long len, prng_state *prng
return rng_get_bytes(buf, len, NULL); return rng_get_bytes(buf, len, NULL);
} }
void sprng_done(prng_state *prng) int sprng_done(prng_state *prng)
{ {
_ARGCHK(prng != NULL); return CRYPT_OK;
} }
int sprng_export(unsigned char *out, unsigned long *outlen, prng_state *prng) int sprng_export(unsigned char *out, unsigned long *outlen, prng_state *prng)
@ -69,6 +69,11 @@ int sprng_import(const unsigned char *in, unsigned long inlen, prng_state *prng)
return CRYPT_OK; return CRYPT_OK;
} }
int sprng_test(void)
{
return CRYPT_OK;
}
#endif #endif

View File

@ -15,14 +15,15 @@
const struct _prng_descriptor yarrow_desc = const struct _prng_descriptor yarrow_desc =
{ {
"yarrow", "yarrow", 64,
&yarrow_start, &yarrow_start,
&yarrow_add_entropy, &yarrow_add_entropy,
&yarrow_ready, &yarrow_ready,
&yarrow_read, &yarrow_read,
&yarrow_done, &yarrow_done,
&yarrow_export, &yarrow_export,
&yarrow_import &yarrow_import,
&yarrow_test
}; };
int yarrow_start(prng_state *prng) int yarrow_start(prng_state *prng)
@ -183,10 +184,12 @@ unsigned long yarrow_read(unsigned char *buf, unsigned long len, prng_state *prn
return len; return len;
} }
void yarrow_done(prng_state *prng) int yarrow_done(prng_state *prng)
{ {
_ARGCHK(prng != NULL); _ARGCHK(prng != NULL);
/* call cipher done when we invent one ;-) */ /* call cipher done when we invent one ;-) */
return CRYPT_OK;
} }
int yarrow_export(unsigned char *out, unsigned long *outlen, prng_state *prng) int yarrow_export(unsigned char *out, unsigned long *outlen, prng_state *prng)
@ -222,10 +225,32 @@ int yarrow_import(const unsigned char *in, unsigned long inlen, prng_state *prng
if ((err = yarrow_start(prng)) != CRYPT_OK) { if ((err = yarrow_start(prng)) != CRYPT_OK) {
return err; return err;
} }
if ((err = yarrow_add_entropy(in, 64, &prng)) != CRYPT_OK) { return yarrow_add_entropy(in, 64, prng);
}
int yarrow_test(void)
{
#ifndef LTC_TEST
return CRYPT_NOP;
#else
int err;
prng_state prng;
if ((err = yarrow_start(&prng)) != CRYPT_OK) {
return err; return err;
} }
return yarrow_ready(&prng);
/* now let's test the hash/cipher that was chosen */
if ((err = cipher_descriptor[prng.yarrow.cipher].test()) != CRYPT_OK) {
return err;
}
if ((err = hash_descriptor[prng.yarrow.hash].test()) != CRYPT_OK) {
return err;
}
yarrow_done(&prng);
return CRYPT_OK;
#endif
} }
#endif #endif