added libtomcrypt-0.98
This commit is contained in:
parent
a21f63bbd8
commit
69f289d6dc
44
changes
44
changes
@ -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
|
||||
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
|
||||
@ -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)
|
||||
-- rsa_exptmod() now pads with leading zeroes as per I2OSP.
|
||||
-- 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.
|
||||
-- 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.
|
||||
|
44
crypt.c
44
crypt.c
@ -141,6 +141,26 @@ const char *crypt_build_settings =
|
||||
" CTR\n"
|
||||
#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"
|
||||
#if defined(YARROW)
|
||||
" Yarrow\n"
|
||||
@ -151,6 +171,12 @@ const char *crypt_build_settings =
|
||||
#if defined(RC4)
|
||||
" RC4\n"
|
||||
#endif
|
||||
#if defined(FORTUNA)
|
||||
" Fortuna\n"
|
||||
#endif
|
||||
#if defined(SOBER128)
|
||||
" SOBER128\n"
|
||||
#endif
|
||||
|
||||
"\nPK Algs:\n"
|
||||
#if defined(MRSA)
|
||||
@ -197,21 +223,6 @@ const char *crypt_build_settings =
|
||||
#if defined(MPI)
|
||||
" MPI "
|
||||
#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)
|
||||
" TRY_UNRANDOM_FIRST "
|
||||
#endif
|
||||
@ -229,6 +240,9 @@ const char *crypt_build_settings =
|
||||
#endif
|
||||
#if defined(NO_FILE)
|
||||
" NO_FILE "
|
||||
#endif
|
||||
#if defined(LTMSSE)
|
||||
" LTMSSE "
|
||||
#endif
|
||||
"\n"
|
||||
"\n\n\n"
|
||||
|
161
crypt.tex
161
crypt.tex
@ -47,7 +47,7 @@
|
||||
\def\gap{\vspace{0.5ex}}
|
||||
\makeindex
|
||||
\begin{document}
|
||||
\title{LibTomCrypt \\ Version 0.97b}
|
||||
\title{LibTomCrypt \\ Version 0.98}
|
||||
\author{Tom St Denis \\
|
||||
\\
|
||||
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.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
\chapter{Pseudo-Random Number Generators}
|
||||
\section{Core Functions}
|
||||
|
||||
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)
|
||||
key generation. There is a universal structure called ``prng\_state''. To initialize a PRNG call:
|
||||
\index{PRNG start}
|
||||
\begin{verbatim}
|
||||
int XXX_start(prng_state *prng);
|
||||
\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
|
||||
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:
|
||||
\index{PRNG add\_entropy}
|
||||
\begin{verbatim}
|
||||
int XXX_add_entropy(const unsigned char *in, unsigned long len,
|
||||
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
|
||||
function to put the entropy into action.
|
||||
\index{PRNG ready}
|
||||
\begin{verbatim}
|
||||
int XXX_ready(prng_state *prng);
|
||||
\end{verbatim}
|
||||
|
||||
Which returns {\bf CRYPTO\_OK} if it is ready. Finally to actually read bytes call:
|
||||
\index{PRNG read}
|
||||
\begin{verbatim}
|
||||
unsigned long XXX_read(unsigned char *out, unsigned long len,
|
||||
prng_state *prng);
|
||||
\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}
|
||||
|
||||
@ -1728,8 +1792,8 @@ checking is guaranteed to see if the entropy is sufficient or if the PRNG is eve
|
||||
|
||||
\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
|
||||
the entropy added is not random.
|
||||
Below is a simple snippet to read 10 bytes from yarrow. Its important to note that this snippet is
|
||||
{\bf NOT} secure since the entropy added is not random.
|
||||
|
||||
\begin{verbatim}
|
||||
#include <mycrypt.h>
|
||||
@ -1762,10 +1826,15 @@ PRNGs have descriptors too (surprised?). Stored in the structure ``prng\_descrip
|
||||
\begin{verbatim}
|
||||
struct _prng_descriptor {
|
||||
char *name;
|
||||
int export_size; /* size in bytes of exported state */
|
||||
int (*start) (prng_state *);
|
||||
int (*add_entropy)(const unsigned char *, unsigned long, prng_state *);
|
||||
int (*ready) (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}
|
||||
|
||||
@ -1779,16 +1848,82 @@ int register_prng(const struct _prng_descriptor *prng);
|
||||
int unregister_prng(const struct _prng_descriptor *prng);
|
||||
\end{verbatim}
|
||||
|
||||
\subsubsection{PRNGs Provided}
|
||||
Currently Yarrow (yarrow\_desc), RC4 (rc4\_desc) and the secure RNG (sprng\_desc) are provided as PRNGs within the
|
||||
library.
|
||||
\subsection{PRNGs Provided}
|
||||
\begin{figure}[here]
|
||||
\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
|
||||
interface. You provide the key for RC4 via the rc4\_add\_entropy() function. By calling rc4\_ready() the key will be used
|
||||
to setup the RC4 state for encryption or decryption. The rc4\_read() function has been modified from RC4 since it will
|
||||
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:
|
||||
\subsubsection{Yarrow}
|
||||
Yarrow is fast PRNG meant to collect an unspecified amount of entropy from sources
|
||||
(keyboard, mouse, interrupts, etc) and produce an unbounded string of random bytes.
|
||||
|
||||
\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{verbatim}
|
||||
#include <mycrypt.h>
|
||||
|
@ -4,7 +4,10 @@
|
||||
|
||||
int cipher_hash_test(void)
|
||||
{
|
||||
int x;
|
||||
int x;
|
||||
unsigned char buf[4096];
|
||||
unsigned long n;
|
||||
prng_state nprng;
|
||||
|
||||
/* test ciphers */
|
||||
for (x = 0; cipher_descriptor[x].name != NULL; x++) {
|
||||
@ -15,6 +18,24 @@ int cipher_hash_test(void)
|
||||
for (x = 0; hash_descriptor[x].name != NULL; x++) {
|
||||
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;
|
||||
}
|
||||
|
@ -1,43 +1,44 @@
|
||||
#include "test.h"
|
||||
|
||||
/* Test store/load macros with offsets */
|
||||
int store_test(void)
|
||||
{
|
||||
unsigned char buf[8];
|
||||
unsigned long L;
|
||||
ulong64 LL;
|
||||
unsigned char buf[24];
|
||||
unsigned long L, L1;
|
||||
int y;
|
||||
ulong64 LL, LL1;
|
||||
|
||||
L = 0x12345678UL;
|
||||
STORE32L (L, &buf[0]);
|
||||
L = 0;
|
||||
LOAD32L (L, &buf[0]);
|
||||
if (L != 0x12345678UL) {
|
||||
printf ("LOAD/STORE32 Little don't work");
|
||||
return 1;
|
||||
}
|
||||
LL = CONST64 (0x01020304050607);
|
||||
STORE64L (LL, &buf[0]);
|
||||
LL = 0;
|
||||
LOAD64L (LL, &buf[0])
|
||||
if (LL != CONST64 (0x01020304050607)) {
|
||||
printf ("LOAD/STORE64 Little don't work");
|
||||
return 1;
|
||||
for (y = 0; y < 4; y++) {
|
||||
STORE32L(L, buf + y);
|
||||
LOAD32L(L1, buf + y);
|
||||
if (L1 != L) {
|
||||
fprintf(stderr, "\n32L failed at offset %d\n", y);
|
||||
return 1;
|
||||
}
|
||||
STORE32H(L, buf + y);
|
||||
LOAD32H(L1, buf + y);
|
||||
if (L1 != L) {
|
||||
fprintf(stderr, "\n32H failed at offset %d\n", y);
|
||||
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);
|
||||
STORE64H (LL, &buf[0]);
|
||||
LL = 0;
|
||||
LOAD64H (LL, &buf[0])
|
||||
if (LL != CONST64 (0x01020304050607)) {
|
||||
printf ("LOAD/STORE64 High don't work");
|
||||
return 1;
|
||||
for (y = 0; y < 8; y++) {
|
||||
STORE64L(LL, buf + y);
|
||||
LOAD64L(LL1, buf + y);
|
||||
if (LL1 != LL) {
|
||||
fprintf(stderr, "\n64L failed at offset %d\n", y);
|
||||
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;
|
||||
}
|
||||
|
@ -112,15 +112,21 @@ void register_algs(void)
|
||||
register_hash (&whirlpool_desc);
|
||||
#endif
|
||||
|
||||
if (register_prng(&yarrow_desc) == -1) {
|
||||
printf("Error registering yarrow PRNG\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
if (register_prng(&sprng_desc) == -1) {
|
||||
printf("Error registering sprng PRNG\n");
|
||||
exit(-1);
|
||||
}
|
||||
#ifdef YARROW
|
||||
register_prng(&yarrow_desc);
|
||||
#endif
|
||||
#ifdef FORTUNA
|
||||
register_prng(&fortuna_desc);
|
||||
#endif
|
||||
#ifdef RC4
|
||||
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 */
|
||||
|
@ -203,7 +203,7 @@ void cipher_gen(void)
|
||||
void hmac_gen(void)
|
||||
{
|
||||
unsigned char key[MAXBLOCKSIZE], output[MAXBLOCKSIZE], *input;
|
||||
int x, y, z, kl, err;
|
||||
int x, y, z, err;
|
||||
FILE *out;
|
||||
unsigned long len;
|
||||
|
||||
|
303
demos/x86_prof.c
303
demos/x86_prof.c
@ -191,16 +191,26 @@ void reg_algs(void)
|
||||
register_hash (&whirlpool_desc);
|
||||
#endif
|
||||
|
||||
#ifndef YARROW
|
||||
#error This demo requires Yarrow.
|
||||
#endif
|
||||
register_prng(&yarrow_desc);
|
||||
#ifdef FORTUNA
|
||||
register_prng(&fortuna_desc);
|
||||
#endif
|
||||
#ifdef RC4
|
||||
register_prng(&rc4_desc);
|
||||
#endif
|
||||
#ifdef SOBER128
|
||||
register_prng(&sober128_desc);
|
||||
#endif
|
||||
|
||||
rng_make_prng(128, find_prng("yarrow"), &prng, NULL);
|
||||
}
|
||||
|
||||
int time_keysched(void)
|
||||
{
|
||||
unsigned long x, i, y1;
|
||||
unsigned long x, y1;
|
||||
ulong64 t1, c1;
|
||||
symmetric_key skey;
|
||||
int kl;
|
||||
@ -241,7 +251,7 @@ int time_cipher(void)
|
||||
symmetric_key skey;
|
||||
void (*func) (const unsigned char *, unsigned char *, symmetric_key *);
|
||||
unsigned char key[MAXBLOCKSIZE], pt[MAXBLOCKSIZE];
|
||||
|
||||
int err;
|
||||
|
||||
printf ("\n\nECB Time Trials for the Symmetric Ciphers:\n");
|
||||
no_results = 0;
|
||||
@ -249,6 +259,12 @@ int time_cipher(void)
|
||||
cipher_descriptor[x].setup (key, cipher_descriptor[x].min_key_length, 0,
|
||||
&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 DO2 DO1 DO1
|
||||
|
||||
@ -303,13 +319,20 @@ int time_hash(void)
|
||||
unsigned long x, y1, len;
|
||||
ulong64 t1, t2, c1, c2;
|
||||
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];
|
||||
|
||||
|
||||
printf ("\n\nHASH Time Trials for:\n");
|
||||
no_results = 0;
|
||||
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);
|
||||
|
||||
#define DO1 func(&md,pt,len);
|
||||
@ -365,7 +388,7 @@ void time_mult(void)
|
||||
t1 = (t_read() - t1)>>1;
|
||||
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);
|
||||
|
||||
@ -395,7 +418,7 @@ void time_sqr(void)
|
||||
t1 = (t_read() - t1)>>1;
|
||||
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);
|
||||
|
||||
@ -407,20 +430,27 @@ void time_prng(void)
|
||||
{
|
||||
ulong64 t1, t2;
|
||||
unsigned char buf[4096];
|
||||
prng_state prng;
|
||||
prng_state tprng;
|
||||
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++) {
|
||||
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);
|
||||
prng_descriptor[x].add_entropy(buf, 256, &prng);
|
||||
prng_descriptor[x].ready(&prng);
|
||||
prng_descriptor[x].add_entropy(buf, 256, &tprng);
|
||||
prng_descriptor[x].ready(&tprng);
|
||||
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
|
||||
|
||||
for (y = 0; y < 10000; y++) {
|
||||
t_start();
|
||||
t1 = t_read();
|
||||
@ -428,14 +458,255 @@ void time_prng(void)
|
||||
t1 = (t_read() - t1)>>1;
|
||||
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 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)
|
||||
{
|
||||
@ -446,10 +717,14 @@ int main(void)
|
||||
// init_timer();
|
||||
time_mult();
|
||||
time_sqr();
|
||||
time_rsa();
|
||||
time_dh();
|
||||
time_ecc();
|
||||
time_prng();
|
||||
time_cipher();
|
||||
time_keysched();
|
||||
time_hash();
|
||||
time_macs();
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
BIN
doc/crypt.pdf
BIN
doc/crypt.pdf
Binary file not shown.
147
fortuna.c
147
fortuna.c
@ -19,22 +19,36 @@ we reseed automatically when len(pool0) >= 64 or every FORTUNA_WD calls to the r
|
||||
|
||||
#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 = {
|
||||
"fortuna",
|
||||
"fortuna", 1024,
|
||||
&fortuna_start,
|
||||
&fortuna_add_entropy,
|
||||
&fortuna_ready,
|
||||
&fortuna_read,
|
||||
&fortuna_done,
|
||||
&fortuna_export,
|
||||
&fortuna_import
|
||||
|
||||
&fortuna_import,
|
||||
&fortuna_test
|
||||
};
|
||||
|
||||
/* update the IV */
|
||||
static void fortuna_update_iv(prng_state *prng)
|
||||
{
|
||||
int x;
|
||||
int x;
|
||||
unsigned char *IV;
|
||||
/* update IV */
|
||||
IV = prng->fortuna.IV;
|
||||
@ -47,7 +61,7 @@ static void fortuna_update_iv(prng_state *prng)
|
||||
/* reseed the PRNG */
|
||||
static int fortuna_reseed(prng_state *prng)
|
||||
{
|
||||
unsigned char tmp[32];
|
||||
unsigned char tmp[MAXBLOCKSIZE];
|
||||
hash_state md;
|
||||
int err, x;
|
||||
|
||||
@ -59,7 +73,7 @@ static int fortuna_reseed(prng_state *prng)
|
||||
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) {
|
||||
/* terminate this hash */
|
||||
if ((err = sha256_done(&prng->fortuna.pool[x], tmp)) != CRYPT_OK) {
|
||||
@ -105,7 +119,7 @@ int fortuna_start(prng_state *prng)
|
||||
_ARGCHK(prng != NULL);
|
||||
|
||||
/* initialize the pools */
|
||||
for (x = 0; x < 32; x++) {
|
||||
for (x = 0; x < FORTUNA_POOLS; x++) {
|
||||
sha256_init(&prng->fortuna.pool[x]);
|
||||
}
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
@ -160,7 +176,7 @@ unsigned long fortuna_read(unsigned char *dst, unsigned long len, prng_state *pr
|
||||
{
|
||||
unsigned char tmp[16];
|
||||
int err;
|
||||
unsigned long tlen, n;
|
||||
unsigned long tlen;
|
||||
|
||||
_ARGCHK(dst != NULL);
|
||||
_ARGCHK(prng != NULL);
|
||||
@ -174,18 +190,21 @@ unsigned long fortuna_read(unsigned char *dst, unsigned long len, prng_state *pr
|
||||
|
||||
/* now generate the blocks required */
|
||||
tlen = len;
|
||||
while (len > 0) {
|
||||
if (len >= 16) {
|
||||
/* encrypt the IV and store it */
|
||||
rijndael_ecb_encrypt(prng->fortuna.IV, dst, &prng->fortuna.skey);
|
||||
dst += 16;
|
||||
len -= 16;
|
||||
} else {
|
||||
rijndael_ecb_encrypt(prng->fortuna.IV, tmp, &prng->fortuna.skey);
|
||||
XMEMCPY(dst, tmp, len);
|
||||
len = 0;
|
||||
}
|
||||
fortuna_update_iv(prng);
|
||||
|
||||
/* handle whole blocks without the extra memcpy */
|
||||
while (len >= 16) {
|
||||
/* encrypt the IV and store it */
|
||||
rijndael_ecb_encrypt(prng->fortuna.IV, dst, &prng->fortuna.skey);
|
||||
dst += 16;
|
||||
len -= 16;
|
||||
fortuna_update_iv(prng);
|
||||
}
|
||||
|
||||
/* left over bytes? */
|
||||
if (len > 0) {
|
||||
rijndael_ecb_encrypt(prng->fortuna.IV, tmp, &prng->fortuna.skey);
|
||||
XMEMCPY(dst, tmp, len);
|
||||
fortuna_update_iv(prng);
|
||||
}
|
||||
|
||||
/* generate new key */
|
||||
@ -201,33 +220,77 @@ unsigned long fortuna_read(unsigned char *dst, unsigned long len, prng_state *pr
|
||||
return tlen;
|
||||
}
|
||||
|
||||
void fortuna_done(prng_state *prng)
|
||||
int fortuna_done(prng_state *prng)
|
||||
{
|
||||
int err, x;
|
||||
unsigned char tmp[32];
|
||||
|
||||
_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 ;-) */
|
||||
|
||||
#ifdef CLEAN_STACK
|
||||
zeromem(tmp, sizeof(tmp));
|
||||
#endif
|
||||
|
||||
return CRYPT_OK;
|
||||
}
|
||||
|
||||
int fortuna_export(unsigned char *out, unsigned long *outlen, prng_state *prng)
|
||||
{
|
||||
int x;
|
||||
int x, err;
|
||||
hash_state *md;
|
||||
|
||||
_ARGCHK(out != NULL);
|
||||
_ARGCHK(outlen != NULL);
|
||||
_ARGCHK(prng != NULL);
|
||||
|
||||
/* we'll write 2048 bytes for s&g's */
|
||||
if (*outlen < 2048) {
|
||||
/* we'll write bytes for s&g's */
|
||||
if (*outlen < 32*FORTUNA_POOLS) {
|
||||
return CRYPT_BUFFER_OVERFLOW;
|
||||
}
|
||||
|
||||
for (x = 0; x < 32; x++) {
|
||||
if (fortuna_read(out+x*64, 64, prng) != 64) {
|
||||
return CRYPT_ERROR_READPRNG;
|
||||
md = XMALLOC(sizeof(hash_state));
|
||||
if (md == NULL) {
|
||||
return CRYPT_MEM;
|
||||
}
|
||||
|
||||
/* 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 = 2048;
|
||||
*outlen = 32*FORTUNA_POOLS;
|
||||
err = CRYPT_OK;
|
||||
|
||||
return 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)
|
||||
@ -237,19 +300,33 @@ int fortuna_import(const unsigned char *in, unsigned long inlen, prng_state *prn
|
||||
_ARGCHK(in != NULL);
|
||||
_ARGCHK(prng != NULL);
|
||||
|
||||
if (inlen != 2048) {
|
||||
if (inlen != 32*FORTUNA_POOLS) {
|
||||
return CRYPT_INVALID_ARG;
|
||||
}
|
||||
|
||||
if ((err = fortuna_start(prng)) != CRYPT_OK) {
|
||||
return err;
|
||||
}
|
||||
for (x = 0; x < 32; x++) {
|
||||
if ((err = fortuna_add_entropy(in+x*64, 64, &prng)) != CRYPT_OK) {
|
||||
for (x = 0; x < FORTUNA_POOLS; x++) {
|
||||
if ((err = fortuna_add_entropy(in+x*32, 32, prng)) != CRYPT_OK) {
|
||||
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
|
||||
|
@ -64,17 +64,17 @@ int hmac_done(hmac_state *hmac, unsigned char *hashOut, unsigned long *outlen)
|
||||
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) {
|
||||
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++) {
|
||||
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);
|
||||
if ((err = hash_descriptor[hash].process(&hmac->md, buf, HMAC_BLOCKSIZE)) != CRYPT_OK) {
|
||||
goto __ERR;
|
||||
@ -86,7 +86,7 @@ int hmac_done(hmac_state *hmac, unsigned char *hashOut, unsigned long *outlen)
|
||||
goto __ERR;
|
||||
}
|
||||
|
||||
// copy to output
|
||||
/* copy to output */
|
||||
for (i = 0; i < hashsize && i < *outlen; i++) {
|
||||
hashOut[i] = buf[i];
|
||||
}
|
||||
|
16
hmac_init.c
16
hmac_init.c
@ -68,9 +68,9 @@ int hmac_init(hmac_state *hmac, int hash, const unsigned char *key, unsigned lon
|
||||
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) {
|
||||
z = (unsigned long)HMAC_BLOCKSIZE;
|
||||
z = HMAC_BLOCKSIZE;
|
||||
if ((err = hash_memory(hash, key, keylen, hmac->key, &z)) != CRYPT_OK) {
|
||||
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++) {
|
||||
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);
|
||||
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:
|
||||
/* free the key since we failed */
|
||||
XFREE(hmac->key);
|
||||
done:
|
||||
#ifdef CLEAN_STACK
|
||||
zeromem(buf, HMAC_BLOCKSIZE);
|
||||
#endif
|
||||
|
@ -291,6 +291,7 @@ Key First"
|
||||
}
|
||||
|
||||
if(memcmp(digest, cases[i].digest, (size_t)hash_descriptor[hash].hashsize) != 0) {
|
||||
failed++;
|
||||
#if 0
|
||||
unsigned int j;
|
||||
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("\n");
|
||||
return CRYPT_ERROR;
|
||||
#endif
|
||||
failed++;
|
||||
//return CRYPT_ERROR;
|
||||
} else {
|
||||
/* printf("HMAC-%s test #%d: Passed\n", cases[i].algo, cases[i].num); */
|
||||
}
|
||||
|
18
makefile
18
makefile
@ -4,7 +4,7 @@
|
||||
# Modified by Clay Culver
|
||||
|
||||
# The version
|
||||
VERSION=0.97b
|
||||
VERSION=0.98
|
||||
|
||||
# Compiler and Linker Names
|
||||
#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_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 \
|
||||
\
|
||||
@ -171,10 +171,10 @@ small: library $(SMALLOBJECTS)
|
||||
$(CC) $(SMALLOBJECTS) $(LIBNAME) -o $(SMALL) $(WARN)
|
||||
|
||||
x86_prof: library $(PROFS)
|
||||
$(CC) $(PROFS) $(LIBNAME) -o $(PROF)
|
||||
$(CC) $(PROFS) $(LIBNAME) $(EXTRALIBS) -o $(PROF)
|
||||
|
||||
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
|
||||
#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
|
||||
latex crypt > /dev/null
|
||||
latex crypt > /dev/null
|
||||
makeindex.idx crypt
|
||||
makeindex crypt.idx
|
||||
latex crypt > /dev/null
|
||||
|
||||
#pretty build
|
||||
pretty:
|
||||
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: clean
|
||||
cd .. ; rm -rf crypt* libtomcrypt-$(VERSION)-beta ; mkdir libtomcrypt-$(VERSION)-beta ; \
|
||||
|
@ -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_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 \
|
||||
\
|
||||
|
@ -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_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 \
|
||||
\
|
||||
@ -188,6 +188,13 @@ x86_prof: library $(PROFS)
|
||||
tv_gen: library $(TVS)
|
||||
$(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
|
||||
#as root in order to have a high enough permission to write to the correct
|
||||
|
@ -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_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 \
|
||||
\
|
||||
|
2
mpi.c
2
mpi.c
@ -4703,7 +4703,7 @@ int mp_mul (mp_int * a, mp_int * b, mp_int * c)
|
||||
res = s_mp_mul (a, b, c);
|
||||
}
|
||||
}
|
||||
c->sign = neg;
|
||||
c->sign = (c->used == 0) ? MP_ZPOS : neg;
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,4 @@
|
||||
/* Defines the _ARGCHK macro used within the library */
|
||||
|
||||
/* ch1-01-1 */
|
||||
/* ARGTYPE is defined in mycrypt_cfg.h */
|
||||
#if ARGTYPE == 0
|
||||
|
||||
@ -20,5 +18,4 @@
|
||||
#define _ARGCHK(x)
|
||||
|
||||
#endif
|
||||
/* ch1-01-1 */
|
||||
|
||||
|
@ -20,12 +20,16 @@ void XFREE(void *p);
|
||||
void *XMEMCPY(void *dest, const void *src, 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 */
|
||||
#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 */
|
||||
#if defined(INTEL_CC) || (defined(_MSC_VER) && defined(WIN32)) || (defined(__GNUC__) && (defined(__DJGPP__) || defined(__CYGWIN__) || defined(__MINGW32__) || defined(__i386__)))
|
||||
#define ENDIAN_LITTLE
|
||||
@ -52,12 +56,6 @@ int XMEMCMP(const void *s1, const void *s2, size_t n);
|
||||
#define ENDIAN_NEUTRAL
|
||||
#endif
|
||||
|
||||
#ifdef YARROW
|
||||
#ifndef CTR
|
||||
#error YARROW requires CTR chaining mode to be defined!
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* packet code */
|
||||
#if defined(MRSA) || defined(MDH) || defined(MECC)
|
||||
#define PACKET
|
||||
|
@ -82,18 +82,29 @@
|
||||
|
||||
/* Various tidbits of modern neatoness */
|
||||
#define BASE64
|
||||
|
||||
/* Yarrow */
|
||||
#define YARROW
|
||||
// which descriptor of AES to use?
|
||||
// 0 = rijndael_enc 1 = aes_enc, 2 = rijndael [full], 3 = aes [full]
|
||||
#define YARROW_AES 0
|
||||
|
||||
#if defined(YARROW) && !defined(CTR)
|
||||
#error YARROW requires CTR chaining mode to be defined!
|
||||
#endif
|
||||
|
||||
#define SPRNG
|
||||
#define RC4
|
||||
|
||||
/* Fortuna */
|
||||
/* Fortuna PRNG */
|
||||
#define FORTUNA
|
||||
/* 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 TRY_URANDOM_FIRST
|
||||
@ -139,6 +150,12 @@
|
||||
/* Use SSE2 optimizations in LTM? Requires GCC or ICC and a P4 or K8 processor */
|
||||
// #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 */
|
||||
#define PKCS_1
|
||||
#define PKCS_5
|
||||
|
@ -11,7 +11,7 @@ struct rc4_prng {
|
||||
};
|
||||
|
||||
struct fortuna_prng {
|
||||
hash_state pool[32]; /* the 32 pools */
|
||||
hash_state pool[FORTUNA_POOLS]; /* the pools */
|
||||
|
||||
symmetric_key skey;
|
||||
|
||||
@ -25,21 +25,44 @@ struct fortuna_prng {
|
||||
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 {
|
||||
#ifdef YARROW
|
||||
struct yarrow_prng yarrow;
|
||||
#endif
|
||||
#ifdef RC4
|
||||
struct rc4_prng rc4;
|
||||
#endif
|
||||
#ifdef FORTUNA
|
||||
struct fortuna_prng fortuna;
|
||||
#endif
|
||||
#ifdef SOBER128
|
||||
struct sober128_prng sober128;
|
||||
#endif
|
||||
} prng_state;
|
||||
|
||||
extern struct _prng_descriptor {
|
||||
char *name;
|
||||
int export_size; /* size in bytes of exported state */
|
||||
int (*start)(prng_state *);
|
||||
int (*add_entropy)(const unsigned char *, unsigned long, prng_state *);
|
||||
int (*ready)(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 (*import)(const unsigned char *, unsigned long, prng_state *);
|
||||
int (*test)(void);
|
||||
} prng_descriptor[];
|
||||
|
||||
#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_ready(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_import(const unsigned char *in, unsigned long inlen, prng_state *prng);
|
||||
int yarrow_test(void);
|
||||
extern const struct _prng_descriptor yarrow_desc;
|
||||
#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_ready(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_import(const unsigned char *in, unsigned long inlen, prng_state *prng);
|
||||
int fortuna_test(void);
|
||||
extern const struct _prng_descriptor fortuna_desc;
|
||||
#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_ready(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_import(const unsigned char *in, unsigned long inlen, prng_state *prng);
|
||||
int rc4_test(void);
|
||||
extern const struct _prng_descriptor rc4_desc;
|
||||
#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_ready(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_import(const unsigned char *in, unsigned long inlen, prng_state *prng);
|
||||
int sprng_test(void);
|
||||
extern const struct _prng_descriptor sprng_desc;
|
||||
#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 register_prng(const struct _prng_descriptor *prng);
|
||||
int unregister_prng(const struct _prng_descriptor *prng);
|
||||
int prng_is_valid(int idx);
|
||||
|
||||
|
||||
/* 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
|
||||
*/
|
||||
/* ch2-02-1 */
|
||||
unsigned long rng_get_bytes(unsigned char *buf,
|
||||
unsigned long rng_get_bytes(unsigned char *buf,
|
||||
unsigned long len,
|
||||
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));
|
||||
|
||||
|
21
noekeon.c
21
noekeon.c
@ -33,7 +33,6 @@ static const ulong32 RC[] = {
|
||||
0x000000d4UL
|
||||
};
|
||||
|
||||
|
||||
#define kTHETA(a, b, c, d) \
|
||||
temp = a^c; temp = temp ^ ROL(temp, 8) ^ ROR(temp, 8); \
|
||||
b ^= temp; d ^= temp; \
|
||||
@ -97,9 +96,7 @@ void noekeon_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_k
|
||||
#endif
|
||||
{
|
||||
ulong32 a,b,c,d,temp;
|
||||
#ifdef SMALL_CODE
|
||||
int r;
|
||||
#endif
|
||||
|
||||
_ARGCHK(key != 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); \
|
||||
PI2(a,b,c,d);
|
||||
|
||||
#ifdef SMALL_CODE
|
||||
for (r = 0; r < 16; ++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
|
||||
|
||||
@ -150,9 +140,7 @@ void noekeon_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_k
|
||||
#endif
|
||||
{
|
||||
ulong32 a,b,c,d, temp;
|
||||
#ifdef SMALL_CODE
|
||||
int r;
|
||||
#endif
|
||||
|
||||
_ARGCHK(key != NULL);
|
||||
_ARGCHK(pt != NULL);
|
||||
@ -169,17 +157,10 @@ void noekeon_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_k
|
||||
GAMMA(a,b,c,d); \
|
||||
PI2(a,b,c,d);
|
||||
|
||||
#ifdef SMALL_CODE
|
||||
for (r = 16; r > 0; --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
|
||||
|
||||
THETA(key->noekeon.dK, a,b,c,d);
|
||||
|
91
notes/tech0004.txt
Normal file
91
notes/tech0004.txt
Normal 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
|
@ -21,8 +21,9 @@ foreach my $filename (glob "*.c") {
|
||||
if (!($filename =~ "sha384.c")) {
|
||||
if (!($filename =~ "dh_sys.c")) {
|
||||
if (!($filename =~ "ecc_sys.c")) {
|
||||
if (!($filename =~ "sober128tab.c")) {
|
||||
++$count;
|
||||
}}}}}}}
|
||||
}}}}}}}}
|
||||
}
|
||||
print "Source files to build: $count\nBuilding...\n";
|
||||
my $i = 0;
|
||||
@ -36,6 +37,7 @@ foreach my $filename (glob "*.c") {
|
||||
if (!($filename =~ "sha384.c")) {
|
||||
if (!($filename =~ "dh_sys.c")) {
|
||||
if (!($filename =~ "ecc_sys.c")) {
|
||||
if (!($filename =~ "sober128tab.c")) {
|
||||
printf("Building %3.2f%%, ", (++$i/$count)*100.0);
|
||||
if ($i % 4 == 0) { print "/, "; }
|
||||
if ($i % 4 == 1) { print "-, "; }
|
||||
@ -71,7 +73,7 @@ foreach my $filename (glob "*.c") {
|
||||
my $delay = time - $starttime;
|
||||
$rate = $i/$delay;
|
||||
}
|
||||
}}}}}}}
|
||||
}}}}}}}}
|
||||
}
|
||||
|
||||
# finish building the library
|
||||
|
119
rc4.c
119
rc4.c
@ -14,14 +14,15 @@
|
||||
|
||||
const struct _prng_descriptor rc4_desc =
|
||||
{
|
||||
"rc4",
|
||||
"rc4", 32,
|
||||
&rc4_start,
|
||||
&rc4_add_entropy,
|
||||
&rc4_ready,
|
||||
&rc4_read,
|
||||
&rc4_done,
|
||||
&rc4_export,
|
||||
&rc4_import
|
||||
&rc4_import,
|
||||
&rc4_test
|
||||
};
|
||||
|
||||
int rc4_start(prng_state *prng)
|
||||
@ -36,11 +37,18 @@ int rc4_start(prng_state *prng)
|
||||
|
||||
int rc4_add_entropy(const unsigned char *buf, unsigned long len, prng_state *prng)
|
||||
{
|
||||
_ARGCHK(buf != NULL);
|
||||
_ARGCHK(buf != NULL);
|
||||
_ARGCHK(prng != NULL);
|
||||
|
||||
|
||||
/* trim as required */
|
||||
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--) {
|
||||
@ -53,26 +61,30 @@ int rc4_add_entropy(const unsigned char *buf, unsigned long len, prng_state *prn
|
||||
|
||||
int rc4_ready(prng_state *prng)
|
||||
{
|
||||
unsigned char key[256], tmp;
|
||||
int keylen, x, y;
|
||||
unsigned char key[256], tmp, *s;
|
||||
int keylen, x, y, j;
|
||||
|
||||
_ARGCHK(prng != NULL);
|
||||
|
||||
/* extract the key */
|
||||
XMEMCPY(key, prng->rc4.buf, 256);
|
||||
s = prng->rc4.buf;
|
||||
XMEMCPY(key, s, 256);
|
||||
keylen = prng->rc4.x;
|
||||
|
||||
/* make RC4 perm and shuffle */
|
||||
for (x = 0; x < 256; x++) {
|
||||
prng->rc4.buf[x] = x;
|
||||
s[x] = x;
|
||||
}
|
||||
|
||||
for (x = y = 0; x < 256; x++) {
|
||||
y = (y + prng->rc4.buf[x] + key[x % keylen]) & 255;
|
||||
tmp = prng->rc4.buf[x]; prng->rc4.buf[x] = prng->rc4.buf[y]; prng->rc4.buf[y] = tmp;
|
||||
for (j = x = y = 0; x < 256; x++) {
|
||||
y = (y + prng->rc4.buf[x] + key[j++]) & 255;
|
||||
if (j == keylen) {
|
||||
j = 0;
|
||||
}
|
||||
tmp = s[x]; s[x] = s[y]; s[y] = tmp;
|
||||
}
|
||||
prng->rc4.x = x;
|
||||
prng->rc4.y = y;
|
||||
prng->rc4.x = 0;
|
||||
prng->rc4.y = 0;
|
||||
|
||||
#ifdef CLEAN_STACK
|
||||
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)
|
||||
{
|
||||
int x, y;
|
||||
unsigned char *s, tmp;
|
||||
unsigned char x, y, *s, tmp;
|
||||
unsigned long n;
|
||||
|
||||
_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;
|
||||
tmp = s[x]; s[x] = s[y]; s[y] = tmp;
|
||||
tmp = (s[x] + s[y]) & 255;
|
||||
*buf++ = s[tmp];
|
||||
*buf++ ^= s[tmp];
|
||||
}
|
||||
prng->rc4.x = x;
|
||||
prng->rc4.y = y;
|
||||
return n;
|
||||
}
|
||||
|
||||
void rc4_done(prng_state *prng)
|
||||
int rc4_done(prng_state *prng)
|
||||
{
|
||||
_ARGCHK(prng != NULL);
|
||||
return CRYPT_OK;
|
||||
}
|
||||
|
||||
int rc4_export(unsigned char *out, unsigned long *outlen, prng_state *prng)
|
||||
{
|
||||
_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;
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
|
@ -13,7 +13,7 @@
|
||||
|
||||
#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,
|
||||
unsigned char *outkey, unsigned long *keylen,
|
||||
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(res != NULL);
|
||||
|
||||
/* default to invalid */
|
||||
*res = 0;
|
||||
|
||||
/* valid hash/prng ? */
|
||||
if ((err = prng_is_valid(prng_idx)) != CRYPT_OK) {
|
||||
return err;
|
||||
|
@ -13,7 +13,7 @@
|
||||
|
||||
#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,
|
||||
unsigned char *outkey, unsigned long *outlen,
|
||||
const unsigned char *lparam, unsigned long lparamlen,
|
||||
|
@ -13,6 +13,7 @@
|
||||
|
||||
#ifdef MRSA
|
||||
|
||||
/* Export an RSA key */
|
||||
int rsa_export(unsigned char *out, unsigned long *outlen, int type, rsa_key *key)
|
||||
{
|
||||
unsigned long y, z;
|
||||
|
@ -14,6 +14,7 @@
|
||||
|
||||
#ifdef MRSA
|
||||
|
||||
/* compute an RSA modular exponentiation */
|
||||
int rsa_exptmod(const unsigned char *in, unsigned long inlen,
|
||||
unsigned char *out, unsigned long *outlen, int which,
|
||||
prng_state *prng, int prng_idx,
|
||||
|
@ -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_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 */
|
||||
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 */
|
||||
|
@ -13,7 +13,7 @@
|
||||
|
||||
#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,
|
||||
unsigned char *sig, unsigned long *siglen,
|
||||
prng_state *prng, int prng_idx,
|
||||
|
@ -26,6 +26,9 @@ int rsa_v15_decrypt_key(const unsigned char *in, unsigned long inlen,
|
||||
_ARGCHK(outkey != NULL);
|
||||
_ARGCHK(key != NULL);
|
||||
_ARGCHK(res != NULL);
|
||||
|
||||
/* default to invalid */
|
||||
*res = 0;
|
||||
|
||||
/* valid prng ? */
|
||||
if ((err = prng_is_valid(prng_idx)) != CRYPT_OK) {
|
||||
|
@ -13,7 +13,7 @@
|
||||
|
||||
#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,
|
||||
const unsigned char *msghash, unsigned long msghashlen,
|
||||
prng_state *prng, int prng_idx,
|
||||
@ -28,6 +28,9 @@ int rsa_v15_verify_hash(const unsigned char *sig, unsigned long siglen,
|
||||
_ARGCHK(sig != NULL);
|
||||
_ARGCHK(stat != NULL);
|
||||
_ARGCHK(key != NULL);
|
||||
|
||||
/* default to invalid */
|
||||
*stat = 0;
|
||||
|
||||
/* valid hash ? */
|
||||
if ((err = hash_is_valid(hash_idx)) != CRYPT_OK) {
|
||||
|
@ -13,7 +13,7 @@
|
||||
|
||||
#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,
|
||||
const unsigned char *msghash, unsigned long msghashlen,
|
||||
prng_state *prng, int prng_idx,
|
||||
@ -28,6 +28,9 @@ int rsa_verify_hash(const unsigned char *sig, unsigned long siglen,
|
||||
_ARGCHK(sig != NULL);
|
||||
_ARGCHK(stat != NULL);
|
||||
_ARGCHK(key != NULL);
|
||||
|
||||
/* default to invalid */
|
||||
*stat = 0;
|
||||
|
||||
/* valid hash ? */
|
||||
if ((err = hash_is_valid(hash_idx)) != CRYPT_OK) {
|
||||
|
444
sober128.c
Normal file
444
sober128.c
Normal 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
154
sober128tab.c
Normal 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
15
sprng.c
@ -19,15 +19,15 @@
|
||||
|
||||
const struct _prng_descriptor sprng_desc =
|
||||
{
|
||||
"sprng",
|
||||
"sprng", 0,
|
||||
&sprng_start,
|
||||
&sprng_add_entropy,
|
||||
&sprng_ready,
|
||||
&sprng_read,
|
||||
&sprng_done,
|
||||
&sprng_export,
|
||||
&sprng_import
|
||||
|
||||
&sprng_import,
|
||||
&sprng_test
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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)
|
||||
@ -69,6 +69,11 @@ int sprng_import(const unsigned char *in, unsigned long inlen, prng_state *prng)
|
||||
return CRYPT_OK;
|
||||
}
|
||||
|
||||
int sprng_test(void)
|
||||
{
|
||||
return CRYPT_OK;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
35
yarrow.c
35
yarrow.c
@ -15,14 +15,15 @@
|
||||
|
||||
const struct _prng_descriptor yarrow_desc =
|
||||
{
|
||||
"yarrow",
|
||||
"yarrow", 64,
|
||||
&yarrow_start,
|
||||
&yarrow_add_entropy,
|
||||
&yarrow_ready,
|
||||
&yarrow_read,
|
||||
&yarrow_done,
|
||||
&yarrow_export,
|
||||
&yarrow_import
|
||||
&yarrow_import,
|
||||
&yarrow_test
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
void yarrow_done(prng_state *prng)
|
||||
int yarrow_done(prng_state *prng)
|
||||
{
|
||||
_ARGCHK(prng != NULL);
|
||||
/* call cipher done when we invent one ;-) */
|
||||
|
||||
return CRYPT_OK;
|
||||
}
|
||||
|
||||
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) {
|
||||
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 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
|
||||
|
Loading…
Reference in New Issue
Block a user