1 /* LibTomCrypt, modular cryptographic library -- Tom St Denis
3 * LibTomCrypt is a library that provides various cryptographic
4 * algorithms in a highly modular and flexible manner.
6 * The library is free for all purposes without any express
13 RC4 PRNG, Tom St Denis
18 const struct ltc_prng_descriptor rc4_desc =
34 @param prng [out] The PRNG state to initialize
35 @return CRYPT_OK if successful
37 int rc4_start(prng_state *prng)
39 LTC_ARGCHK(prng != NULL);
41 /* set entropy (key) size to zero */
43 /* clear entropy (key) buffer */
44 XMEMSET(&prng->rc4.s.buf, 0, sizeof(prng->rc4.s.buf));
45 LTC_MUTEX_INIT(&prng->lock)
50 Add entropy to the PRNG state
51 @param in The data to add
52 @param inlen Length of the data to add
53 @param prng PRNG state to update
54 @return CRYPT_OK if successful
56 int rc4_add_entropy(const unsigned char *in, unsigned long inlen, prng_state *prng)
58 unsigned char buf[256];
62 LTC_ARGCHK(prng != NULL);
63 LTC_ARGCHK(in != NULL);
64 LTC_ARGCHK(inlen > 0);
66 LTC_MUTEX_LOCK(&prng->lock);
68 /* rc4_ready() was already called, do "rekey" operation */
69 if ((err = rc4_stream_keystream(&prng->rc4.s, buf, sizeof(buf))) != CRYPT_OK) goto LBL_UNLOCK;
70 for(i = 0; i < inlen; i++) buf[i % sizeof(buf)] ^= in[i];
72 if ((err = rc4_stream_setup(&prng->rc4.s, buf, sizeof(buf))) != CRYPT_OK) goto LBL_UNLOCK;
73 /* drop first 3072 bytes - https://en.wikipedia.org/wiki/RC4#Fluhrer.2C_Mantin_and_Shamir_attack */
74 for (i = 0; i < 12; i++) rc4_stream_keystream(&prng->rc4.s, buf, sizeof(buf));
75 zeromem(buf, sizeof(buf));
78 /* rc4_ready() was not called yet, add entropy to the buffer */
79 while (inlen--) prng->rc4.s.buf[prng->rc4.s.x++ % sizeof(prng->rc4.s.buf)] ^= *in++;
83 LTC_MUTEX_UNLOCK(&prng->lock);
88 Make the PRNG ready to read from
89 @param prng The PRNG to make active
90 @return CRYPT_OK if successful
92 int rc4_ready(prng_state *prng)
94 unsigned char buf[256] = { 0 };
98 LTC_ARGCHK(prng != NULL);
100 LTC_MUTEX_LOCK(&prng->lock);
101 if (prng->ready) { err = CRYPT_OK; goto LBL_UNLOCK; }
102 XMEMCPY(buf, prng->rc4.s.buf, sizeof(buf));
104 len = MIN(prng->rc4.s.x, 256); /* TODO: we can perhaps always use all 256 bytes */
105 if ((err = rc4_stream_setup(&prng->rc4.s, buf, len)) != CRYPT_OK) goto LBL_UNLOCK;
106 /* drop first 3072 bytes - https://en.wikipedia.org/wiki/RC4#Fluhrer.2C_Mantin_and_Shamir_attack */
107 for (i = 0; i < 12; i++) rc4_stream_keystream(&prng->rc4.s, buf, sizeof(buf));
110 LTC_MUTEX_UNLOCK(&prng->lock);
116 @param out Destination
117 @param outlen Length of output
118 @param prng The active PRNG to read from
119 @return Number of octets read
121 unsigned long rc4_read(unsigned char *out, unsigned long outlen, prng_state *prng)
123 if (outlen == 0 || prng == NULL || out == NULL) return 0;
124 LTC_MUTEX_LOCK(&prng->lock);
125 if (!prng->ready) { outlen = 0; goto LBL_UNLOCK; }
126 if (rc4_stream_keystream(&prng->rc4.s, out, outlen) != CRYPT_OK) outlen = 0;
128 LTC_MUTEX_UNLOCK(&prng->lock);
134 @param prng The PRNG to terminate
135 @return CRYPT_OK if successful
137 int rc4_done(prng_state *prng)
140 LTC_ARGCHK(prng != NULL);
141 LTC_MUTEX_LOCK(&prng->lock);
143 err = rc4_stream_done(&prng->rc4.s);
144 LTC_MUTEX_UNLOCK(&prng->lock);
145 LTC_MUTEX_DESTROY(&prng->lock);
150 Export the PRNG state
151 @param out [out] Destination
152 @param outlen [in/out] Max size and resulting size of the state
153 @param prng The PRNG to export
154 @return CRYPT_OK if successful
156 int rc4_export(unsigned char *out, unsigned long *outlen, prng_state *prng)
158 unsigned long len = rc4_desc.export_size;
160 LTC_ARGCHK(prng != NULL);
161 LTC_ARGCHK(out != NULL);
162 LTC_ARGCHK(outlen != NULL);
166 return CRYPT_BUFFER_OVERFLOW;
169 if (rc4_read(out, len, prng) != len) {
170 return CRYPT_ERROR_READPRNG;
179 @param in The PRNG state
180 @param inlen Size of the state
181 @param prng The PRNG to import
182 @return CRYPT_OK if successful
184 int rc4_import(const unsigned char *in, unsigned long inlen, prng_state *prng)
188 LTC_ARGCHK(prng != NULL);
189 LTC_ARGCHK(in != NULL);
190 if (inlen < (unsigned long)rc4_desc.export_size) return CRYPT_INVALID_ARG;
192 if ((err = rc4_start(prng)) != CRYPT_OK) return err;
193 if ((err = rc4_add_entropy(in, inlen, prng)) != CRYPT_OK) return err;
199 @return CRYPT_OK if successful, CRYPT_NOP if self-testing has been disabled
207 unsigned char en[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
208 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14,
209 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e,
210 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
211 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32 };
212 unsigned char dmp[500];
213 unsigned long dmplen = sizeof(dmp);
214 unsigned char out[1000];
215 unsigned char t1[] = { 0xE0, 0x4D, 0x9A, 0xF6, 0xA8, 0x9D, 0x77, 0x53, 0xAE, 0x09 };
216 unsigned char t2[] = { 0xEF, 0x80, 0xA2, 0xE6, 0x50, 0x91, 0xF3, 0x17, 0x4A, 0x8A };
217 unsigned char t3[] = { 0x4B, 0xD6, 0x5C, 0x67, 0x99, 0x03, 0x56, 0x12, 0x80, 0x48 };
220 if ((err = rc4_start(&st)) != CRYPT_OK) return err;
221 /* add entropy to uninitialized prng */
222 if ((err = rc4_add_entropy(en, sizeof(en), &st)) != CRYPT_OK) return err;
223 if ((err = rc4_ready(&st)) != CRYPT_OK) return err;
224 if (rc4_read(out, 10, &st) != 10) return CRYPT_ERROR_READPRNG; /* 10 bytes for testing */
225 if (compare_testvector(out, 10, t1, sizeof(t1), "RC4-PRNG", 1)) return CRYPT_FAIL_TESTVECTOR;
226 if (rc4_read(out, 500, &st) != 500) return CRYPT_ERROR_READPRNG; /* skip 500 bytes */
227 /* add entropy to already initialized prng */
228 if ((err = rc4_add_entropy(en, sizeof(en), &st)) != CRYPT_OK) return err;
229 if (rc4_read(out, 500, &st) != 500) return CRYPT_ERROR_READPRNG; /* skip 500 bytes */
230 if ((err = rc4_export(dmp, &dmplen, &st)) != CRYPT_OK) return err;
231 if (rc4_read(out, 500, &st) != 500) return CRYPT_ERROR_READPRNG; /* skip 500 bytes */
232 if (rc4_read(out, 10, &st) != 10) return CRYPT_ERROR_READPRNG; /* 10 bytes for testing */
233 if (compare_testvector(out, 10, t2, sizeof(t2), "RC4-PRNG", 2)) return CRYPT_FAIL_TESTVECTOR;
234 if ((err = rc4_done(&st)) != CRYPT_OK) return err;
235 if ((err = rc4_import(dmp, dmplen, &st)) != CRYPT_OK) return err;
236 if ((err = rc4_ready(&st)) != CRYPT_OK) return err;
237 if (rc4_read(out, 500, &st) != 500) return CRYPT_ERROR_READPRNG; /* skip 500 bytes */
238 if (rc4_read(out, 10, &st) != 10) return CRYPT_ERROR_READPRNG; /* 10 bytes for testing */
239 if (compare_testvector(out, 10, t3, sizeof(t3), "RC4-PRNG", 3)) return CRYPT_FAIL_TESTVECTOR;
240 if ((err = rc4_done(&st)) != CRYPT_OK) return err;
248 /* ref: $Format:%D$ */
249 /* git commit: $Format:%H$ */
250 /* commit time: $Format:%ai$ */