2004-01-25 17:40:34 +00:00
|
|
|
/* 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
|
2004-05-12 20:42:16 +00:00
|
|
|
* guarantee it works.
|
2004-01-25 17:40:34 +00:00
|
|
|
*
|
2007-07-20 17:48:02 +00:00
|
|
|
* Tom St Denis, tomstdenis@gmail.com, http://libtom.org
|
2004-01-25 17:40:34 +00:00
|
|
|
*/
|
2004-12-30 23:55:53 +00:00
|
|
|
#include "tomcrypt.h"
|
|
|
|
|
|
|
|
/**
|
|
|
|
@file rc4.c
|
2007-07-20 17:48:02 +00:00
|
|
|
LTC_RC4 PRNG, Tom St Denis
|
2004-12-30 23:55:53 +00:00
|
|
|
*/
|
2003-03-03 00:59:24 +00:00
|
|
|
|
2007-07-20 17:48:02 +00:00
|
|
|
#ifdef LTC_RC4
|
2003-03-03 00:59:24 +00:00
|
|
|
|
2004-12-30 23:55:53 +00:00
|
|
|
const struct ltc_prng_descriptor rc4_desc =
|
2003-03-03 00:59:24 +00:00
|
|
|
{
|
2004-08-06 16:42:41 +00:00
|
|
|
"rc4", 32,
|
2003-03-03 00:59:24 +00:00
|
|
|
&rc4_start,
|
|
|
|
&rc4_add_entropy,
|
|
|
|
&rc4_ready,
|
2004-07-23 15:40:22 +00:00
|
|
|
&rc4_read,
|
|
|
|
&rc4_done,
|
|
|
|
&rc4_export,
|
2004-08-06 16:42:41 +00:00
|
|
|
&rc4_import,
|
|
|
|
&rc4_test
|
2003-03-03 00:59:24 +00:00
|
|
|
};
|
|
|
|
|
2004-12-30 23:55:53 +00:00
|
|
|
/**
|
|
|
|
Start the PRNG
|
|
|
|
@param prng [out] The PRNG state to initialize
|
|
|
|
@return CRYPT_OK if successful
|
|
|
|
*/
|
2003-03-03 00:59:24 +00:00
|
|
|
int rc4_start(prng_state *prng)
|
|
|
|
{
|
2004-12-30 23:55:53 +00:00
|
|
|
LTC_ARGCHK(prng != NULL);
|
2003-03-03 00:59:24 +00:00
|
|
|
|
|
|
|
/* set keysize to zero */
|
|
|
|
prng->rc4.x = 0;
|
|
|
|
|
|
|
|
return CRYPT_OK;
|
|
|
|
}
|
|
|
|
|
2004-12-30 23:55:53 +00:00
|
|
|
/**
|
|
|
|
Add entropy to the PRNG state
|
|
|
|
@param in The data to add
|
|
|
|
@param inlen Length of the data to add
|
|
|
|
@param prng PRNG state to update
|
|
|
|
@return CRYPT_OK if successful
|
|
|
|
*/
|
|
|
|
int rc4_add_entropy(const unsigned char *in, unsigned long inlen, prng_state *prng)
|
2003-03-03 00:59:24 +00:00
|
|
|
{
|
2004-12-30 23:55:53 +00:00
|
|
|
LTC_ARGCHK(in != NULL);
|
|
|
|
LTC_ARGCHK(prng != NULL);
|
2004-08-06 16:42:41 +00:00
|
|
|
|
|
|
|
/* trim as required */
|
2004-12-30 23:55:53 +00:00
|
|
|
if (prng->rc4.x + inlen > 256) {
|
2004-08-06 16:42:41 +00:00
|
|
|
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 */
|
2004-12-30 23:55:53 +00:00
|
|
|
inlen = 256 - prng->rc4.x;
|
2004-08-06 16:42:41 +00:00
|
|
|
}
|
2003-03-03 00:59:24 +00:00
|
|
|
}
|
|
|
|
|
2004-12-30 23:55:53 +00:00
|
|
|
while (inlen--) {
|
|
|
|
prng->rc4.buf[prng->rc4.x++] = *in++;
|
2003-03-03 00:59:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return CRYPT_OK;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2004-12-30 23:55:53 +00:00
|
|
|
/**
|
|
|
|
Make the PRNG ready to read from
|
|
|
|
@param prng The PRNG to make active
|
|
|
|
@return CRYPT_OK if successful
|
|
|
|
*/
|
2003-03-03 00:59:24 +00:00
|
|
|
int rc4_ready(prng_state *prng)
|
|
|
|
{
|
2004-08-06 16:42:41 +00:00
|
|
|
unsigned char key[256], tmp, *s;
|
|
|
|
int keylen, x, y, j;
|
2003-03-03 00:59:24 +00:00
|
|
|
|
2004-12-30 23:55:53 +00:00
|
|
|
LTC_ARGCHK(prng != NULL);
|
2003-03-03 00:59:24 +00:00
|
|
|
|
|
|
|
/* extract the key */
|
2004-08-06 16:42:41 +00:00
|
|
|
s = prng->rc4.buf;
|
|
|
|
XMEMCPY(key, s, 256);
|
2003-03-03 00:59:24 +00:00
|
|
|
keylen = prng->rc4.x;
|
|
|
|
|
2007-07-20 17:48:02 +00:00
|
|
|
/* make LTC_RC4 perm and shuffle */
|
2003-03-03 00:59:24 +00:00
|
|
|
for (x = 0; x < 256; x++) {
|
2004-08-06 16:42:41 +00:00
|
|
|
s[x] = x;
|
2003-03-03 00:59:24 +00:00
|
|
|
}
|
|
|
|
|
2004-08-06 16:42:41 +00:00
|
|
|
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;
|
2003-03-03 00:59:24 +00:00
|
|
|
}
|
2004-08-06 16:42:41 +00:00
|
|
|
prng->rc4.x = 0;
|
|
|
|
prng->rc4.y = 0;
|
2003-03-03 00:59:24 +00:00
|
|
|
|
2004-12-30 23:55:53 +00:00
|
|
|
#ifdef LTC_CLEAN_STACK
|
2003-03-03 00:59:24 +00:00
|
|
|
zeromem(key, sizeof(key));
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return CRYPT_OK;
|
|
|
|
}
|
|
|
|
|
2004-12-30 23:55:53 +00:00
|
|
|
/**
|
|
|
|
Read from the PRNG
|
|
|
|
@param out Destination
|
|
|
|
@param outlen Length of output
|
|
|
|
@param prng The active PRNG to read from
|
|
|
|
@return Number of octets read
|
|
|
|
*/
|
|
|
|
unsigned long rc4_read(unsigned char *out, unsigned long outlen, prng_state *prng)
|
2003-03-03 00:59:24 +00:00
|
|
|
{
|
2004-08-06 16:42:41 +00:00
|
|
|
unsigned char x, y, *s, tmp;
|
2003-03-03 00:59:24 +00:00
|
|
|
unsigned long n;
|
|
|
|
|
2004-12-30 23:55:53 +00:00
|
|
|
LTC_ARGCHK(out != NULL);
|
|
|
|
LTC_ARGCHK(prng != NULL);
|
2003-03-03 00:59:24 +00:00
|
|
|
|
2006-11-17 14:21:24 +00:00
|
|
|
#ifdef LTC_VALGRIND
|
|
|
|
zeromem(out, outlen);
|
|
|
|
#endif
|
|
|
|
|
2004-12-30 23:55:53 +00:00
|
|
|
n = outlen;
|
2003-03-03 00:59:24 +00:00
|
|
|
x = prng->rc4.x;
|
|
|
|
y = prng->rc4.y;
|
|
|
|
s = prng->rc4.buf;
|
2004-12-30 23:55:53 +00:00
|
|
|
while (outlen--) {
|
2003-03-03 00:59:24 +00:00
|
|
|
x = (x + 1) & 255;
|
|
|
|
y = (y + s[x]) & 255;
|
|
|
|
tmp = s[x]; s[x] = s[y]; s[y] = tmp;
|
|
|
|
tmp = (s[x] + s[y]) & 255;
|
2004-12-30 23:55:53 +00:00
|
|
|
*out++ ^= s[tmp];
|
2003-03-03 00:59:24 +00:00
|
|
|
}
|
|
|
|
prng->rc4.x = x;
|
|
|
|
prng->rc4.y = y;
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
2004-12-30 23:55:53 +00:00
|
|
|
/**
|
|
|
|
Terminate the PRNG
|
|
|
|
@param prng The PRNG to terminate
|
|
|
|
@return CRYPT_OK if successful
|
|
|
|
*/
|
2004-08-06 16:42:41 +00:00
|
|
|
int rc4_done(prng_state *prng)
|
2004-07-23 15:40:22 +00:00
|
|
|
{
|
2004-12-30 23:55:53 +00:00
|
|
|
LTC_ARGCHK(prng != NULL);
|
2004-08-06 16:42:41 +00:00
|
|
|
return CRYPT_OK;
|
2004-07-23 15:40:22 +00:00
|
|
|
}
|
|
|
|
|
2004-12-30 23:55:53 +00:00
|
|
|
/**
|
|
|
|
Export the PRNG state
|
|
|
|
@param out [out] Destination
|
|
|
|
@param outlen [in/out] Max size and resulting size of the state
|
|
|
|
@param prng The PRNG to export
|
|
|
|
@return CRYPT_OK if successful
|
|
|
|
*/
|
2004-07-23 15:40:22 +00:00
|
|
|
int rc4_export(unsigned char *out, unsigned long *outlen, prng_state *prng)
|
|
|
|
{
|
2004-12-30 23:55:53 +00:00
|
|
|
LTC_ARGCHK(outlen != NULL);
|
|
|
|
LTC_ARGCHK(out != NULL);
|
|
|
|
LTC_ARGCHK(prng != NULL);
|
2004-08-06 16:42:41 +00:00
|
|
|
|
|
|
|
if (*outlen < 32) {
|
2006-06-18 01:37:50 +00:00
|
|
|
*outlen = 32;
|
2004-08-06 16:42:41 +00:00
|
|
|
return CRYPT_BUFFER_OVERFLOW;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rc4_read(out, 32, prng) != 32) {
|
|
|
|
return CRYPT_ERROR_READPRNG;
|
|
|
|
}
|
|
|
|
*outlen = 32;
|
2004-07-23 15:40:22 +00:00
|
|
|
|
|
|
|
return CRYPT_OK;
|
|
|
|
}
|
|
|
|
|
2004-12-30 23:55:53 +00:00
|
|
|
/**
|
|
|
|
Import a PRNG state
|
|
|
|
@param in The PRNG state
|
|
|
|
@param inlen Size of the state
|
|
|
|
@param prng The PRNG to import
|
|
|
|
@return CRYPT_OK if successful
|
|
|
|
*/
|
2004-07-23 15:40:22 +00:00
|
|
|
int rc4_import(const unsigned char *in, unsigned long inlen, prng_state *prng)
|
|
|
|
{
|
2004-08-06 16:42:41 +00:00
|
|
|
int err;
|
2004-12-30 23:55:53 +00:00
|
|
|
LTC_ARGCHK(in != NULL);
|
|
|
|
LTC_ARGCHK(prng != NULL);
|
2004-08-06 16:42:41 +00:00
|
|
|
|
|
|
|
if (inlen != 32) {
|
|
|
|
return CRYPT_INVALID_ARG;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((err = rc4_start(prng)) != CRYPT_OK) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
return rc4_add_entropy(in, 32, prng);
|
2004-07-23 15:40:22 +00:00
|
|
|
}
|
|
|
|
|
2004-12-30 23:55:53 +00:00
|
|
|
/**
|
|
|
|
PRNG self-test
|
|
|
|
@return CRYPT_OK if successful, CRYPT_NOP if self-testing has been disabled
|
|
|
|
*/
|
2004-08-06 16:42:41 +00:00
|
|
|
int rc4_test(void)
|
|
|
|
{
|
2006-11-17 14:21:24 +00:00
|
|
|
#if !defined(LTC_TEST) || defined(LTC_VALGRIND)
|
2004-08-06 16:42:41 +00:00
|
|
|
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);
|
2006-11-17 14:21:24 +00:00
|
|
|
if (XMEMCMP(dst, tests[x].ct, 8)) {
|
2004-08-06 16:42:41 +00:00
|
|
|
#if 0
|
|
|
|
int y;
|
2007-07-20 17:48:02 +00:00
|
|
|
printf("\n\nLTC_RC4 failed, I got:\n");
|
2004-08-06 16:42:41 +00:00
|
|
|
for (y = 0; y < 8; y++) printf("%02x ", dst[y]);
|
|
|
|
printf("\n");
|
|
|
|
#endif
|
|
|
|
return CRYPT_FAIL_TESTVECTOR;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return CRYPT_OK;
|
|
|
|
#endif
|
|
|
|
}
|
2004-07-23 15:40:22 +00:00
|
|
|
|
2003-03-03 00:59:24 +00:00
|
|
|
#endif
|
|
|
|
|
2005-06-09 00:08:13 +00:00
|
|
|
|
|
|
|
/* $Source$ */
|
|
|
|
/* $Revision$ */
|
|
|
|
/* $Date$ */
|