propagate of 3f8f752126017cbe7d93c4086c27a91550df745f and 747ebf284d40a15b338e5a5c7730ecec6eade3d7 from branch 'au.asn.ucc.matt.ltc-orig' to 'au.asn.ucc.matt.ltc-db'

--HG--
branch : libtomcrypt
extra : convert_revision : 6abc32a16c5814f6a46957d95c1cc4c5a3f63191
This commit is contained in:
Matt Johnston
2004-12-19 11:47:33 +00:00
17 changed files with 3360 additions and 127 deletions

View File

@@ -15,7 +15,8 @@ VERSION=0.99
#ARFLAGS=r
# Compilation flags. Note the += does not write over the user's CFLAGS!
CFLAGS += -c -I./ -Wall -Wsign-compare -W -Wshadow
# The rest of the flags come from the parent Dropbear makefile
CFLAGS += -c -I$(srcdir)
# -Werror
# optimize for SPEED
@@ -25,7 +26,7 @@ CFLAGS += -c -I./ -Wall -Wsign-compare -W -Wshadow
#CFLAGS += -fomit-frame-pointer
# optimize for SIZE
CFLAGS += -Os -DSMALL_CODE
#CFLAGS += -Os -DSMALL_CODE
# compile for DEBUGING (required for ccmalloc checking!!!)
#CFLAGS += -g3
@@ -51,7 +52,9 @@ DATAPATH=/usr/share/doc/libtomcrypt/pdf
#List of objects to compile.
#Leave MPI built-in or force developer to link against libtommath?
MPIOBJECT=mpi.o
#MPIOBJECT=mpi.o
#Dropbear uses libtommath
MPIOBJECT=
OBJECTS=error_to_string.o mpi_to_ltc_error.o base64_encode.o base64_decode.o \
\
@@ -138,14 +141,14 @@ COMPRESSED=crypt-$(VERSION).tar.bz2 crypt-$(VERSION).zip
HEADERS=ltc_tommath.h mycrypt_cfg.h \
mycrypt_misc.h mycrypt_prng.h mycrypt_cipher.h mycrypt_hash.h \
mycrypt_macros.h mycrypt_pk.h mycrypt.h mycrypt_argchk.h \
mycrypt_custom.h mycrypt_pkcs.h tommath_class.h tommath_superclass.h
mycrypt_custom.h mycrypt_pkcs.h
#The default rule for make builds the libtomcrypt library.
default:library
#ciphers come in two flavours... enc+dec and enc
aes_enc.o: aes.c aes_tab.c
$(CC) $(CFLAGS) -DENCRYPT_ONLY -c aes.c -o aes_enc.o
$(CC) $(CFLAGS) -DENCRYPT_ONLY -c $(srcdir)/aes.c -o aes_enc.o
#These are the rules to make certain object files.
aes.o: aes.c aes_tab.c
@@ -161,6 +164,7 @@ library: $(LIBNAME)
$(LIBNAME): $(OBJECTS)
$(AR) $(ARFLAGS) $@ $(OBJECTS)
$(RANLIB) $@
#This rule makes the hash program included with libtomcrypt
hashsum: library $(HASHOBJECTS)
@@ -200,19 +204,19 @@ install_lib: library
#This rule cleans the source tree of all compiled code, not including the pdf
#documentation.
clean:
rm -f $(OBJECTS) $(TESTOBJECTS) $(HASHOBJECTS) $(CRYPTOBJECTS) $(SMALLOBJECTS) $(LEFTOVERS) $(LIBNAME)
rm -f $(TEST) $(HASH) $(COMPRESSED) $(PROFS) $(PROF) $(TVS) $(TV)
rm -f *.la *.lo *.o *.a *.dll *stackdump *.lib *.exe *.obj demos/*.obj demos/*.o *.bat *.txt *.il *.da demos/*.il demos/*.da *.dyn *.dpi \
-rm -f $(OBJECTS) $(TESTOBJECTS) $(HASHOBJECTS) $(CRYPTOBJECTS) $(SMALLOBJECTS) $(LEFTOVERS) $(LIBNAME)
-rm -f $(TEST) $(HASH) $(COMPRESSED) $(PROFS) $(PROF) $(TVS) $(TV)
-rm -f *.la *.lo *.o *.a *.dll *stackdump *.lib *.exe *.obj demos/*.obj demos/*.o *.bat *.txt *.il *.da demos/*.il demos/*.da *.dyn *.dpi \
*.gcda *.gcno demos/*.gcno demos/*.gcda *~ doc/*
cd demos/test ; make clean
rm -rf .libs demos/.libs demos/test/.libs
-cd demos/test && make clean
-rm -rf .libs demos/.libs demos/test/.libs
#This builds the crypt.pdf file. Note that the rm -f *.pdf has been removed
#from the clean command! This is because most people would like to keep the
#nice pre-compiled crypt.pdf that comes with libtomcrypt! We only need to
#delete it if we are rebuilding it.
docs: crypt.tex
rm -f doc/crypt.pdf $(LEFTOVERS)
-rm -f doc/crypt.pdf $(LEFTOVERS)
echo "hello" > crypt.ind
latex crypt > /dev/null
latex crypt > /dev/null
@@ -220,7 +224,7 @@ docs: crypt.tex
latex crypt > /dev/null
dvipdf crypt
mv -ivf crypt.pdf doc/crypt.pdf
rm -f $(LEFTOVERS)
-rm -f $(LEFTOVERS)
docdvi: crypt.tex
echo hello > crypt.ind

38
PLAN Normal file
View File

@@ -0,0 +1,38 @@
The following functions are marked for removal and/or behavioural change by v1.00 of LibTomCrypt
1. RSA Support
rsa_pad, rsa_signpad, rsa_depad, rsa_signdepad, rsa_import, rsa_export
They will be replaced with PKCS #1 compliant OAEP/PSS padding function as early as v0.96
2. DSA Support
dsa_import, dsa_export
Will be replaced with suitable DSS [what is the standard?] compliant formats. Planned for v0.96
3. Key Ring Support
(all)
The entire API will be dropped as early as v0.96. It was just an experiment and nobody uses it anyways.
4. Test Harness
demos/test.c
The test harness is well overdue for a makeover. Planned for as early as v0.97
Put things in order...
v0.96 -- removed keyring.c and gf.c
-- removed LTC RSA padding
-- DSS support [whatever this entails]
-- Bug fixes/updates to the PKCS/DSS support, should be stable in this release
v0.97 -- Re-written test harness
-- More demos in the manual and demos/ directory
... future???

55
ampi.c Normal file
View File

@@ -0,0 +1,55 @@
/* Code submitted by Svante Seleborg, cleaned up by Tom St Denis */
#include "mycrypt.h"
#include <stdarg.h>
#ifdef MPI
mp_err mp_init_multi(mp_int *mp, ...)
{
mp_err res = MP_OKAY; /* Assume ok until proven otherwise */
int n = 0; /* Number of ok inits */
mp_int* cur_arg = mp;
va_list args;
va_start(args, mp); /* init args to next argument from caller */
while (cur_arg != NULL) {
if (mp_init(cur_arg) != MP_OKAY) {
/* Oops - error! Back-track and mp_clear what we already
succeeded in init-ing, then return error.
*/
va_list clean_args;
cur_arg = mp;
va_start(clean_args, mp);
while (n--) {
mp_clear(cur_arg);
cur_arg = va_arg(clean_args, mp_int*);
}
va_end(clean_args);
res = MP_MEM;
break;
}
n++;
cur_arg = va_arg(args, mp_int*);
}
va_end(args);
return res; /* Assumed ok, if error flagged above. */
}
/*
Clear all arguments given, ended by a NULL marker.
*/
void mp_clear_multi(mp_int *mp, ...)
{
mp_int* next_mp = mp;
va_list args;
va_start(args, mp);
while (next_mp != NULL) {
mp_clear(next_mp);
next_mp = va_arg(args, mp_int*);
}
va_end(args);
}
#endif

121
base64.c Normal file
View File

@@ -0,0 +1,121 @@
/* 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
*/
/* compliant base64 code donated by Wayne Scott (wscott@bitmover.com) */
#include "mycrypt.h"
#ifdef BASE64
static const char *codes =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
static const unsigned char map[256] = {
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 62, 255, 255, 255, 63,
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255,
255, 254, 255, 255, 255, 0, 1, 2, 3, 4, 5, 6,
7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255, 255,
255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,
37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
49, 50, 51, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255 };
int base64_encode(const unsigned char *in, unsigned long len,
unsigned char *out, unsigned long *outlen)
{
unsigned long i, len2, leven;
unsigned char *p;
_ARGCHK(in != NULL);
_ARGCHK(out != NULL);
_ARGCHK(outlen != NULL);
/* valid output size ? */
len2 = 4 * ((len + 2) / 3);
if (*outlen < len2 + 1) {
return CRYPT_BUFFER_OVERFLOW;
}
p = out;
leven = 3*(len / 3);
for (i = 0; i < leven; i += 3) {
*p++ = codes[(in[0] >> 2) & 0x3F];
*p++ = codes[(((in[0] & 3) << 4) + (in[1] >> 4)) & 0x3F];
*p++ = codes[(((in[1] & 0xf) << 2) + (in[2] >> 6)) & 0x3F];
*p++ = codes[in[2] & 0x3F];
in += 3;
}
/* Pad it if necessary... */
if (i < len) {
unsigned a = in[0];
unsigned b = (i+1 < len) ? in[1] : 0;
*p++ = codes[(a >> 2) & 0x3F];
*p++ = codes[(((a & 3) << 4) + (b >> 4)) & 0x3F];
*p++ = (i+1 < len) ? codes[(((b & 0xf) << 2)) & 0x3F] : '=';
*p++ = '=';
}
/* append a NULL byte */
*p = '\0';
/* return ok */
*outlen = p - out;
return CRYPT_OK;
}
int base64_decode(const unsigned char *in, unsigned long len,
unsigned char *out, unsigned long *outlen)
{
unsigned long t, x, y, z;
unsigned char c;
int g;
_ARGCHK(in != NULL);
_ARGCHK(out != NULL);
_ARGCHK(outlen != NULL);
g = 3;
for (x = y = z = t = 0; x < len; x++) {
c = map[in[x]&0xFF];
if (c == 255) continue;
if (c == 254) { c = 0; g--; }
t = (t<<6)|c;
if (++y == 4) {
if (z + g > *outlen) {
return CRYPT_BUFFER_OVERFLOW;
}
out[z++] = (unsigned char)((t>>16)&255);
if (g > 1) out[z++] = (unsigned char)((t>>8)&255);
if (g > 2) out[z++] = (unsigned char)(t&255);
y = t = 0;
}
}
if (y != 0) {
return CRYPT_INVALID_PACKET;
}
*outlen = z;
return CRYPT_OK;
}
#endif

View File

@@ -10,6 +10,8 @@
*/
#include "mycrypt.h"
/* Dropbear doesn't need these
const char *crypt_build_settings =
"LibTomCrypt " SCRYPT "\n\n"
"Endianess: "
@@ -250,4 +252,5 @@ const char *crypt_build_settings =
"\n"
"\n\n\n"
;
*/

Binary file not shown.

305
gf.c Normal file
View File

@@ -0,0 +1,305 @@
/* 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
*/
/* polynomial basis GF(2^w) routines */
#include "mycrypt.h"
#ifdef GF
#define FORLOOP for (i = 0; i < LSIZE; i++)
/* c = a + b */
void gf_add(gf_intp a, gf_intp b, gf_intp c)
{
int i;
FORLOOP c[i] = a[i]^b[i];
}
/* b = a */
void gf_copy(gf_intp a, gf_intp b)
{
int i;
FORLOOP b[i] = a[i];
}
/* a = 0 */
void gf_zero(gf_intp a)
{
int i;
FORLOOP a[i] = 0;
}
/* is a zero? */
int gf_iszero(gf_intp a)
{
int i;
FORLOOP if (a[i]) {
return 0;
}
return 1;
}
/* is a one? */
int gf_isone(gf_intp a)
{
int i;
for (i = 1; i < LSIZE; i++) {
if (a[i]) {
return 0;
}
}
return a[0] == 1;
}
/* b = a << 1*/
void gf_shl(gf_intp a, gf_intp b)
{
int i;
gf_int tmp;
gf_copy(a, tmp);
for (i = LSIZE-1; i > 0; i--)
b[i] = ((tmp[i]<<1)|((tmp[i-1]&0xFFFFFFFFUL)>>31))&0xFFFFFFFFUL;
b[0] = (tmp[0] << 1)&0xFFFFFFFFUL;
gf_zero(tmp);
}
/* b = a >> 1 */
void gf_shr(gf_intp a, gf_intp b)
{
int i;
gf_int tmp;
gf_copy(a, tmp);
for (i = 0; i < LSIZE-1; i++)
b[i] = (((tmp[i]&0xFFFFFFFFUL)>>1)|(tmp[i+1]<<31))&0xFFFFFFFFUL;
b[LSIZE-1] = (tmp[LSIZE-1]&0xFFFFFFFFUL)>>1;
gf_zero(tmp);
}
/* returns -1 if its zero, otherwise degree of a */
int gf_deg(gf_intp a)
{
int i, ii;
unsigned long t;
ii = -1;
for (i = LSIZE-1; i >= 0; i--)
if (a[i]) {
for (t = a[i], ii = 0; t; t >>= 1, ++ii);
break;
}
if (i == -1) i = 0;
return (i<<5)+ii;
}
/* c = ab */
void gf_mul(gf_intp a, gf_intp b, gf_intp c)
{
gf_int ta, tb;
int i, n;
gf_copy(a, ta);
gf_copy(b, tb);
gf_zero(c);
n = gf_deg(ta)+1;
for (i = 0; i < n; i++) {
if (ta[i>>5]&(1<<(i&31)))
gf_add(c, tb, c);
gf_shl(tb, tb);
}
gf_zero(ta);
gf_zero(tb);
}
/* q = a/b, r = a%b */
void gf_div(gf_intp a, gf_intp b, gf_intp q, gf_intp r)
{
gf_int ta, tb, shifts[LSIZE*32];
int i, magb, mag;
mag = gf_deg(a);
magb = gf_deg(b);
/* special cases */
if (magb > mag) {
gf_copy(a, r);
gf_zero(q);
return;
}
if (magb == -1) {
return;
}
/* copy locally */
gf_copy(a, ta);
gf_copy(b, tb);
gf_zero(q);
/* make shifted versions of "b" */
gf_copy(tb, shifts[0]);
for (i = 1; i <= (mag-magb); i++)
gf_shl(shifts[i-1], shifts[i]);
while (mag >= magb) {
i = (mag - magb);
q[i>>5] |= (1<<(i&31));
gf_add(ta, shifts[i], ta);
mag = gf_deg(ta);
}
gf_copy(ta, r);
gf_zero(ta);
gf_zero(tb);
zeromem(shifts, sizeof(shifts));
}
/* b = a mod m */
void gf_mod(gf_intp a, gf_intp m, gf_intp b)
{
gf_int tmp;
gf_div(a,m,tmp,b);
gf_zero(tmp);
}
/* c = ab (mod m) */
void gf_mulmod(gf_intp a, gf_intp b, gf_intp m, gf_intp c)
{
gf_int tmp;
gf_mul(a, b, tmp);
gf_mod(tmp, m, c);
gf_zero(tmp);
}
/* B = 1/A mod M */
void gf_invmod(gf_intp A, gf_intp M, gf_intp B)
{
gf_int m, n, p0, p1, p2, r, q, tmp;
/* put all variables in known setup state */
gf_zero(p0);
gf_zero(p2);
gf_copy(M, m);
gf_copy(A, n);
p0[0] = 1;
gf_div(m, n, p1, r);
gf_copy(p1, q);
/* loop until r == 0 */
while (!gf_iszero(r)) {
gf_copy(n, m);
gf_copy(r, n);
gf_div(m, n, q, r);
gf_mul(q, p1, tmp);
gf_add(tmp, p0, p2);
gf_copy(p1, p0);
gf_copy(p2, p1);
}
gf_copy(p0, B);
gf_zero(p0);
}
/* find a square root modulo a prime. Note the number of
* elements is 2^k - 1, so we must square k-2 times to get the
* square root..
*/
void gf_sqrt(gf_intp a, gf_intp M, gf_intp b)
{
int k;
k = gf_deg(M)-2;
gf_copy(a, b);
while (k--)
gf_mulmod(b, b, M, b);
}
/* c = gcd(A,B) */
void gf_gcd(gf_intp A, gf_intp B, gf_intp c)
{
gf_int a, b, r;
int n;
gf_add(A, B, r);
n = gf_deg(r);
if (gf_deg(A) > n) {
gf_copy(A, a);
gf_copy(B, b);
} else {
gf_copy(A, b);
gf_copy(B, a);
}
do {
gf_mod(a, b, r);
gf_copy(b, a);
gf_copy(r, b);
} while (!gf_iszero(r));
gf_copy(a, c);
gf_zero(a);
gf_zero(b);
}
/* returns non-zero if 'a' is irreducible */
int gf_is_prime(gf_intp a)
{
gf_int u, tmp;
int m, n;
gf_zero(u);
u[0] = 2; /* u(x) = x */
m = gf_deg(a);
for (n = 0; n < (m/2); n++) {
gf_mulmod(u, u, a, u); /* u(x) = u(x)^2 mod a(x) */
gf_copy(u, tmp);
tmp[0] ^= 2; /* tmp(x) = u(x) - x */
gf_gcd(tmp, a, tmp); /* tmp(x) = gcd(a(x), u(x) - x) */
if (!gf_isone(tmp)) {
return 0;
}
}
return 1;
}
/* returns bytes required to store a gf_int */
int gf_size(gf_intp a)
{
int n;
n = gf_deg(a);
if (n == -1) {
return 4;
}
n = n + (32 - (n&31));
return n/8;
}
/* store a gf_int */
void gf_toraw(gf_intp a, unsigned char *dst)
{
int x, n;
n = gf_size(a)/4;
for (x = 0; x < n; x++) {
STORE32L(a[x], dst);
dst += 4;
}
}
/* read a gf_int (len == in bytes) */
void gf_readraw(gf_intp a, unsigned char *str, int len)
{
int x;
gf_zero(a);
for (x = 0; x < len/4; x++) {
LOAD32L(a[x], str);
str += 4;
}
}
#endif

862
keyring.c Normal file
View File

@@ -0,0 +1,862 @@
/* 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
*/
/* Provides keyring functionality for libtomcrypt, Tom St Denis */
#include <mycrypt.h>
#ifdef KR
static const unsigned char key_magic[4] = { 0x12, 0x34, 0x56, 0x78 };
static const unsigned char file_magic[4] = { 0x9A, 0xBC, 0xDE, 0xF0 };
static const unsigned char sign_magic[4] = { 0x87, 0x56, 0x43, 0x21 };
static const unsigned char enc_magic[4] = { 0x0F, 0xED, 0xCB, 0xA9 };
static const unsigned long crc_table[256] = {
0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL,
0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL,
0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL,
0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL,
0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL, 0x136c9856UL,
0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL,
0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL,
0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL,
0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL,
0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL, 0x26d930acUL, 0x51de003aUL,
0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL,
0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL,
0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL,
0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL,
0x9fbfe4a5UL, 0xe8b8d433UL, 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL,
0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL,
0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL,
0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL,
0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL,
0xfbd44c65UL, 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL,
0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL,
0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL,
0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL,
0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL,
0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL,
0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL,
0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL,
0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL,
0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL, 0xf00f9344UL,
0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL,
0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL,
0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL,
0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL,
0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL, 0xd80d2bdaUL, 0xaf0a1b4cUL,
0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL,
0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL,
0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL,
0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL,
0x2cd99e8bUL, 0x5bdeae1dUL, 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL,
0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL,
0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL,
0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL,
0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL,
0x18b74777UL, 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL,
0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL,
0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL,
0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL,
0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL,
0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL,
0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL,
0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL,
0x2d02ef8dUL
};
#define DO1(buf) crc = crc_table[(crc ^ (*buf++)) & 0xff] ^ (crc >> 8);
#define DO2(buf) DO1(buf); DO1(buf);
#define DO4(buf) DO2(buf); DO2(buf);
#define DO8(buf) DO4(buf); DO4(buf);
static unsigned long crc32 (unsigned long crc, const unsigned char *buf, unsigned long len)
{
//_ARGCHK(buf != NULL && len == 0);
crc = crc ^ 0xffffffffL;
while (len >= 8) {
DO8 (buf);
len -= 8;
}
if (len > 0) {
do {
DO1 (buf);
} while (--len > 0);
}
return crc ^ 0xffffffffUL;
}
int kr_init(pk_key **pk)
{
_ARGCHK(pk != NULL);
*pk = XCALLOC(1, sizeof(pk_key));
if (*pk == NULL) {
return CRYPT_MEM;
}
(*pk)->system = NON_KEY;
return CRYPT_OK;
}
unsigned long kr_crc(const unsigned char *name, const unsigned char *email, const unsigned char *description)
{
unsigned long crc;
_ARGCHK(name != NULL);
_ARGCHK(email != NULL);
_ARGCHK(description != NULL);
crc = crc32(0UL, NULL, 0UL);
crc = crc32(crc, name, (unsigned long)MIN(MAXLEN, strlen((char *)name)));
crc = crc32(crc, email, (unsigned long)MIN(MAXLEN, strlen((char *)email)));
return crc32(crc, description, (unsigned long)MIN(MAXLEN, strlen((char *)description)));
}
pk_key *kr_find(pk_key *pk, unsigned long ID)
{
_ARGCHK(pk != NULL);
while (pk != NULL) {
if (pk->system != NON_KEY && pk->ID == ID) {
return pk;
}
pk = pk->next;
}
return NULL;
}
pk_key *kr_find_name(pk_key *pk, const char *name)
{
_ARGCHK(pk != NULL);
_ARGCHK(name != NULL);
while (pk != NULL) {
if (pk->system != NON_KEY && strncmp((char *)pk->name, (char *)name, sizeof(pk->name)-1) == 0) {
return pk;
}
pk = pk->next;
}
return NULL;
}
int kr_add(pk_key *pk, int key_type, int sys, const unsigned char *name,
const unsigned char *email, const unsigned char *description, const _pk_key *key)
{
_ARGCHK(pk != NULL);
_ARGCHK(name != NULL);
_ARGCHK(email != NULL);
_ARGCHK(description != NULL);
_ARGCHK(key != NULL);
/* check parameters */
if (key_type != PK_PRIVATE && key_type != PK_PRIVATE_OPTIMIZED && key_type != PK_PUBLIC) {
return CRYPT_PK_INVALID_TYPE;
}
if (sys != RSA_KEY && sys != DH_KEY && sys != ECC_KEY) {
return CRYPT_PK_INVALID_SYSTEM;
}
/* see if its a dupe */
if (kr_find(pk, kr_crc(name, email, description)) != NULL) {
return CRYPT_PK_DUP;
}
/* find spot in key ring */
while (pk->system != NON_KEY) {
if (pk->next == NULL) {
return CRYPT_ERROR;
}
pk = pk->next;
}
/* now we have a spot make a next spot */
pk->next = XCALLOC(1, sizeof(pk_key));
if (pk->next == NULL) {
return CRYPT_MEM;
}
pk->next->system = NON_KEY;
/* now add this new data to this ring spot */
pk->key_type = key_type;
pk->system = sys;
strncpy((char *)pk->name, (char *)name, sizeof(pk->name)-1);
strncpy((char *)pk->email, (char *)email, sizeof(pk->email)-1);
strncpy((char *)pk->description, (char *)description, sizeof(pk->description)-1);
pk->ID = kr_crc(pk->name, pk->email, pk->description);
/* clear the memory area */
zeromem(&(pk->key), sizeof(pk->key));
/* copy the key */
switch (sys) {
case RSA_KEY:
memcpy(&(pk->key.rsa), &(key->rsa), sizeof(key->rsa));
break;
case DH_KEY:
memcpy(&(pk->key.dh), &(key->dh), sizeof(key->dh));
break;
case ECC_KEY:
memcpy(&(pk->key.ecc), &(key->ecc), sizeof(key->ecc));
break;
}
return CRYPT_OK;
}
int kr_del(pk_key **_pk, unsigned long ID)
{
pk_key *ppk, *pk;
_ARGCHK(_pk != NULL);
pk = *_pk;
ppk = NULL;
while (pk->system != NON_KEY && pk->ID != ID) {
ppk = pk;
pk = pk->next;
if (pk == NULL) {
return CRYPT_PK_NOT_FOUND;
}
}
switch (pk->system) {
case RSA_KEY:
rsa_free(&(pk->key.rsa));
break;
case DH_KEY:
dh_free(&(pk->key.dh));
break;
case ECC_KEY:
ecc_free(&(pk->key.ecc));
break;
}
if (ppk == NULL) { /* the first element matches the ID */
ppk = pk->next; /* get the 2nd element */
XFREE(pk); /* free the first */
*_pk = ppk; /* make the first element the second */
} else { /* (not) first element matches the ID */
ppk->next = pk->next; /* make the previous'es next point to the current next */
XFREE(pk); /* free the element */
}
return CRYPT_OK;
}
int kr_clear(pk_key **pk)
{
int err;
_ARGCHK(pk != NULL);
while ((*pk)->system != NON_KEY) {
if ((err = kr_del(pk, (*pk)->ID)) != CRYPT_OK) {
return err;
}
}
XFREE(*pk);
*pk = NULL;
return CRYPT_OK;
}
static unsigned long _write(unsigned char *buf, unsigned long len, FILE *f, symmetric_CTR *ctr)
{
#ifdef NO_FILE
return 0;
#else
_ARGCHK(buf != NULL);
_ARGCHK(f != NULL);
if (ctr != NULL) {
if (ctr_encrypt(buf, buf, len, ctr) != CRYPT_OK) {
return 0;
}
}
return (unsigned long)fwrite(buf, 1, (size_t)len, f);
#endif
}
static unsigned long _read(unsigned char *buf, unsigned long len, FILE *f, symmetric_CTR *ctr)
{
#ifdef NO_FILE
return 0;
#else
unsigned long y;
_ARGCHK(buf != NULL);
_ARGCHK(f != NULL);
y = (unsigned long)fread(buf, 1, (size_t)len, f);
if (ctr != NULL) {
if (ctr_decrypt(buf, buf, y, ctr) != CRYPT_OK) {
return 0;
}
}
return y;
#endif
}
int kr_export(pk_key *pk, unsigned long ID, int key_type, unsigned char *out, unsigned long *outlen)
{
unsigned char buf[8192], *obuf;
pk_key *ppk;
unsigned long len;
int err;
_ARGCHK(pk != NULL);
_ARGCHK(out != NULL);
_ARGCHK(outlen != NULL);
/* find the desired key */
ppk = kr_find(pk, ID);
if (ppk == NULL) {
return CRYPT_PK_NOT_FOUND;
}
if (ppk->key_type == PK_PUBLIC && key_type != PK_PUBLIC) {
return CRYPT_PK_NOT_PRIVATE;
}
/* this makes PK_PRIVATE an alias for PK_PRIVATE_OPTIMIZED type */
if (ppk->key_type == PK_PRIVATE_OPTIMIZED && key_type == PK_PRIVATE) {
key_type = PK_PRIVATE_OPTIMIZED;
}
/* now copy the header and various other details */
memcpy(buf, key_magic, 4); /* magic info */
buf[4] = key_type; /* key type */
buf[5] = ppk->system; /* system */
STORE32L(ppk->ID, buf+6); /* key ID */
memcpy(buf+10, ppk->name, MAXLEN); /* the name */
memcpy(buf+10+MAXLEN, ppk->email, MAXLEN); /* the email */
memcpy(buf+10+MAXLEN+MAXLEN, ppk->description, MAXLEN); /* the description */
/* export key */
len = sizeof(buf) - (6 + 4 + MAXLEN*3);
obuf = buf+6+4+MAXLEN*3;
switch (ppk->system) {
case RSA_KEY:
if ((err = rsa_export(obuf, &len, key_type, &(ppk->key.rsa))) != CRYPT_OK) {
return err;
}
break;
case DH_KEY:
if ((err = dh_export(obuf, &len, key_type, &(ppk->key.dh))) != CRYPT_OK) {
return err;
}
break;
case ECC_KEY:
if ((err = ecc_export(obuf, &len, key_type, &(ppk->key.ecc))) != CRYPT_OK) {
return err;
}
break;
}
/* get the entire length of the packet */
len += 6 + 4 + 3*MAXLEN;
if (*outlen < len) {
#ifdef CLEAN_STACK
zeromem(buf, sizeof(buf));
#endif
return CRYPT_BUFFER_OVERFLOW;
} else {
*outlen = len;
memcpy(out, buf, len);
#ifdef CLEAN_STACK
zeromem(buf, sizeof(buf));
#endif
return CRYPT_OK;
}
}
int kr_import(pk_key *pk, const unsigned char *in, unsigned long inlen)
{
_pk_key key;
int sys, key_type, err;
unsigned long ID;
_ARGCHK(pk != NULL);
_ARGCHK(in != NULL);
if (inlen < 10) {
return CRYPT_INVALID_PACKET;
}
if (memcmp(in, key_magic, 4) != 0) {
return CRYPT_INVALID_PACKET;
}
key_type = in[4]; /* get type */
sys = in[5]; /* get system */
LOAD32L(ID,in+6); /* the ID */
if (ID != kr_crc(in+10, in+10+MAXLEN, in+10+MAXLEN+MAXLEN)) {
return CRYPT_INVALID_PACKET;
}
zeromem(&key, sizeof(key));
/* size of remaining packet */
inlen -= 10 + 3*MAXLEN;
switch (sys) {
case RSA_KEY:
if ((err = rsa_import(in+10+3*MAXLEN, inlen, &(key.rsa))) != CRYPT_OK) {
return err;
}
break;
case DH_KEY:
if ((err = dh_import(in+10+3*MAXLEN, inlen, &(key.dh))) != CRYPT_OK) {
return err;
}
break;
case ECC_KEY:
if ((err = ecc_import(in+10+3*MAXLEN, inlen, &(key.ecc))) != CRYPT_OK) {
return err;
}
break;
}
return kr_add(pk, key_type, sys,
in+10, /* the name */
in+10+MAXLEN, /* email address */
in+10+MAXLEN+MAXLEN, /* description */
&key);
}
int kr_load(pk_key **pk, FILE *in, symmetric_CTR *ctr)
{
unsigned char buf[8192], blen[4];
unsigned long len;
int res, err;
_ARGCHK(pk != NULL);
_ARGCHK(in != NULL);
/* init keyring */
if ((err = kr_init(pk)) != CRYPT_OK) {
return err;
}
/* read in magic bytes */
if (_read(buf, 6, in, ctr) != 6) { goto done2; }
if (memcmp(buf, file_magic, 4) != 0) {
return CRYPT_INVALID_PACKET;
}
len = (unsigned long)buf[4] | ((unsigned long)buf[5] << 8);
if (len > CRYPT) {
return CRYPT_INVALID_PACKET;
}
/* while there are lengths to read... */
while (_read(blen, 4, in, ctr) == 4) {
/* get length */
LOAD32L(len, blen);
if (len > (unsigned long)sizeof(buf)) {
return CRYPT_INVALID_PACKET;
}
if (_read(buf, len, in, ctr) != len) { goto done2; }
if ((err = kr_import(*pk, buf, len)) != CRYPT_OK) {
return err;
}
}
res = CRYPT_OK;
goto done;
done2:
res = CRYPT_ERROR;
done:
#ifdef CLEAN_STACK
zeromem(buf, sizeof(buf));
#endif
return res;
}
int kr_save(pk_key *pk, FILE *out, symmetric_CTR *ctr)
{
unsigned char buf[8192], blen[4];
unsigned long len;
int res, err;
_ARGCHK(pk != NULL);
_ARGCHK(out != NULL);
/* write out magic bytes */
memcpy(buf, file_magic, 4);
buf[4] = (unsigned char)(CRYPT&255);
buf[5] = (unsigned char)((CRYPT>>8)&255);
if (_write(buf, 6, out, ctr) != 6) { goto done2; }
while (pk->system != NON_KEY) {
len = sizeof(buf);
if ((err = kr_export(pk, pk->ID, pk->key_type, buf, &len)) != CRYPT_OK) {
return err;
}
STORE32L(len, blen);
if (_write(blen, 4, out, ctr) != 4) { goto done2; }
if (_write(buf, len, out, ctr) != len) { goto done2; }
pk = pk->next;
}
res = CRYPT_OK;
goto done;
done2:
res = CRYPT_ERROR;
done:
#ifdef CLEAN_STACK
zeromem(buf, sizeof(buf));
#endif
return res;
}
int kr_make_key(pk_key *pk, prng_state *prng, int wprng,
int sys, int keysize, const unsigned char *name,
const unsigned char *email, const unsigned char *description)
{
_pk_key key;
int key_type, err;
_ARGCHK(pk != NULL);
_ARGCHK(name != NULL);
_ARGCHK(email != NULL);
_ARGCHK(description != NULL);
/* valid PRNG? */
if ((err = prng_is_valid(wprng)) != CRYPT_OK) {
return err;
}
/* make the key first */
zeromem(&key, sizeof(key));
switch (sys) {
case RSA_KEY:
if ((err = rsa_make_key(prng, wprng, keysize, 65537, &(key.rsa))) != CRYPT_OK) {
return err;
}
key_type = key.rsa.type;
break;
case DH_KEY:
if ((err = dh_make_key(prng, wprng, keysize, &(key.dh))) != CRYPT_OK) {
return err;
}
key_type = key.dh.type;
break;
case ECC_KEY:
if ((err = ecc_make_key(prng, wprng, keysize, &(key.ecc))) != CRYPT_OK) {
return err;
}
key_type = key.ecc.type;
break;
default:
return CRYPT_PK_INVALID_SYSTEM;
}
/* now add the key */
if ((err = kr_add(pk, key_type, sys, name, email, description, &key)) != CRYPT_OK) {
return err;
}
#ifdef CLEAN_STACK
zeromem(&key, sizeof(key));
#endif
return CRYPT_OK;
}
int kr_encrypt_key(pk_key *pk, unsigned long ID,
const unsigned char *in, unsigned long inlen,
unsigned char *out, unsigned long *outlen,
prng_state *prng, int wprng, int hash)
{
unsigned char buf[8192];
unsigned long len;
pk_key *kr;
int err;
_ARGCHK(pk != NULL);
_ARGCHK(in != NULL);
_ARGCHK(out != NULL);
_ARGCHK(outlen != NULL);
/* find the key */
kr = kr_find(pk, ID);
if (kr == NULL) {
return CRYPT_PK_NOT_FOUND;
}
/* store the header */
memcpy(buf, enc_magic, 4);
/* now store the ID */
STORE32L(kr->ID,buf+4);
/* now encrypt it */
len = sizeof(buf)-12;
switch (kr->system) {
case RSA_KEY:
if ((err = rsa_encrypt_key(in, inlen, buf+12, &len, prng, wprng, &(kr->key.rsa))) != CRYPT_OK) {
return err;
}
break;
case DH_KEY:
if ((err = dh_encrypt_key(in, inlen, buf+12, &len, prng, wprng, hash, &(kr->key.dh))) != CRYPT_OK) {
return err;
}
break;
case ECC_KEY:
if ((err = ecc_encrypt_key(in, inlen, buf+12, &len, prng, wprng, hash, &(kr->key.ecc))) != CRYPT_OK) {
return err;
}
break;
}
STORE32L(len,buf+8);
len += 12;
if (len > *outlen) {
#ifdef CLEAN_STACK
zeromem(buf, sizeof(buf));
#endif
return CRYPT_BUFFER_OVERFLOW;
} else {
memcpy(out, buf, len);
#ifdef CLEAN_STACK
zeromem(buf, sizeof(buf));
#endif
*outlen = len;
return CRYPT_OK;
}
}
int kr_decrypt_key(pk_key *pk, const unsigned char *in,
unsigned char *out, unsigned long *outlen)
{
unsigned char buf[8192];
unsigned long pklen, len, ID;
pk_key *kr;
int err;
_ARGCHK(pk != NULL);
_ARGCHK(in != NULL);
_ARGCHK(out != NULL);
_ARGCHK(outlen != NULL);
/* check magic header */
if (memcmp(in, enc_magic, 4)) {
return CRYPT_INVALID_PACKET;
}
/* now try to find key */
LOAD32L(ID,in+4);
kr = kr_find(pk, ID);
if (kr == NULL) {
return CRYPT_PK_NOT_FOUND;
}
/* is it public? */
if (kr->key_type == PK_PUBLIC) {
return CRYPT_PK_NOT_PRIVATE;
}
/* now try and decrypt it */
LOAD32L(pklen,in+8);
len = sizeof(buf);
switch (kr->system) {
case RSA_KEY:
if ((err = rsa_decrypt_key(in+12, pklen, buf, &len, &(kr->key.rsa))) != CRYPT_OK) {
return err;
}
break;
case DH_KEY:
if ((err = dh_decrypt_key(in+12, pklen, buf, &len, &(kr->key.dh))) != CRYPT_OK) {
return err;
}
break;
case ECC_KEY:
if ((err = ecc_decrypt_key(in+12, pklen, buf, &len, &(kr->key.ecc))) != CRYPT_OK) {
return err;
}
break;
}
if (len > *outlen) {
#ifdef CLEAN_STACK
zeromem(buf, sizeof(buf));
#endif
return CRYPT_BUFFER_OVERFLOW;
} else {
memcpy(out, buf, len);
#ifdef CLEAN_STACK
zeromem(buf, sizeof(buf));
#endif
*outlen = len;
return CRYPT_OK;
}
}
int kr_sign_hash(pk_key *pk, unsigned long ID,
const unsigned char *in, unsigned long inlen,
unsigned char *out, unsigned long *outlen,
prng_state *prng, int wprng)
{
unsigned char buf[8192];
unsigned long len;
pk_key *kr;
int err;
_ARGCHK(pk != NULL);
_ARGCHK(in != NULL);
_ARGCHK(out != NULL);
_ARGCHK(outlen != NULL);
/* find the key */
kr = kr_find(pk, ID);
if (kr == NULL) {
return CRYPT_PK_NOT_FOUND;
}
/* is it public? */
if (kr->key_type == PK_PUBLIC) {
return CRYPT_PK_NOT_PRIVATE;
}
/* store the header */
memcpy(buf, sign_magic, 4);
/* now store the ID */
STORE32L(kr->ID,buf+4);
/* now sign it */
len = sizeof(buf)-16;
switch (kr->system) {
case RSA_KEY:
if ((err = rsa_sign_hash(in, inlen, buf+16, &len, &(kr->key.rsa))) != CRYPT_OK) {
return err;
}
break;
case DH_KEY:
if ((err = dh_sign_hash(in, inlen, buf+16, &len, prng, wprng, &(kr->key.dh))) != CRYPT_OK) {
return err;
}
break;
case ECC_KEY:
if ((err = ecc_sign_hash(in, inlen, buf+16, &len, prng, wprng, &(kr->key.ecc))) != CRYPT_OK) {
return err;
}
break;
}
STORE32L(inlen,buf+8);
STORE32L(len,buf+12);
len += 16;
if (len > *outlen) {
#ifdef CLEAN_STACK
zeromem(buf, sizeof(buf));
#endif
return CRYPT_BUFFER_OVERFLOW;
} else {
memcpy(out, buf, len);
#ifdef CLEAN_STACK
zeromem(buf, sizeof(buf));
#endif
*outlen = len;
return CRYPT_OK;
}
}
int kr_verify_hash(pk_key *pk, const unsigned char *in, const unsigned char *hash,
unsigned long hashlen, int *stat)
{
unsigned long inlen, pklen, ID;
pk_key *kr;
int err;
_ARGCHK(pk != NULL);
_ARGCHK(in != NULL);
_ARGCHK(hash != NULL);
_ARGCHK(stat != NULL);
/* default to not match */
*stat = 0;
/* check magic header */
if (memcmp(in, sign_magic, 4)) {
return CRYPT_INVALID_PACKET;
}
/* now try to find key */
LOAD32L(ID,in+4);
kr = kr_find(pk, ID);
if (kr == NULL) {
return CRYPT_PK_NOT_FOUND;
}
/* now try and verify it */
LOAD32L(inlen,in+8); /* this is the length of the original inlen */
LOAD32L(pklen,in+12); /* size of the PK packet */
if (inlen != hashlen) { /* size doesn't match means the signature is invalid */
return CRYPT_OK;
}
switch (kr->system) {
case RSA_KEY:
if ((err = rsa_verify_hash(in+16, pklen, hash, stat, &(kr->key.rsa))) != CRYPT_OK) {
return err;
}
break;
case DH_KEY:
if ((err = dh_verify_hash(in+16, pklen, hash, inlen, stat, &(kr->key.dh))) != CRYPT_OK) {
return err;
}
break;
case ECC_KEY:
if ((err = ecc_verify_hash(in+16, pklen, hash, inlen, stat, &(kr->key.ecc))) != CRYPT_OK) {
return err;
}
break;
}
return CRYPT_OK;
}
int kr_fingerprint(pk_key *pk, unsigned long ID, int hash,
unsigned char *out, unsigned long *outlen)
{
unsigned char buf[8192];
unsigned long len;
int err;
_ARGCHK(pk != NULL);
_ARGCHK(out != NULL);
_ARGCHK(outlen != NULL);
/* valid hash? */
if ((err = hash_is_valid(hash)) != CRYPT_OK) {
return err;
}
len = (unsigned long)sizeof(buf);
if ((err = kr_export(pk, ID, PK_PUBLIC, buf, &len)) != CRYPT_OK) {
return err;
}
/* now hash it */
if ((err = hash_memory(hash, buf, len, out, outlen)) != CRYPT_OK) {
return err;
}
#ifdef CLEAN_STACK
zeromem(buf, sizeof(buf));
#endif
return CRYPT_OK;
}
#endif

View File

@@ -23,7 +23,8 @@ extern "C" {
#define MAXBLOCKSIZE 64
/* descriptor table size */
#define TAB_SIZE 32
/* Dropbear change - this should be smaller, saves some size */
#define TAB_SIZE 4
/* error codes [will be expanded in future releases] */
enum {

View File

@@ -5,6 +5,9 @@
#ifndef MYCRYPT_CUSTOM_H_
#define MYCRYPT_CUSTOM_H_
/* this will sort out which stuff based on the user-config in options.h */
#include "../options.h"
/* macros for various libc functions you can change for embedded targets */
#define XMALLOC malloc
#define XREALLOC realloc
@@ -17,11 +20,13 @@
#define XCLOCK clock
#define XCLOCKS_PER_SEC CLOCKS_PER_SEC
/* Use small code where possible */
// #define SMALL_CODE
#ifdef DROPBEAR_SMALL_CODE
#define SMALL_CODE
#endif
/* Enable self-test test vector checking */
#define LTC_TEST
/* Not for dropbear */
//#define LTC_TEST
/* clean the stack of functions which put private information on stack */
// #define CLEAN_STACK
@@ -29,131 +34,46 @@
/* disable all file related functions */
// #define NO_FILE
/* various ciphers */
#define CLEAN_STACK
#ifdef DROPBEAR_BLOWFISH_CBC
#define BLOWFISH
#define RC2
#define RC5
#define RC6
#define SAFERP
#endif
#ifdef DROPBEAR_AES128_CBC
#define RIJNDAEL
#define XTEA
/* _TABLES tells it to use tables during setup, _SMALL means to use the smaller scheduled key format
* (saves 4KB of ram), _ALL_TABLES enables all tables during setup */
#endif
#ifdef DROPBEAR_TWOFISH128_CBC
#define TWOFISH
#define TWOFISH_TABLES
// #define TWOFISH_ALL_TABLES
// #define TWOFISH_SMALL
/* DES includes EDE triple-DES */
/* enabling just TWOFISH_SMALL will make the binary ~1kB smaller, turning on
* TWOFISH_TABLES will make it a few kB bigger, but perhaps reduces runtime
* memory usage? */
#define TWOFISH_SMALL
/*#define TWOFISH_TABLES*/
#endif
#ifdef DROPBEAR_3DES_CBC
#define DES
#define CAST5
#define NOEKEON
#define SKIPJACK
/* SAFER code isn't public domain. It appears to be free to use
* but has been disabled by default to avoid any such problems
*/
//#define SAFER
/* block cipher modes of operation */
#define CFB
#define OFB
#define ECB
#endif
#define CBC
#define CTR
/* hash functions */
#define CHC_HASH
#define WHIRLPOOL
#if defined(DROPBEAR_DSS) && defined(DSS_PROTOK)
#define SHA512
#define SHA384
#define SHA256
#define SHA224
#define TIGER
#endif
#define SHA1
#ifdef DROPBEAR_MD5_HMAC
#define MD5
#define MD4
#define MD2
#define RIPEMD128
#define RIPEMD160
#endif
/* MAC functions */
#define HMAC
#define OMAC
#define PMAC
/* Encrypt + Authenticate Modes */
#define EAX_MODE
#define OCB_MODE
/* 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 PRNG */
#define FORTUNA
/* reseed every N calls to the read function */
#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
/* Public Key Neatoness */
#define MRSA
/* enable RSA side channel timing prevention */
#define RSA_TIMING
/* Digital Signature Algorithm */
#define MDSA
/* Max diff between group and modulus size in bytes */
#define MDSA_DELTA 512
/* Max DSA group size in bytes (default allows 4k-bit groups) */
#define MDSA_MAX_GROUP 512
/* Diffie-Hellman */
#define MDH
/* Supported Key Sizes */
#define DH768
#define DH1024
#define DH1280
#define DH1536
#define DH1792
#define DH2048
#define DH2560
#define DH3072
#define DH4096
/* ECC */
#define MECC
/* Supported Key Sizes */
#define ECC160
#define ECC192
#define ECC224
#define ECC256
#define ECC384
#define ECC521
/* Include the MPI functionality? (required by the PK algorithms) */
#define MPI
/* PKCS #1 (RSA) and #5 (Password Handling) stuff */
#define PKCS_1
#define PKCS_5
#endif

32
mycrypt_gf.h Normal file
View File

@@ -0,0 +1,32 @@
/* ---- GF(2^w) polynomial basis ---- */
#ifdef GF
#define LSIZE 32 /* handle upto 1024-bit GF numbers */
typedef unsigned long gf_int[LSIZE];
typedef unsigned long *gf_intp;
extern void gf_copy(gf_intp a, gf_intp b);
extern void gf_zero(gf_intp a);
extern int gf_iszero(gf_intp a);
extern int gf_isone(gf_intp a);
extern int gf_deg(gf_intp a);
extern void gf_shl(gf_intp a, gf_intp b);
extern void gf_shr(gf_intp a, gf_intp b);
extern void gf_add(gf_intp a, gf_intp b, gf_intp c);
extern void gf_mul(gf_intp a, gf_intp b, gf_intp c);
extern void gf_div(gf_intp a, gf_intp b, gf_intp q, gf_intp r);
extern void gf_mod(gf_intp a, gf_intp m, gf_intp b);
extern void gf_mulmod(gf_intp a, gf_intp b, gf_intp m, gf_intp c);
extern void gf_invmod(gf_intp A, gf_intp M, gf_intp B);
extern void gf_sqrt(gf_intp a, gf_intp M, gf_intp b);
extern void gf_gcd(gf_intp A, gf_intp B, gf_intp c);
extern int gf_is_prime(gf_intp a);
extern int gf_size(gf_intp a);
extern void gf_toraw(gf_intp a, unsigned char *dst);
extern void gf_readraw(gf_intp a, unsigned char *str, int len);
#endif

View File

@@ -14,4 +14,7 @@
const char *error_to_string(int err);
int mpi_to_ltc_error(int err);
extern const char *crypt_build_settings;
#if 0
/* Takes up space we don\'t need for Dropbear */
extern const char *crypt_build_settings;
#endif

273
rsa.c Normal file
View File

@@ -0,0 +1,273 @@
/* 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
*/
/* RSA Code by Tom St Denis */
#include "mycrypt.h"
#ifdef MRSA
int rsa_signpad(const unsigned char *in, unsigned long inlen,
unsigned char *out, unsigned long *outlen)
{
unsigned long x, y;
_ARGCHK(in != NULL);
_ARGCHK(out != NULL);
_ARGCHK(outlen != NULL);
if (*outlen < (3 * inlen)) {
return CRYPT_BUFFER_OVERFLOW;
}
/* check inlen */
if (inlen > MAX_RSA_SIZE/8) {
return CRYPT_PK_INVALID_SIZE;
}
for (y = x = 0; x < inlen; x++)
out[y++] = (unsigned char)0xFF;
for (x = 0; x < inlen; x++)
out[y++] = in[x];
for (x = 0; x < inlen; x++)
out[y++] = (unsigned char)0xFF;
*outlen = 3 * inlen;
return CRYPT_OK;
}
int rsa_pad(const unsigned char *in, unsigned long inlen,
unsigned char *out, unsigned long *outlen,
int wprng, prng_state *prng)
{
unsigned char buf[3*(MAX_RSA_SIZE/8)];
unsigned long x;
int err;
_ARGCHK(in != NULL);
_ARGCHK(out != NULL);
_ARGCHK(outlen != NULL);
/* is output big enough? */
if (*outlen < (3 * inlen)) {
return CRYPT_BUFFER_OVERFLOW;
}
/* get random padding required */
if ((err = prng_is_valid(wprng)) != CRYPT_OK) {
return err;
}
/* check inlen */
if (inlen > (MAX_RSA_SIZE/8)) {
return CRYPT_PK_INVALID_SIZE;
}
if (prng_descriptor[wprng].read(buf, inlen*2-2, prng) != (inlen*2 - 2)) {
return CRYPT_ERROR_READPRNG;
}
/* pad it like a sandwhich
*
* Looks like 0xFF R1 M R2 0xFF
*
* Where R1/R2 are random and exactly equal to the length of M minus one byte.
*/
for (x = 0; x < inlen-1; x++) {
out[x+1] = buf[x];
}
for (x = 0; x < inlen; x++) {
out[x+inlen] = in[x];
}
for (x = 0; x < inlen-1; x++) {
out[x+inlen+inlen] = buf[x+inlen-1];
}
/* last and first bytes are 0xFF */
out[0] = out[inlen+inlen+inlen-1] = (unsigned char)0xFF;
/* clear up and return */
#ifdef CLEAN_STACK
zeromem(buf, sizeof(buf));
#endif
*outlen = inlen*3;
return CRYPT_OK;
}
int rsa_signdepad(const unsigned char *in, unsigned long inlen,
unsigned char *out, unsigned long *outlen)
{
unsigned long x;
_ARGCHK(in != NULL);
_ARGCHK(out != NULL);
_ARGCHK(outlen != NULL);
if (*outlen < inlen/3) {
return CRYPT_BUFFER_OVERFLOW;
}
/* check padding bytes */
for (x = 0; x < inlen/3; x++) {
if (in[x] != (unsigned char)0xFF || in[x+(inlen/3)+(inlen/3)] != (unsigned char)0xFF) {
return CRYPT_INVALID_PACKET;
}
}
for (x = 0; x < inlen/3; x++) {
out[x] = in[x+(inlen/3)];
}
*outlen = inlen/3;
return CRYPT_OK;
}
int rsa_depad(const unsigned char *in, unsigned long inlen,
unsigned char *out, unsigned long *outlen)
{
unsigned long x;
_ARGCHK(in != NULL);
_ARGCHK(out != NULL);
_ARGCHK(outlen != NULL);
if (*outlen < inlen/3) {
return CRYPT_BUFFER_OVERFLOW;
}
for (x = 0; x < inlen/3; x++) {
out[x] = in[x+(inlen/3)];
}
*outlen = inlen/3;
return CRYPT_OK;
}
int rsa_export(unsigned char *out, unsigned long *outlen, int type, rsa_key *key)
{
unsigned long y, z;
int err;
_ARGCHK(out != NULL);
_ARGCHK(outlen != NULL);
_ARGCHK(key != NULL);
/* can we store the static header? */
if (*outlen < (PACKET_SIZE + 1)) {
return CRYPT_BUFFER_OVERFLOW;
}
/* type valid? */
if (!(key->type == PK_PRIVATE || key->type == PK_PRIVATE_OPTIMIZED) &&
(type == PK_PRIVATE || type == PK_PRIVATE_OPTIMIZED)) {
return CRYPT_PK_INVALID_TYPE;
}
/* start at offset y=PACKET_SIZE */
y = PACKET_SIZE;
/* output key type */
out[y++] = type;
/* output modulus */
OUTPUT_BIGNUM(&key->N, out, y, z);
/* output public key */
OUTPUT_BIGNUM(&key->e, out, y, z);
if (type == PK_PRIVATE || type == PK_PRIVATE_OPTIMIZED) {
OUTPUT_BIGNUM(&key->d, out, y, z);
}
if (type == PK_PRIVATE_OPTIMIZED) {
OUTPUT_BIGNUM(&key->dQ, out, y, z);
OUTPUT_BIGNUM(&key->dP, out, y, z);
OUTPUT_BIGNUM(&key->pQ, out, y, z);
OUTPUT_BIGNUM(&key->qP, out, y, z);
OUTPUT_BIGNUM(&key->p, out, y, z);
OUTPUT_BIGNUM(&key->q, out, y, z);
}
/* store packet header */
packet_store_header(out, PACKET_SECT_RSA, PACKET_SUB_KEY);
/* copy to the user buffer */
*outlen = y;
/* clear stack and return */
return CRYPT_OK;
}
int rsa_import(const unsigned char *in, unsigned long inlen, rsa_key *key)
{
unsigned long x, y;
int err;
_ARGCHK(in != NULL);
_ARGCHK(key != NULL);
/* check length */
if (inlen < (1+PACKET_SIZE)) {
return CRYPT_INVALID_PACKET;
}
/* test packet header */
if ((err = packet_valid_header((unsigned char *)in, PACKET_SECT_RSA, PACKET_SUB_KEY)) != CRYPT_OK) {
return err;
}
/* init key */
if ((err = mp_init_multi(&key->e, &key->d, &key->N, &key->dQ, &key->dP, &key->qP,
&key->pQ, &key->p, &key->q, NULL)) != MP_OKAY) {
return mpi_to_ltc_error(err);
}
/* get key type */
y = PACKET_SIZE;
key->type = (int)in[y++];
/* load the modulus */
INPUT_BIGNUM(&key->N, in, x, y, inlen);
/* load public exponent */
INPUT_BIGNUM(&key->e, in, x, y, inlen);
/* get private exponent */
if (key->type == PK_PRIVATE || key->type == PK_PRIVATE_OPTIMIZED) {
INPUT_BIGNUM(&key->d, in, x, y, inlen);
}
/* get CRT private data if required */
if (key->type == PK_PRIVATE_OPTIMIZED) {
INPUT_BIGNUM(&key->dQ, in, x, y, inlen);
INPUT_BIGNUM(&key->dP, in, x, y, inlen);
INPUT_BIGNUM(&key->pQ, in, x, y, inlen);
INPUT_BIGNUM(&key->qP, in, x, y, inlen);
INPUT_BIGNUM(&key->p, in, x, y, inlen);
INPUT_BIGNUM(&key->q, in, x, y, inlen);
}
/* free up ram not required */
if (key->type != PK_PRIVATE_OPTIMIZED) {
mp_clear_multi(&key->dQ, &key->dP, &key->pQ, &key->qP, &key->p, &key->q, NULL);
}
if (key->type != PK_PRIVATE && key->type != PK_PRIVATE_OPTIMIZED) {
mp_clear(&key->d);
}
return CRYPT_OK;
error:
mp_clear_multi(&key->d, &key->e, &key->N, &key->dQ, &key->dP,
&key->pQ, &key->qP, &key->p, &key->q, NULL);
return err;
}
#include "rsa_sys.c"
#endif /* RSA */

274
rsa_sys.c Normal file
View File

@@ -0,0 +1,274 @@
/* 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
*/
/* these are smaller routines written by Clay Culver. They do the same function as the rsa_encrypt/decrypt
* except that they are used to RSA encrypt/decrypt a single value and not a packet.
*/
int rsa_encrypt_key(const unsigned char *inkey, unsigned long inlen,
unsigned char *outkey, unsigned long *outlen,
prng_state *prng, int wprng, rsa_key *key)
{
unsigned char rsa_in[RSA_STACK], rsa_out[RSA_STACK];
unsigned long x, y, rsa_size;
int err;
_ARGCHK(inkey != NULL);
_ARGCHK(outkey != NULL);
_ARGCHK(outlen != NULL);
_ARGCHK(key != NULL);
/* only allow keys from 64 to 256 bits */
if (inlen < 8 || inlen > 32) {
return CRYPT_INVALID_ARG;
}
/* are the parameters valid? */
if ((err = prng_is_valid(wprng)) != CRYPT_OK) {
return err;
}
/* rsa_pad the symmetric key */
y = (unsigned long)sizeof(rsa_in);
if ((err = rsa_pad(inkey, inlen, rsa_in, &y, wprng, prng)) != CRYPT_OK) {
return CRYPT_ERROR;
}
/* rsa encrypt it */
rsa_size = (unsigned long)sizeof(rsa_out);
if ((err = rsa_exptmod(rsa_in, y, rsa_out, &rsa_size, PK_PUBLIC, key)) != CRYPT_OK) {
return CRYPT_ERROR;
}
/* check size */
if (*outlen < (PACKET_SIZE+4+rsa_size)) {
return CRYPT_BUFFER_OVERFLOW;
}
/* store header */
packet_store_header(outkey, PACKET_SECT_RSA, PACKET_SUB_ENC_KEY);
/* now lets make the header */
y = PACKET_SIZE;
/* store the size of the RSA value */
STORE32L(rsa_size, (outkey+y));
y += 4;
/* store the rsa value */
for (x = 0; x < rsa_size; x++, y++) {
outkey[y] = rsa_out[x];
}
*outlen = y;
#ifdef CLEAN_STACK
/* clean up */
zeromem(rsa_in, sizeof(rsa_in));
zeromem(rsa_out, sizeof(rsa_out));
#endif
return CRYPT_OK;
}
int rsa_decrypt_key(const unsigned char *in, unsigned long inlen,
unsigned char *outkey, unsigned long *keylen,
rsa_key *key)
{
unsigned char sym_key[MAXBLOCKSIZE], rsa_out[RSA_STACK];
unsigned long x, y, z, i, rsa_size;
int err;
_ARGCHK(in != NULL);
_ARGCHK(outkey != NULL);
_ARGCHK(keylen != NULL);
_ARGCHK(key != NULL);
/* right key type? */
if (key->type != PK_PRIVATE && key->type != PK_PRIVATE_OPTIMIZED) {
return CRYPT_PK_NOT_PRIVATE;
}
if (inlen < PACKET_SIZE+4) {
return CRYPT_INVALID_PACKET;
} else {
inlen -= PACKET_SIZE+4;
}
/* check the header */
if ((err = packet_valid_header((unsigned char *)in, PACKET_SECT_RSA, PACKET_SUB_ENC_KEY)) != CRYPT_OK) {
return err;
}
/* grab length of the rsa key */
y = PACKET_SIZE;
LOAD32L(rsa_size, (in+y));
if (inlen < rsa_size) {
return CRYPT_INVALID_PACKET;
} else {
inlen -= rsa_size;
}
y += 4;
/* decrypt it */
x = (unsigned long)sizeof(rsa_out);
if ((err = rsa_exptmod(in+y, rsa_size, rsa_out, &x, PK_PRIVATE, key)) != CRYPT_OK) {
return err;
}
y += rsa_size;
/* depad it */
z = (unsigned long)sizeof(sym_key);
if ((err = rsa_depad(rsa_out, x, sym_key, &z)) != CRYPT_OK) {
return err;
}
/* check size */
if (*keylen < z) {
return CRYPT_BUFFER_OVERFLOW;
}
for (i = 0; i < z; i++) {
outkey[i] = sym_key[i];
}
#ifdef CLEAN_STACK
/* clean up */
zeromem(sym_key, sizeof(sym_key));
zeromem(rsa_out, sizeof(rsa_out));
#endif
*keylen = z;
return CRYPT_OK;
}
int rsa_sign_hash(const unsigned char *in, unsigned long inlen,
unsigned char *out, unsigned long *outlen,
rsa_key *key)
{
unsigned long rsa_size, x, y;
unsigned char rsa_in[RSA_STACK], rsa_out[RSA_STACK];
int err;
_ARGCHK(in != NULL);
_ARGCHK(out != NULL);
_ARGCHK(outlen != NULL);
_ARGCHK(key != NULL);
/* reject nonsense sizes */
if (inlen > (512/3) || inlen < 16) {
return CRYPT_INVALID_ARG;
}
/* type of key? */
if (key->type != PK_PRIVATE && key->type != PK_PRIVATE_OPTIMIZED) {
return CRYPT_PK_NOT_PRIVATE;
}
/* pad it */
x = (unsigned long)sizeof(rsa_out);
if ((err = rsa_signpad(in, inlen, rsa_out, &x)) != CRYPT_OK) {
return err;
}
/* sign it */
rsa_size = (unsigned long)sizeof(rsa_in);
if ((err = rsa_exptmod(rsa_out, x, rsa_in, &rsa_size, PK_PRIVATE, key)) != CRYPT_OK) {
return err;
}
/* check size */
if (*outlen < (PACKET_SIZE+4+rsa_size)) {
return CRYPT_BUFFER_OVERFLOW;
}
/* now lets output the message */
y = PACKET_SIZE;
/* output the len */
STORE32L(rsa_size, (out+y));
y += 4;
/* store the signature */
for (x = 0; x < rsa_size; x++, y++) {
out[y] = rsa_in[x];
}
/* store header */
packet_store_header(out, PACKET_SECT_RSA, PACKET_SUB_SIGNED);
#ifdef CLEAN_STACK
/* clean up */
zeromem(rsa_in, sizeof(rsa_in));
zeromem(rsa_out, sizeof(rsa_out));
#endif
*outlen = y;
return CRYPT_OK;
}
int rsa_verify_hash(const unsigned char *sig, unsigned long siglen,
const unsigned char *md, int *stat, rsa_key *key)
{
unsigned long rsa_size, x, y, z;
unsigned char rsa_in[RSA_STACK], rsa_out[RSA_STACK];
int err;
_ARGCHK(sig != NULL);
_ARGCHK(md != NULL);
_ARGCHK(stat != NULL);
_ARGCHK(key != NULL);
/* always be incorrect by default */
*stat = 0;
if (siglen < PACKET_SIZE+4) {
return CRYPT_INVALID_PACKET;
} else {
siglen -= PACKET_SIZE+4;
}
/* verify header */
if ((err = packet_valid_header((unsigned char *)sig, PACKET_SECT_RSA, PACKET_SUB_SIGNED)) != CRYPT_OK) {
return err;
}
/* get the len */
y = PACKET_SIZE;
LOAD32L(rsa_size, (sig+y));
if (siglen < rsa_size) {
return CRYPT_INVALID_PACKET;
} else {
siglen -= rsa_size;
}
y += 4;
/* exptmod it */
x = (unsigned long)sizeof(rsa_out);
if ((err = rsa_exptmod(sig+y, rsa_size, rsa_out, &x, PK_PUBLIC, key)) != CRYPT_OK) {
return err;
}
y += rsa_size;
/* depad it */
z = (unsigned long)sizeof(rsa_in);
if ((err = rsa_signdepad(rsa_out, x, rsa_in, &z)) != CRYPT_OK) {
return err;
}
/* check? */
if (memcmp(rsa_in, md, (size_t)z) == 0) {
*stat = 1;
}
#ifdef CLEAN_STACK
zeromem(rsa_in, sizeof(rsa_in));
zeromem(rsa_out, sizeof(rsa_out));
#endif
return CRYPT_OK;
}

698
serpent.c Normal file
View File

@@ -0,0 +1,698 @@
#include "mycrypt.h"
#ifdef SERPENT
const struct _cipher_descriptor serpent_desc =
{
"serpent",
5,
16, 32, 16, 32,
&serpent_setup,
&serpent_ecb_encrypt,
&serpent_ecb_decrypt,
&serpent_test,
&serpent_keysize
};
/* These defines are derived from Brian Gladman's work. Contact him at gladman@seven77.demon.co.uk
*
* Available on the web at http://fp.gladman.plus.com/cryptography_technology/aes/index.htm
*/
#define sb0(a,b,c,d,e,f,g,h) \
t1 = a ^ d; \
t2 = a & d; \
t3 = c ^ t1; \
t6 = b & t1; \
t4 = b ^ t3; \
t10 = ~t3; \
h = t2 ^ t4; \
t7 = a ^ t6; \
t14 = ~t7; \
t8 = c | t7; \
t11 = t3 ^ t7; \
g = t4 ^ t8; \
t12 = h & t11; \
f = t10 ^ t12; \
e = t12 ^ t14
/* 15 terms */
#define ib0(a,b,c,d,e,f,g,h) \
t1 = ~a; \
t2 = a ^ b; \
t3 = t1 | t2; \
t4 = d ^ t3; \
t7 = d & t2; \
t5 = c ^ t4; \
t8 = t1 ^ t7; \
g = t2 ^ t5; \
t11 = a & t4; \
t9 = g & t8; \
t14 = t5 ^ t8; \
f = t4 ^ t9; \
t12 = t5 | f; \
h = t11 ^ t12; \
e = h ^ t14
/* 14 terms! */
#define sb1(a,b,c,d,e,f,g,h) \
t1 = ~a; \
t2 = b ^ t1; \
t3 = a | t2; \
t4 = d | t2; \
t5 = c ^ t3; \
g = d ^ t5; \
t7 = b ^ t4; \
t8 = t2 ^ g; \
t9 = t5 & t7; \
h = t8 ^ t9; \
t11 = t5 ^ t7; \
f = h ^ t11; \
t13 = t8 & t11; \
e = t5 ^ t13
/* 17 terms */
#define ib1(a,b,c,d,e,f,g,h) \
t1 = a ^ d; \
t2 = a & b; \
t3 = b ^ c; \
t4 = a ^ t3; \
t5 = b | d; \
t7 = c | t1; \
h = t4 ^ t5; \
t8 = b ^ t7; \
t11 = ~t2; \
t9 = t4 & t8; \
f = t1 ^ t9; \
t13 = t9 ^ t11; \
t12 = h & f; \
g = t12 ^ t13; \
t15 = a & d; \
t16 = c ^ t13; \
e = t15 ^ t16
/* 16 terms */
#define sb2(a,b,c,d,e,f,g,h) \
t1 = ~a; \
t2 = b ^ d; \
t3 = c & t1; \
t13 = d | t1; \
e = t2 ^ t3; \
t5 = c ^ t1; \
t6 = c ^ e; \
t7 = b & t6; \
t10 = e | t5; \
h = t5 ^ t7; \
t9 = d | t7; \
t11 = t9 & t10; \
t14 = t2 ^ h; \
g = a ^ t11; \
t15 = g ^ t13; \
f = t14 ^ t15
/* 16 terms */
#define ib2(a,b,c,d,e,f,g,h) \
t1 = b ^ d; \
t2 = ~t1; \
t3 = a ^ c; \
t4 = c ^ t1; \
t7 = a | t2; \
t5 = b & t4; \
t8 = d ^ t7; \
t11 = ~t4; \
e = t3 ^ t5; \
t9 = t3 | t8; \
t14 = d & t11; \
h = t1 ^ t9; \
t12 = e | h; \
f = t11 ^ t12; \
t15 = t3 ^ t12; \
g = t14 ^ t15
/* 17 terms */
#define sb3(a,b,c,d,e,f,g,h) \
t1 = a ^ c; \
t2 = d ^ t1; \
t3 = a & t2; \
t4 = d ^ t3; \
t5 = b & t4; \
g = t2 ^ t5; \
t7 = a | g; \
t8 = b | d; \
t11 = a | d; \
t9 = t4 & t7; \
f = t8 ^ t9; \
t12 = b ^ t11; \
t13 = g ^ t9; \
t15 = t3 ^ t8; \
h = t12 ^ t13; \
t16 = c & t15; \
e = t12 ^ t16
/* 16 term solution that performs less well than 17 term one
in my environment (PPro/PII)
#define sb3(a,b,c,d,e,f,g,h) \
t1 = a ^ b; \
t2 = a & c; \
t3 = a | d; \
t4 = c ^ d; \
t5 = t1 & t3; \
t6 = t2 | t5; \
g = t4 ^ t6; \
t8 = b ^ t3; \
t9 = t6 ^ t8; \
t10 = t4 & t9; \
e = t1 ^ t10; \
t12 = g & e; \
f = t9 ^ t12; \
t14 = b | d; \
t15 = t4 ^ t12; \
h = t14 ^ t15
*/
/* 17 terms */
#define ib3(a,b,c,d,e,f,g,h) \
t1 = b ^ c; \
t2 = b | c; \
t3 = a ^ c; \
t7 = a ^ d; \
t4 = t2 ^ t3; \
t5 = d | t4; \
t9 = t2 ^ t7; \
e = t1 ^ t5; \
t8 = t1 | t5; \
t11 = a & t4; \
g = t8 ^ t9; \
t12 = e | t9; \
f = t11 ^ t12; \
t14 = a & g; \
t15 = t2 ^ t14; \
t16 = e & t15; \
h = t4 ^ t16
/* 15 terms */
#define sb4(a,b,c,d,e,f,g,h) \
t1 = a ^ d; \
t2 = d & t1; \
t3 = c ^ t2; \
t4 = b | t3; \
h = t1 ^ t4; \
t6 = ~b; \
t7 = t1 | t6; \
e = t3 ^ t7; \
t9 = a & e; \
t10 = t1 ^ t6; \
t11 = t4 & t10; \
g = t9 ^ t11; \
t13 = a ^ t3; \
t14 = t10 & g; \
f = t13 ^ t14
/* 17 terms */
#define ib4(a,b,c,d,e,f,g,h) \
t1 = c ^ d; \
t2 = c | d; \
t3 = b ^ t2; \
t4 = a & t3; \
f = t1 ^ t4; \
t6 = a ^ d; \
t7 = b | d; \
t8 = t6 & t7; \
h = t3 ^ t8; \
t10 = ~a; \
t11 = c ^ h; \
t12 = t10 | t11;\
e = t3 ^ t12; \
t14 = c | t4; \
t15 = t7 ^ t14; \
t16 = h | t10; \
g = t15 ^ t16
/* 16 terms */
#define sb5(a,b,c,d,e,f,g,h) \
t1 = ~a; \
t2 = a ^ b; \
t3 = a ^ d; \
t4 = c ^ t1; \
t5 = t2 | t3; \
e = t4 ^ t5; \
t7 = d & e; \
t8 = t2 ^ e; \
t10 = t1 | e; \
f = t7 ^ t8; \
t11 = t2 | t7; \
t12 = t3 ^ t10; \
t14 = b ^ t7; \
g = t11 ^ t12; \
t15 = f & t12; \
h = t14 ^ t15
/* 16 terms */
#define ib5(a,b,c,d,e,f,g,h) \
t1 = ~c; \
t2 = b & t1; \
t3 = d ^ t2; \
t4 = a & t3; \
t5 = b ^ t1; \
h = t4 ^ t5; \
t7 = b | h; \
t8 = a & t7; \
f = t3 ^ t8; \
t10 = a | d; \
t11 = t1 ^ t7; \
e = t10 ^ t11; \
t13 = a ^ c; \
t14 = b & t10; \
t15 = t4 | t13; \
g = t14 ^ t15
/* 15 terms */
#define sb6(a,b,c,d,e,f,g,h) \
t1 = ~a; \
t2 = a ^ d; \
t3 = b ^ t2; \
t4 = t1 | t2; \
t5 = c ^ t4; \
f = b ^ t5; \
t13 = ~t5; \
t7 = t2 | f; \
t8 = d ^ t7; \
t9 = t5 & t8; \
g = t3 ^ t9; \
t11 = t5 ^ t8; \
e = g ^ t11; \
t14 = t3 & t11; \
h = t13 ^ t14
/* 15 terms */
#define ib6(a,b,c,d,e,f,g,h) \
t1 = ~a; \
t2 = a ^ b; \
t3 = c ^ t2; \
t4 = c | t1; \
t5 = d ^ t4; \
t13 = d & t1; \
f = t3 ^ t5; \
t7 = t3 & t5; \
t8 = t2 ^ t7; \
t9 = b | t8; \
h = t5 ^ t9; \
t11 = b | h; \
e = t8 ^ t11; \
t14 = t3 ^ t11; \
g = t13 ^ t14
/* 17 terms */
#define sb7(a,b,c,d,e,f,g,h) \
t1 = ~c; \
t2 = b ^ c; \
t3 = b | t1; \
t4 = d ^ t3; \
t5 = a & t4; \
t7 = a ^ d; \
h = t2 ^ t5; \
t8 = b ^ t5; \
t9 = t2 | t8; \
t11 = d & t3; \
f = t7 ^ t9; \
t12 = t5 ^ f; \
t15 = t1 | t4; \
t13 = h & t12; \
g = t11 ^ t13; \
t16 = t12 ^ g; \
e = t15 ^ t16
/* 17 terms */
#define ib7(a,b,c,d,e,f,g,h) \
t1 = a & b; \
t2 = a | b; \
t3 = c | t1; \
t4 = d & t2; \
h = t3 ^ t4; \
t6 = ~d; \
t7 = b ^ t4; \
t8 = h ^ t6; \
t11 = c ^ t7; \
t9 = t7 | t8; \
f = a ^ t9; \
t12 = d | f; \
e = t11 ^ t12; \
t14 = a & h; \
t15 = t3 ^ f; \
t16 = e ^ t14; \
g = t15 ^ t16
#define k_xor(r,a,b,c,d) \
a ^= skey->serpent.K[4 * (r) + 0]; \
b ^= skey->serpent.K[4 * (r) + 1]; \
c ^= skey->serpent.K[4 * (r) + 2]; \
d ^= skey->serpent.K[4 * (r) + 3]
#define k_set(r,a,b,c,d) \
a = lkey[4 * (r) + 8]; \
b = lkey[4 * (r) + 9]; \
c = lkey[4 * (r) + 10]; \
d = lkey[4 * (r) + 11]
#define k_get(r,a,b,c,d) \
skey->serpent.K[4 * (r) + 0] = a; \
skey->serpent.K[4 * (r) + 1] = b; \
skey->serpent.K[4 * (r) + 2] = c; \
skey->serpent.K[4 * (r) + 3] = d
/* the linear transformation and its inverse */
#define rot(a,b,c,d) \
a = ROL(a, 13); \
c = ROL(c, 3); \
d ^= c ^ (a << 3); \
b ^= a ^ c; \
d = ROL(d, 7); \
b = ROL(b, 1); \
a ^= b ^ d; \
c ^= d ^ (b << 7); \
a = ROL(a, 5); \
c = ROL(c, 22)
#define irot(a,b,c,d) \
c = ROR(c, 22); \
a = ROR(a, 5); \
c ^= d ^ (b << 7); \
a ^= b ^ d; \
d = ROR(d, 7); \
b = ROR(b, 1); \
d ^= c ^ (a << 3); \
b ^= a ^ c; \
c = ROR(c, 3); \
a = ROR(a, 13)
#ifdef CLEAN_STACK
static int _serpent_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey)
#else
int serpent_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey)
#endif
{
unsigned long lkey[140], t, a, b, c, d, e, f, g, h, x;
unsigned long t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14,t15,t16;
unsigned char buf[32];
_ARGCHK(key != NULL);
_ARGCHK(skey != NULL);
/* check rounds */
if (num_rounds != 0 && num_rounds != 32) {
return CRYPT_INVALID_ROUNDS;
}
/* check keylen */
if (keylen < 16 || keylen > 32) {
return CRYPT_INVALID_KEYSIZE;
}
/* copy key and expand to 32bytes as required */
for (x = 0; x < (unsigned long)keylen; x++) {
buf[x] = key[x];
}
if (x < 32) {
buf[x++] = (unsigned char)0x01;
while (x < 32) {
buf[x++] = (unsigned char)0;
}
}
/* copy key into 32-bit words */
for (x = 0; x < 8; x++) {
LOAD32L(lkey[x], &buf[x*4]);
}
/* expand using the LFSR to 140 words */
for (x = 0; x < 132; x++) {
t = lkey[x] ^ lkey[x+3] ^ lkey[x+5] ^ lkey[x+7] ^ x ^ 0x9E3779B9UL;
lkey[x + 8] = ROL(t, 11);
}
/* perform the substituions */
for (x = 0; x < 32; ) {
k_set( x,a,b,c,d);sb3(a,b,c,d,e,f,g,h);k_get( x,e,f,g,h); ++x;
k_set( x,a,b,c,d);sb2(a,b,c,d,e,f,g,h);k_get( x,e,f,g,h); ++x;
k_set( x,a,b,c,d);sb1(a,b,c,d,e,f,g,h);k_get( x,e,f,g,h); ++x;
k_set( x,a,b,c,d);sb0(a,b,c,d,e,f,g,h);k_get( x,e,f,g,h); ++x;
k_set( x,a,b,c,d);sb7(a,b,c,d,e,f,g,h);k_get( x,e,f,g,h); ++x;
k_set( x,a,b,c,d);sb6(a,b,c,d,e,f,g,h);k_get( x,e,f,g,h); ++x;
k_set( x,a,b,c,d);sb5(a,b,c,d,e,f,g,h);k_get( x,e,f,g,h); ++x;
k_set( x,a,b,c,d);sb4(a,b,c,d,e,f,g,h);k_get( x,e,f,g,h); ++x;
}
k_set(32,a,b,c,d);sb3(a,b,c,d,e,f,g,h);k_get(32,e,f,g,h);
return CRYPT_OK;
}
#ifdef CLEAN_STACK
int serpent_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey)
{
int x;
x = _serpent_setup(key, keylen, num_rounds, skey);
burn_stack(sizeof(unsigned long)*166 + sizeof(unsigned char)*32);
return x;
}
#endif
#ifdef CLEAN_STACK
static void _serpent_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey)
#else
void serpent_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey)
#endif
{
unsigned long a,b,c,d,e,f,g,h;
unsigned long t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14,t15,t16;
_ARGCHK(pt != NULL);
_ARGCHK(ct != NULL);
_ARGCHK(skey != NULL);
LOAD32L(a, &pt[0]);LOAD32L(b, &pt[4]);LOAD32L(c, &pt[8]);LOAD32L(d, &pt[12]);
k_xor( 0,a,b,c,d); sb0(a,b,c,d,e,f,g,h); rot(e,f,g,h);
k_xor( 1,e,f,g,h); sb1(e,f,g,h,a,b,c,d); rot(a,b,c,d);
k_xor( 2,a,b,c,d); sb2(a,b,c,d,e,f,g,h); rot(e,f,g,h);
k_xor( 3,e,f,g,h); sb3(e,f,g,h,a,b,c,d); rot(a,b,c,d);
k_xor( 4,a,b,c,d); sb4(a,b,c,d,e,f,g,h); rot(e,f,g,h);
k_xor( 5,e,f,g,h); sb5(e,f,g,h,a,b,c,d); rot(a,b,c,d);
k_xor( 6,a,b,c,d); sb6(a,b,c,d,e,f,g,h); rot(e,f,g,h);
k_xor( 7,e,f,g,h); sb7(e,f,g,h,a,b,c,d); rot(a,b,c,d);
k_xor( 8,a,b,c,d); sb0(a,b,c,d,e,f,g,h); rot(e,f,g,h);
k_xor( 9,e,f,g,h); sb1(e,f,g,h,a,b,c,d); rot(a,b,c,d);
k_xor(10,a,b,c,d); sb2(a,b,c,d,e,f,g,h); rot(e,f,g,h);
k_xor(11,e,f,g,h); sb3(e,f,g,h,a,b,c,d); rot(a,b,c,d);
k_xor(12,a,b,c,d); sb4(a,b,c,d,e,f,g,h); rot(e,f,g,h);
k_xor(13,e,f,g,h); sb5(e,f,g,h,a,b,c,d); rot(a,b,c,d);
k_xor(14,a,b,c,d); sb6(a,b,c,d,e,f,g,h); rot(e,f,g,h);
k_xor(15,e,f,g,h); sb7(e,f,g,h,a,b,c,d); rot(a,b,c,d);
k_xor(16,a,b,c,d); sb0(a,b,c,d,e,f,g,h); rot(e,f,g,h);
k_xor(17,e,f,g,h); sb1(e,f,g,h,a,b,c,d); rot(a,b,c,d);
k_xor(18,a,b,c,d); sb2(a,b,c,d,e,f,g,h); rot(e,f,g,h);
k_xor(19,e,f,g,h); sb3(e,f,g,h,a,b,c,d); rot(a,b,c,d);
k_xor(20,a,b,c,d); sb4(a,b,c,d,e,f,g,h); rot(e,f,g,h);
k_xor(21,e,f,g,h); sb5(e,f,g,h,a,b,c,d); rot(a,b,c,d);
k_xor(22,a,b,c,d); sb6(a,b,c,d,e,f,g,h); rot(e,f,g,h);
k_xor(23,e,f,g,h); sb7(e,f,g,h,a,b,c,d); rot(a,b,c,d);
k_xor(24,a,b,c,d); sb0(a,b,c,d,e,f,g,h); rot(e,f,g,h);
k_xor(25,e,f,g,h); sb1(e,f,g,h,a,b,c,d); rot(a,b,c,d);
k_xor(26,a,b,c,d); sb2(a,b,c,d,e,f,g,h); rot(e,f,g,h);
k_xor(27,e,f,g,h); sb3(e,f,g,h,a,b,c,d); rot(a,b,c,d);
k_xor(28,a,b,c,d); sb4(a,b,c,d,e,f,g,h); rot(e,f,g,h);
k_xor(29,e,f,g,h); sb5(e,f,g,h,a,b,c,d); rot(a,b,c,d);
k_xor(30,a,b,c,d); sb6(a,b,c,d,e,f,g,h); rot(e,f,g,h);
k_xor(31,e,f,g,h); sb7(e,f,g,h,a,b,c,d); k_xor(32,a,b,c,d);
STORE32L(a, &ct[0]);STORE32L(b, &ct[4]);STORE32L(c, &ct[8]);STORE32L(d, &ct[12]);
}
#ifdef CLEAN_STACK
void serpent_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey)
{
_serpent_ecb_encrypt(pt, ct, skey);
burn_stack(sizeof(unsigned long)*24);
}
#endif
#ifdef CLEAN_STACK
static void _serpent_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey)
#else
void serpent_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey)
#endif
{
unsigned long a,b,c,d,e,f,g,h;
unsigned long t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14,t15,t16;
_ARGCHK(pt != NULL);
_ARGCHK(ct != NULL);
_ARGCHK(skey != NULL);
LOAD32L(a, &ct[0]);LOAD32L(b, &ct[4]);LOAD32L(c, &ct[8]);LOAD32L(d, &ct[12]);
k_xor(32,a,b,c,d); ib7(a,b,c,d,e,f,g,h); k_xor(31,e,f,g,h);
irot(e,f,g,h); ib6(e,f,g,h,a,b,c,d); k_xor(30,a,b,c,d);
irot(a,b,c,d); ib5(a,b,c,d,e,f,g,h); k_xor(29,e,f,g,h);
irot(e,f,g,h); ib4(e,f,g,h,a,b,c,d); k_xor(28,a,b,c,d);
irot(a,b,c,d); ib3(a,b,c,d,e,f,g,h); k_xor(27,e,f,g,h);
irot(e,f,g,h); ib2(e,f,g,h,a,b,c,d); k_xor(26,a,b,c,d);
irot(a,b,c,d); ib1(a,b,c,d,e,f,g,h); k_xor(25,e,f,g,h);
irot(e,f,g,h); ib0(e,f,g,h,a,b,c,d); k_xor(24,a,b,c,d);
irot(a,b,c,d); ib7(a,b,c,d,e,f,g,h); k_xor(23,e,f,g,h);
irot(e,f,g,h); ib6(e,f,g,h,a,b,c,d); k_xor(22,a,b,c,d);
irot(a,b,c,d); ib5(a,b,c,d,e,f,g,h); k_xor(21,e,f,g,h);
irot(e,f,g,h); ib4(e,f,g,h,a,b,c,d); k_xor(20,a,b,c,d);
irot(a,b,c,d); ib3(a,b,c,d,e,f,g,h); k_xor(19,e,f,g,h);
irot(e,f,g,h); ib2(e,f,g,h,a,b,c,d); k_xor(18,a,b,c,d);
irot(a,b,c,d); ib1(a,b,c,d,e,f,g,h); k_xor(17,e,f,g,h);
irot(e,f,g,h); ib0(e,f,g,h,a,b,c,d); k_xor(16,a,b,c,d);
irot(a,b,c,d); ib7(a,b,c,d,e,f,g,h); k_xor(15,e,f,g,h);
irot(e,f,g,h); ib6(e,f,g,h,a,b,c,d); k_xor(14,a,b,c,d);
irot(a,b,c,d); ib5(a,b,c,d,e,f,g,h); k_xor(13,e,f,g,h);
irot(e,f,g,h); ib4(e,f,g,h,a,b,c,d); k_xor(12,a,b,c,d);
irot(a,b,c,d); ib3(a,b,c,d,e,f,g,h); k_xor(11,e,f,g,h);
irot(e,f,g,h); ib2(e,f,g,h,a,b,c,d); k_xor(10,a,b,c,d);
irot(a,b,c,d); ib1(a,b,c,d,e,f,g,h); k_xor( 9,e,f,g,h);
irot(e,f,g,h); ib0(e,f,g,h,a,b,c,d); k_xor( 8,a,b,c,d);
irot(a,b,c,d); ib7(a,b,c,d,e,f,g,h); k_xor( 7,e,f,g,h);
irot(e,f,g,h); ib6(e,f,g,h,a,b,c,d); k_xor( 6,a,b,c,d);
irot(a,b,c,d); ib5(a,b,c,d,e,f,g,h); k_xor( 5,e,f,g,h);
irot(e,f,g,h); ib4(e,f,g,h,a,b,c,d); k_xor( 4,a,b,c,d);
irot(a,b,c,d); ib3(a,b,c,d,e,f,g,h); k_xor( 3,e,f,g,h);
irot(e,f,g,h); ib2(e,f,g,h,a,b,c,d); k_xor( 2,a,b,c,d);
irot(a,b,c,d); ib1(a,b,c,d,e,f,g,h); k_xor( 1,e,f,g,h);
irot(e,f,g,h); ib0(e,f,g,h,a,b,c,d); k_xor( 0,a,b,c,d);
STORE32L(a, &pt[0]);STORE32L(b, &pt[4]);STORE32L(c, &pt[8]);STORE32L(d, &pt[12]);
}
#ifdef CLEAN_STACK
void serpent_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey)
{
_serpent_ecb_decrypt(ct, pt, skey);
burn_stack(sizeof(unsigned long)*24);
}
#endif
int serpent_test(void)
{
static const struct {
int keylen;
unsigned char key[32], pt[16], ct[16];
} tests[] = {
{
16,
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
{ 0xdd, 0xd2, 0x6b, 0x98, 0xa5, 0xff, 0xd8, 0x2c,
0x05, 0x34, 0x5a, 0x9d, 0xad, 0xbf, 0xaf, 0x49 }
},
{
16,
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80 },
{ 0x4a, 0xe9, 0xa2, 0x0b, 0x2b, 0x14, 0xa1, 0x02,
0x90, 0xcb, 0xb8, 0x20, 0xb7, 0xff, 0xb5, 0x10 }
},
{
24,
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08 },
{ 0xe1, 0x1b, 0x01, 0x52, 0x4e, 0xa1, 0xf4, 0x65,
0xa2, 0xa2, 0x00, 0x43, 0xeb, 0x9f, 0x7e, 0x8a }
},
{
32,
{ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
{ 0xe0, 0x88, 0x5d, 0x44, 0x60, 0x37, 0x34, 0x69,
0xd1, 0xfa, 0x6c, 0x36, 0xa6, 0xe1, 0xc5, 0x2f }
},
{
32,
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
{ 0x17, 0xc6, 0x25, 0x8e, 0x60, 0x09, 0xe2, 0x82,
0x66, 0x18, 0x69, 0xd5, 0x25, 0xf7, 0xd2, 0x04 }
},
{
32,
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
{ 0x9f, 0xe1, 0x43, 0x25, 0x0d, 0x00, 0xe2, 0x56,
0x96, 0xb0, 0x1e, 0x0a, 0x2e, 0xd0, 0x5d, 0xb3 }
}
};
unsigned char buf[2][16];
int x, err;
symmetric_key key;
for (x = 0; x < (int)(sizeof(tests) / sizeof(tests[0])); x++) {
/* setup key */
if ((err = serpent_setup(tests[x].key, tests[x].keylen, 0, &key))!= CRYPT_OK) {
return err;
}
/* encrypt and decrypt */
serpent_ecb_encrypt(tests[x].pt, buf[0], &key);
serpent_ecb_decrypt(buf[0], buf[1], &key);
/* compare */
if (memcmp(buf[0], tests[x].ct, 16) != 0 || memcmp(buf[1], tests[x].pt, 16) != 0) {
return CRYPT_FAIL_TESTVECTOR;
}
}
return CRYPT_OK;
}
int serpent_keysize(int *desired_keysize)
{
_ARGCHK(desired_keysize != NULL);
if (*desired_keysize < 16)
return CRYPT_INVALID_KEYSIZE;
if (*desired_keysize > 32)
*desired_keysize = 32;
return CRYPT_OK;
}
#endif

86
strings.c Normal file
View File

@@ -0,0 +1,86 @@
/* 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
*/
/* Future releases will make use of this */
#include "mycrypt.h"
static const char *err_2_str[] =
{
"CRYPT_OK",
"CRYPT_ERROR",
"Non-fatal 'no-operation' requested.",
"Invalid keysize for block cipher.",
"Invalid number of rounds for block cipher.",
"Algorithm failed test vectors.",
"Buffer overflow.",
"Invalid input packet.",
"Invalid number of bits for a PRNG.",
"Error reading the PRNG.",
"Invalid cipher specified.",
"Invalid hash specified.",
"Invalid PRNG specified.",
"Out of memory.",
"Invalid PK key or key type specified for function.",
"A private PK key is required.",
"Invalid argument provided.",
"File Not Found",
"Invalid PK type.",
"Invalid PK system.",
"Duplicate PK key found on keyring.",
"Key not found in keyring.",
"Invalid sized parameter.",
"Invalid size for prime.",
};
#ifdef MPI
static const struct {
int mpi_code, ltc_code;
} mpi_to_ltc_codes[] = {
{ MP_OKAY , CRYPT_OK},
{ MP_MEM , CRYPT_MEM},
{ MP_VAL , CRYPT_INVALID_ARG},
};
#endif
const char *error_to_string(int err)
{
if (err < 0 || err >= (int)(sizeof(err_2_str)/sizeof(err_2_str[0]))) {
return "Invalid error code.";
} else {
return err_2_str[err];
}
}
#ifdef MPI
/* convert a MPI error to a LTC error (Possibly the most powerful function ever! Oh wait... no) */
int mpi_to_ltc_error(int err)
{
int x;
for (x = 0; x < (int)(sizeof(mpi_to_ltc_codes)/sizeof(mpi_to_ltc_codes[0])); x++) {
if (err == mpi_to_ltc_codes[x].mpi_code) {
return mpi_to_ltc_codes[x].ltc_code;
}
}
return CRYPT_ERROR;
}
#endif

558
tommath.h Normal file
View File

@@ -0,0 +1,558 @@
/* LibTomMath, multiple-precision integer library -- Tom St Denis
*
* LibTomMath is a library that provides multiple-precision
* integer arithmetic as well as number theoretic functionality.
*
* The library was designed directly after the MPI library by
* Michael Fromberger but has been written from scratch with
* additional optimizations in place.
*
* The library is free for all purposes without any express
* guarantee it works.
*
* Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org
*/
#ifndef BN_H_
#define BN_H_
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <limits.h>
#define NO_LTM_TOOM 1
#undef MIN
#define MIN(x,y) ((x)<(y)?(x):(y))
#undef MAX
#define MAX(x,y) ((x)>(y)?(x):(y))
#ifdef __cplusplus
extern "C" {
/* C++ compilers don't like assigning void * to mp_digit * */
#define OPT_CAST(x) (x *)
#else
/* C on the other hand doesn't care */
#define OPT_CAST(x)
#endif
/* some default configurations.
*
* A "mp_digit" must be able to hold DIGIT_BIT + 1 bits
* A "mp_word" must be able to hold 2*DIGIT_BIT + 1 bits
*
* At the very least a mp_digit must be able to hold 7 bits
* [any size beyond that is ok provided it doesn't overflow the data type]
*/
#ifdef MP_8BIT
typedef unsigned char mp_digit;
typedef unsigned short mp_word;
#elif defined(MP_16BIT)
typedef unsigned short mp_digit;
typedef unsigned long mp_word;
#elif defined(MP_64BIT)
/* for GCC only on supported platforms */
#ifndef CRYPT
typedef unsigned long long ulong64;
typedef signed long long long64;
#endif
typedef ulong64 mp_digit;
typedef unsigned long mp_word __attribute__ ((mode(TI)));
#define DIGIT_BIT 60
#else
/* this is the default case, 28-bit digits */
/* this is to make porting into LibTomCrypt easier :-) */
#ifndef CRYPT
#if defined(_MSC_VER) || defined(__BORLANDC__)
typedef unsigned __int64 ulong64;
typedef signed __int64 long64;
#else
typedef unsigned long long ulong64;
typedef signed long long long64;
#endif
#endif
typedef unsigned long mp_digit;
typedef ulong64 mp_word;
#ifdef MP_31BIT
/* this is an extension that uses 31-bit digits */
#define DIGIT_BIT 31
#else
/* default case is 28-bit digits, defines MP_28BIT as a handy macro to test */
#define DIGIT_BIT 28
#define MP_28BIT
#endif
#endif
/* define heap macros */
#ifndef CRYPT
/* default to libc stuff */
#ifndef XMALLOC
#define XMALLOC malloc
#define XFREE free
#define XREALLOC realloc
#define XCALLOC calloc
#else
/* prototypes for our heap functions */
extern void *XMALLOC(size_t n);
extern void *REALLOC(void *p, size_t n);
extern void *XCALLOC(size_t n, size_t s);
extern void XFREE(void *p);
#endif
#endif
/* otherwise the bits per digit is calculated automatically from the size of a mp_digit */
#ifndef DIGIT_BIT
#define DIGIT_BIT ((int)((CHAR_BIT * sizeof(mp_digit) - 1))) /* bits per digit */
#endif
#define MP_DIGIT_BIT DIGIT_BIT
#define MP_MASK ((((mp_digit)1)<<((mp_digit)DIGIT_BIT))-((mp_digit)1))
#define MP_DIGIT_MAX MP_MASK
/* equalities */
#define MP_LT -1 /* less than */
#define MP_EQ 0 /* equal to */
#define MP_GT 1 /* greater than */
#define MP_ZPOS 0 /* positive integer */
#define MP_NEG 1 /* negative */
#define MP_OKAY 0 /* ok result */
#define MP_MEM -2 /* out of mem */
#define MP_VAL -3 /* invalid input */
#define MP_RANGE MP_VAL
#define MP_YES 1 /* yes response */
#define MP_NO 0 /* no response */
/* Primality generation flags */
#define LTM_PRIME_BBS 0x0001 /* BBS style prime */
#define LTM_PRIME_SAFE 0x0002 /* Safe prime (p-1)/2 == prime */
#define LTM_PRIME_2MSB_OFF 0x0004 /* force 2nd MSB to 0 */
#define LTM_PRIME_2MSB_ON 0x0008 /* force 2nd MSB to 1 */
typedef int mp_err;
/* you'll have to tune these... */
extern int KARATSUBA_MUL_CUTOFF,
KARATSUBA_SQR_CUTOFF,
TOOM_MUL_CUTOFF,
TOOM_SQR_CUTOFF;
/* define this to use lower memory usage routines (exptmods mostly) */
/* #define MP_LOW_MEM */
/* default precision */
#ifndef MP_PREC
#ifdef MP_LOW_MEM
#define MP_PREC 64 /* default digits of precision */
#else
#define MP_PREC 8 /* default digits of precision */
#endif
#endif
/* size of comba arrays, should be at least 2 * 2**(BITS_PER_WORD - BITS_PER_DIGIT*2) */
#define MP_WARRAY (1 << (sizeof(mp_word) * CHAR_BIT - 2 * DIGIT_BIT + 1))
/* the infamous mp_int structure */
typedef struct {
int used, alloc, sign;
mp_digit *dp;
} mp_int;
/* callback for mp_prime_random, should fill dst with random bytes and return how many read [upto len] */
typedef int ltm_prime_callback(unsigned char *dst, int len, void *dat);
#define USED(m) ((m)->used)
#define DIGIT(m,k) ((m)->dp[(k)])
#define SIGN(m) ((m)->sign)
/* error code to char* string */
char *mp_error_to_string(int code);
/* ---> init and deinit bignum functions <--- */
/* init a bignum */
int mp_init(mp_int *a);
/* free a bignum */
void mp_clear(mp_int *a);
/* init a null terminated series of arguments */
int mp_init_multi(mp_int *mp, ...);
/* clear a null terminated series of arguments */
void mp_clear_multi(mp_int *mp, ...);
/* exchange two ints */
void mp_exch(mp_int *a, mp_int *b);
/* shrink ram required for a bignum */
int mp_shrink(mp_int *a);
/* grow an int to a given size */
int mp_grow(mp_int *a, int size);
/* init to a given number of digits */
int mp_init_size(mp_int *a, int size);
/* ---> Basic Manipulations <--- */
#define mp_iszero(a) (((a)->used == 0) ? MP_YES : MP_NO)
#define mp_iseven(a) (((a)->used > 0 && (((a)->dp[0] & 1) == 0)) ? MP_YES : MP_NO)
#define mp_isodd(a) (((a)->used > 0 && (((a)->dp[0] & 1) == 1)) ? MP_YES : MP_NO)
/* set to zero */
void mp_zero(mp_int *a);
/* set to a digit */
void mp_set(mp_int *a, mp_digit b);
/* set a 32-bit const */
int mp_set_int(mp_int *a, unsigned long b);
/* get a 32-bit value */
unsigned long mp_get_int(mp_int * a);
/* initialize and set a digit */
int mp_init_set (mp_int * a, mp_digit b);
/* initialize and set 32-bit value */
int mp_init_set_int (mp_int * a, unsigned long b);
/* copy, b = a */
int mp_copy(mp_int *a, mp_int *b);
/* inits and copies, a = b */
int mp_init_copy(mp_int *a, mp_int *b);
/* trim unused digits */
void mp_clamp(mp_int *a);
/* ---> digit manipulation <--- */
/* right shift by "b" digits */
void mp_rshd(mp_int *a, int b);
/* left shift by "b" digits */
int mp_lshd(mp_int *a, int b);
/* c = a / 2**b */
int mp_div_2d(mp_int *a, int b, mp_int *c, mp_int *d);
/* b = a/2 */
int mp_div_2(mp_int *a, mp_int *b);
/* c = a * 2**b */
int mp_mul_2d(mp_int *a, int b, mp_int *c);
/* b = a*2 */
int mp_mul_2(mp_int *a, mp_int *b);
/* c = a mod 2**d */
int mp_mod_2d(mp_int *a, int b, mp_int *c);
/* computes a = 2**b */
int mp_2expt(mp_int *a, int b);
/* Counts the number of lsbs which are zero before the first zero bit */
int mp_cnt_lsb(mp_int *a);
/* I Love Earth! */
/* makes a pseudo-random int of a given size */
int mp_rand(mp_int *a, int digits);
/* ---> binary operations <--- */
/* c = a XOR b */
int mp_xor(mp_int *a, mp_int *b, mp_int *c);
/* c = a OR b */
int mp_or(mp_int *a, mp_int *b, mp_int *c);
/* c = a AND b */
int mp_and(mp_int *a, mp_int *b, mp_int *c);
/* ---> Basic arithmetic <--- */
/* b = -a */
int mp_neg(mp_int *a, mp_int *b);
/* b = |a| */
int mp_abs(mp_int *a, mp_int *b);
/* compare a to b */
int mp_cmp(mp_int *a, mp_int *b);
/* compare |a| to |b| */
int mp_cmp_mag(mp_int *a, mp_int *b);
/* c = a + b */
int mp_add(mp_int *a, mp_int *b, mp_int *c);
/* c = a - b */
int mp_sub(mp_int *a, mp_int *b, mp_int *c);
/* c = a * b */
int mp_mul(mp_int *a, mp_int *b, mp_int *c);
/* b = a*a */
int mp_sqr(mp_int *a, mp_int *b);
/* a/b => cb + d == a */
int mp_div(mp_int *a, mp_int *b, mp_int *c, mp_int *d);
/* c = a mod b, 0 <= c < b */
int mp_mod(mp_int *a, mp_int *b, mp_int *c);
/* ---> single digit functions <--- */
/* compare against a single digit */
int mp_cmp_d(mp_int *a, mp_digit b);
/* c = a + b */
int mp_add_d(mp_int *a, mp_digit b, mp_int *c);
/* c = a - b */
int mp_sub_d(mp_int *a, mp_digit b, mp_int *c);
/* c = a * b */
int mp_mul_d(mp_int *a, mp_digit b, mp_int *c);
/* a/b => cb + d == a */
int mp_div_d(mp_int *a, mp_digit b, mp_int *c, mp_digit *d);
/* a/3 => 3c + d == a */
int mp_div_3(mp_int *a, mp_int *c, mp_digit *d);
/* c = a**b */
int mp_expt_d(mp_int *a, mp_digit b, mp_int *c);
/* c = a mod b, 0 <= c < b */
int mp_mod_d(mp_int *a, mp_digit b, mp_digit *c);
/* ---> number theory <--- */
/* d = a + b (mod c) */
int mp_addmod(mp_int *a, mp_int *b, mp_int *c, mp_int *d);
/* d = a - b (mod c) */
int mp_submod(mp_int *a, mp_int *b, mp_int *c, mp_int *d);
/* d = a * b (mod c) */
int mp_mulmod(mp_int *a, mp_int *b, mp_int *c, mp_int *d);
/* c = a * a (mod b) */
int mp_sqrmod(mp_int *a, mp_int *b, mp_int *c);
/* c = 1/a (mod b) */
int mp_invmod(mp_int *a, mp_int *b, mp_int *c);
/* c = (a, b) */
int mp_gcd(mp_int *a, mp_int *b, mp_int *c);
/* produces value such that U1*a + U2*b = U3 */
int mp_exteuclid(mp_int *a, mp_int *b, mp_int *U1, mp_int *U2, mp_int *U3);
/* c = [a, b] or (a*b)/(a, b) */
int mp_lcm(mp_int *a, mp_int *b, mp_int *c);
/* finds one of the b'th root of a, such that |c|**b <= |a|
*
* returns error if a < 0 and b is even
*/
int mp_n_root(mp_int *a, mp_digit b, mp_int *c);
/* special sqrt algo */
int mp_sqrt(mp_int *arg, mp_int *ret);
/* is number a square? */
int mp_is_square(mp_int *arg, int *ret);
/* computes the jacobi c = (a | n) (or Legendre if b is prime) */
int mp_jacobi(mp_int *a, mp_int *n, int *c);
/* used to setup the Barrett reduction for a given modulus b */
int mp_reduce_setup(mp_int *a, mp_int *b);
/* Barrett Reduction, computes a (mod b) with a precomputed value c
*
* Assumes that 0 < a <= b*b, note if 0 > a > -(b*b) then you can merely
* compute the reduction as -1 * mp_reduce(mp_abs(a)) [pseudo code].
*/
int mp_reduce(mp_int *a, mp_int *b, mp_int *c);
/* setups the montgomery reduction */
int mp_montgomery_setup(mp_int *a, mp_digit *mp);
/* computes a = B**n mod b without division or multiplication useful for
* normalizing numbers in a Montgomery system.
*/
int mp_montgomery_calc_normalization(mp_int *a, mp_int *b);
/* computes x/R == x (mod N) via Montgomery Reduction */
int mp_montgomery_reduce(mp_int *a, mp_int *m, mp_digit mp);
/* returns 1 if a is a valid DR modulus */
int mp_dr_is_modulus(mp_int *a);
/* sets the value of "d" required for mp_dr_reduce */
void mp_dr_setup(mp_int *a, mp_digit *d);
/* reduces a modulo b using the Diminished Radix method */
int mp_dr_reduce(mp_int *a, mp_int *b, mp_digit mp);
/* returns true if a can be reduced with mp_reduce_2k */
int mp_reduce_is_2k(mp_int *a);
/* determines k value for 2k reduction */
int mp_reduce_2k_setup(mp_int *a, mp_digit *d);
/* reduces a modulo b where b is of the form 2**p - k [0 <= a] */
int mp_reduce_2k(mp_int *a, mp_int *n, mp_digit d);
/* d = a**b (mod c) */
int mp_exptmod(mp_int *a, mp_int *b, mp_int *c, mp_int *d);
/* ---> Primes <--- */
/* number of primes */
#ifdef MP_8BIT
#define PRIME_SIZE 31
#else
#define PRIME_SIZE 256
#endif
/* table of first PRIME_SIZE primes */
extern const mp_digit __prime_tab[];
/* result=1 if a is divisible by one of the first PRIME_SIZE primes */
int mp_prime_is_divisible(mp_int *a, int *result);
/* performs one Fermat test of "a" using base "b".
* Sets result to 0 if composite or 1 if probable prime
*/
int mp_prime_fermat(mp_int *a, mp_int *b, int *result);
/* performs one Miller-Rabin test of "a" using base "b".
* Sets result to 0 if composite or 1 if probable prime
*/
int mp_prime_miller_rabin(mp_int *a, mp_int *b, int *result);
/* This gives [for a given bit size] the number of trials required
* such that Miller-Rabin gives a prob of failure lower than 2^-96
*/
int mp_prime_rabin_miller_trials(int size);
/* performs t rounds of Miller-Rabin on "a" using the first
* t prime bases. Also performs an initial sieve of trial
* division. Determines if "a" is prime with probability
* of error no more than (1/4)**t.
*
* Sets result to 1 if probably prime, 0 otherwise
*/
int mp_prime_is_prime(mp_int *a, int t, int *result);
/* finds the next prime after the number "a" using "t" trials
* of Miller-Rabin.
*
* bbs_style = 1 means the prime must be congruent to 3 mod 4
*/
int mp_prime_next_prime(mp_int *a, int t, int bbs_style);
/* makes a truly random prime of a given size (bytes),
* call with bbs = 1 if you want it to be congruent to 3 mod 4
*
* You have to supply a callback which fills in a buffer with random bytes. "dat" is a parameter you can
* have passed to the callback (e.g. a state or something). This function doesn't use "dat" itself
* so it can be NULL
*
* The prime generated will be larger than 2^(8*size).
*/
#define mp_prime_random(a, t, size, bbs, cb, dat) mp_prime_random_ex(a, t, ((size) * 8) + 1, (bbs==1)?LTM_PRIME_BBS:0, cb, dat)
/* makes a truly random prime of a given size (bits),
*
* Flags are as follows:
*
* LTM_PRIME_BBS - make prime congruent to 3 mod 4
* LTM_PRIME_SAFE - make sure (p-1)/2 is prime as well (implies LTM_PRIME_BBS)
* LTM_PRIME_2MSB_OFF - make the 2nd highest bit zero
* LTM_PRIME_2MSB_ON - make the 2nd highest bit one
*
* You have to supply a callback which fills in a buffer with random bytes. "dat" is a parameter you can
* have passed to the callback (e.g. a state or something). This function doesn't use "dat" itself
* so it can be NULL
*
*/
int mp_prime_random_ex(mp_int *a, int t, int size, int flags, ltm_prime_callback cb, void *dat);
/* ---> radix conversion <--- */
int mp_count_bits(mp_int *a);
int mp_unsigned_bin_size(mp_int *a);
int mp_read_unsigned_bin(mp_int *a, unsigned char *b, int c);
int mp_to_unsigned_bin(mp_int *a, unsigned char *b);
int mp_signed_bin_size(mp_int *a);
int mp_read_signed_bin(mp_int *a, unsigned char *b, int c);
int mp_to_signed_bin(mp_int *a, unsigned char *b);
int mp_read_radix(mp_int *a, char *str, int radix);
int mp_toradix(mp_int *a, char *str, int radix);
int mp_toradix_n(mp_int * a, char *str, int radix, int maxlen);
int mp_radix_size(mp_int *a, int radix, int *size);
int mp_fread(mp_int *a, int radix, FILE *stream);
int mp_fwrite(mp_int *a, int radix, FILE *stream);
#define mp_read_raw(mp, str, len) mp_read_signed_bin((mp), (str), (len))
#define mp_raw_size(mp) mp_signed_bin_size(mp)
#define mp_toraw(mp, str) mp_to_signed_bin((mp), (str))
#define mp_read_mag(mp, str, len) mp_read_unsigned_bin((mp), (str), (len))
#define mp_mag_size(mp) mp_unsigned_bin_size(mp)
#define mp_tomag(mp, str) mp_to_unsigned_bin((mp), (str))
#define mp_tobinary(M, S) mp_toradix((M), (S), 2)
#define mp_tooctal(M, S) mp_toradix((M), (S), 8)
#define mp_todecimal(M, S) mp_toradix((M), (S), 10)
#define mp_tohex(M, S) mp_toradix((M), (S), 16)
/* lowlevel functions, do not call! */
int s_mp_add(mp_int *a, mp_int *b, mp_int *c);
int s_mp_sub(mp_int *a, mp_int *b, mp_int *c);
#define s_mp_mul(a, b, c) s_mp_mul_digs(a, b, c, (a)->used + (b)->used + 1)
int fast_s_mp_mul_digs(mp_int *a, mp_int *b, mp_int *c, int digs);
int s_mp_mul_digs(mp_int *a, mp_int *b, mp_int *c, int digs);
int fast_s_mp_mul_high_digs(mp_int *a, mp_int *b, mp_int *c, int digs);
int s_mp_mul_high_digs(mp_int *a, mp_int *b, mp_int *c, int digs);
int fast_s_mp_sqr(mp_int *a, mp_int *b);
int s_mp_sqr(mp_int *a, mp_int *b);
int mp_karatsuba_mul(mp_int *a, mp_int *b, mp_int *c);
int mp_toom_mul(mp_int *a, mp_int *b, mp_int *c);
int mp_karatsuba_sqr(mp_int *a, mp_int *b);
int mp_toom_sqr(mp_int *a, mp_int *b);
int fast_mp_invmod(mp_int *a, mp_int *b, mp_int *c);
int fast_mp_montgomery_reduce(mp_int *a, mp_int *m, mp_digit mp);
int mp_exptmod_fast(mp_int *G, mp_int *X, mp_int *P, mp_int *Y, int mode);
int s_mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y);
void bn_reverse(unsigned char *s, int len);
extern const char *mp_s_rmap;
#ifdef __cplusplus
}
#endif
#endif