Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
wine-mirror
GitHub Repository: wine-mirror/wine
Path: blob/master/libs/tomcrypt/src/prngs/rc4.c
5971 views
1
/* LibTomCrypt, modular cryptographic library -- Tom St Denis
2
*
3
* LibTomCrypt is a library that provides various cryptographic
4
* algorithms in a highly modular and flexible manner.
5
*
6
* The library is free for all purposes without any express
7
* guarantee it works.
8
*/
9
#include "tomcrypt.h"
10
11
/**
12
@file prngs/rc4.c
13
RC4 PRNG, Tom St Denis
14
*/
15
16
#ifdef LTC_RC4
17
18
const struct ltc_prng_descriptor rc4_desc =
19
{
20
"rc4",
21
32,
22
&rc4_start,
23
&rc4_add_entropy,
24
&rc4_ready,
25
&rc4_read,
26
&rc4_done,
27
&rc4_export,
28
&rc4_import,
29
&rc4_test
30
};
31
32
/**
33
Start the PRNG
34
@param prng [out] The PRNG state to initialize
35
@return CRYPT_OK if successful
36
*/
37
int rc4_start(prng_state *prng)
38
{
39
LTC_ARGCHK(prng != NULL);
40
prng->ready = 0;
41
/* set entropy (key) size to zero */
42
prng->rc4.s.x = 0;
43
/* clear entropy (key) buffer */
44
XMEMSET(&prng->rc4.s.buf, 0, sizeof(prng->rc4.s.buf));
45
LTC_MUTEX_INIT(&prng->lock)
46
return CRYPT_OK;
47
}
48
49
/**
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
55
*/
56
int rc4_add_entropy(const unsigned char *in, unsigned long inlen, prng_state *prng)
57
{
58
unsigned char buf[256];
59
unsigned long i;
60
int err;
61
62
LTC_ARGCHK(prng != NULL);
63
LTC_ARGCHK(in != NULL);
64
LTC_ARGCHK(inlen > 0);
65
66
LTC_MUTEX_LOCK(&prng->lock);
67
if (prng->ready) {
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];
71
/* initialize RC4 */
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));
76
}
77
else {
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++;
80
}
81
err = CRYPT_OK;
82
LBL_UNLOCK:
83
LTC_MUTEX_UNLOCK(&prng->lock);
84
return err;
85
}
86
87
/**
88
Make the PRNG ready to read from
89
@param prng The PRNG to make active
90
@return CRYPT_OK if successful
91
*/
92
int rc4_ready(prng_state *prng)
93
{
94
unsigned char buf[256] = { 0 };
95
unsigned long len;
96
int err, i;
97
98
LTC_ARGCHK(prng != NULL);
99
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));
103
/* initialize RC4 */
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));
108
prng->ready = 1;
109
LBL_UNLOCK:
110
LTC_MUTEX_UNLOCK(&prng->lock);
111
return err;
112
}
113
114
/**
115
Read from the PRNG
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
120
*/
121
unsigned long rc4_read(unsigned char *out, unsigned long outlen, prng_state *prng)
122
{
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;
127
LBL_UNLOCK:
128
LTC_MUTEX_UNLOCK(&prng->lock);
129
return outlen;
130
}
131
132
/**
133
Terminate the PRNG
134
@param prng The PRNG to terminate
135
@return CRYPT_OK if successful
136
*/
137
int rc4_done(prng_state *prng)
138
{
139
int err;
140
LTC_ARGCHK(prng != NULL);
141
LTC_MUTEX_LOCK(&prng->lock);
142
prng->ready = 0;
143
err = rc4_stream_done(&prng->rc4.s);
144
LTC_MUTEX_UNLOCK(&prng->lock);
145
LTC_MUTEX_DESTROY(&prng->lock);
146
return err;
147
}
148
149
/**
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
155
*/
156
int rc4_export(unsigned char *out, unsigned long *outlen, prng_state *prng)
157
{
158
unsigned long len = rc4_desc.export_size;
159
160
LTC_ARGCHK(prng != NULL);
161
LTC_ARGCHK(out != NULL);
162
LTC_ARGCHK(outlen != NULL);
163
164
if (*outlen < len) {
165
*outlen = len;
166
return CRYPT_BUFFER_OVERFLOW;
167
}
168
169
if (rc4_read(out, len, prng) != len) {
170
return CRYPT_ERROR_READPRNG;
171
}
172
173
*outlen = len;
174
return CRYPT_OK;
175
}
176
177
/**
178
Import a PRNG state
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
183
*/
184
int rc4_import(const unsigned char *in, unsigned long inlen, prng_state *prng)
185
{
186
int err;
187
188
LTC_ARGCHK(prng != NULL);
189
LTC_ARGCHK(in != NULL);
190
if (inlen < (unsigned long)rc4_desc.export_size) return CRYPT_INVALID_ARG;
191
192
if ((err = rc4_start(prng)) != CRYPT_OK) return err;
193
if ((err = rc4_add_entropy(in, inlen, prng)) != CRYPT_OK) return err;
194
return CRYPT_OK;
195
}
196
197
/**
198
PRNG self-test
199
@return CRYPT_OK if successful, CRYPT_NOP if self-testing has been disabled
200
*/
201
int rc4_test(void)
202
{
203
#ifndef LTC_TEST
204
return CRYPT_NOP;
205
#else
206
prng_state st;
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 };
218
int err;
219
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;
241
242
return CRYPT_OK;
243
#endif
244
}
245
246
#endif
247
248