~ubuntu-branches/ubuntu/utopic/dropbear/utopic-proposed

« back to all changes in this revision

Viewing changes to libtomcrypt/src/prngs/rc4.c

  • Committer: Bazaar Package Importer
  • Author(s): Matt Johnston
  • Date: 2005-12-08 19:20:21 UTC
  • mfrom: (1.2.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20051208192021-nyp9rwnt77nsg6ty
Tags: 0.47-1
* New upstream release.
* SECURITY: Fix incorrect buffer sizing.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 * Tom St Denis, tomstdenis@gmail.com, http://libtomcrypt.org
 
10
 */
 
11
#include "tomcrypt.h"
 
12
 
 
13
/**
 
14
  @file rc4.c
 
15
  RC4 PRNG, Tom St Denis
 
16
*/  
 
17
 
 
18
#ifdef RC4
 
19
 
 
20
const struct ltc_prng_descriptor rc4_desc = 
 
21
{
 
22
   "rc4", 32,
 
23
    &rc4_start,
 
24
    &rc4_add_entropy,
 
25
    &rc4_ready,
 
26
    &rc4_read,
 
27
    &rc4_done,
 
28
    &rc4_export,
 
29
    &rc4_import,
 
30
    &rc4_test
 
31
};
 
32
 
 
33
/**
 
34
  Start the PRNG
 
35
  @param prng     [out] The PRNG state to initialize
 
36
  @return CRYPT_OK if successful
 
37
*/  
 
38
int rc4_start(prng_state *prng)
 
39
{
 
40
    LTC_ARGCHK(prng != NULL);
 
41
 
 
42
    /* set keysize to zero */
 
43
    prng->rc4.x = 0;
 
44
    
 
45
    return CRYPT_OK;
 
46
}
 
47
 
 
48
/**
 
49
  Add entropy to the PRNG state
 
50
  @param in       The data to add
 
51
  @param inlen    Length of the data to add
 
52
  @param prng     PRNG state to update
 
53
  @return CRYPT_OK if successful
 
54
*/  
 
55
int rc4_add_entropy(const unsigned char *in, unsigned long inlen, prng_state *prng)
 
56
{
 
57
    LTC_ARGCHK(in  != NULL);
 
58
    LTC_ARGCHK(prng != NULL);
 
59
 
 
60
    /* trim as required */
 
61
    if (prng->rc4.x + inlen > 256) {
 
62
       if (prng->rc4.x == 256) {
 
63
          /* I can't possibly accept another byte, ok maybe a mint wafer... */
 
64
          return CRYPT_OK;
 
65
       } else {
 
66
          /* only accept part of it */
 
67
          inlen = 256 - prng->rc4.x;
 
68
       }       
 
69
    }
 
70
 
 
71
    while (inlen--) {
 
72
       prng->rc4.buf[prng->rc4.x++] = *in++;
 
73
    }
 
74
 
 
75
    return CRYPT_OK;
 
76
    
 
77
}
 
78
 
 
79
/**
 
80
  Make the PRNG ready to read from
 
81
  @param prng   The PRNG to make active
 
82
  @return CRYPT_OK if successful
 
83
*/  
 
84
int rc4_ready(prng_state *prng)
 
85
{
 
86
    unsigned char key[256], tmp, *s;
 
87
    int keylen, x, y, j;
 
88
 
 
89
    LTC_ARGCHK(prng != NULL);
 
90
 
 
91
    /* extract the key */
 
92
    s = prng->rc4.buf;
 
93
    XMEMCPY(key, s, 256);
 
94
    keylen = prng->rc4.x;
 
95
 
 
96
    /* make RC4 perm and shuffle */
 
97
    for (x = 0; x < 256; x++) {
 
98
        s[x] = x;
 
99
    }
 
100
 
 
101
    for (j = x = y = 0; x < 256; x++) {
 
102
        y = (y + prng->rc4.buf[x] + key[j++]) & 255;
 
103
        if (j == keylen) {
 
104
           j = 0; 
 
105
        }
 
106
        tmp = s[x]; s[x] = s[y]; s[y] = tmp;
 
107
    }
 
108
    prng->rc4.x = 0;
 
109
    prng->rc4.y = 0;
 
110
 
 
111
#ifdef LTC_CLEAN_STACK
 
112
    zeromem(key, sizeof(key));
 
113
#endif
 
114
 
 
115
    return CRYPT_OK;
 
116
}
 
117
 
 
118
/**
 
119
  Read from the PRNG
 
120
  @param out      Destination
 
121
  @param outlen   Length of output
 
122
  @param prng     The active PRNG to read from
 
123
  @return Number of octets read
 
124
*/  
 
125
unsigned long rc4_read(unsigned char *out, unsigned long outlen, prng_state *prng)
 
126
{
 
127
   unsigned char x, y, *s, tmp;
 
128
   unsigned long n;
 
129
 
 
130
   LTC_ARGCHK(out != NULL);
 
131
   LTC_ARGCHK(prng != NULL);
 
132
 
 
133
   n = outlen;
 
134
   x = prng->rc4.x;
 
135
   y = prng->rc4.y;
 
136
   s = prng->rc4.buf;
 
137
   while (outlen--) {
 
138
      x = (x + 1) & 255;
 
139
      y = (y + s[x]) & 255;
 
140
      tmp = s[x]; s[x] = s[y]; s[y] = tmp;
 
141
      tmp = (s[x] + s[y]) & 255;
 
142
      *out++ ^= s[tmp];
 
143
   }
 
144
   prng->rc4.x = x;
 
145
   prng->rc4.y = y;
 
146
   return n;
 
147
}
 
148
 
 
149
/**
 
150
  Terminate the PRNG
 
151
  @param prng   The PRNG to terminate
 
152
  @return CRYPT_OK if successful
 
153
*/  
 
154
int rc4_done(prng_state *prng)
 
155
{
 
156
   LTC_ARGCHK(prng != NULL);
 
157
   return CRYPT_OK;
 
158
}
 
159
 
 
160
/**
 
161
  Export the PRNG state
 
162
  @param out       [out] Destination
 
163
  @param outlen    [in/out] Max size and resulting size of the state
 
164
  @param prng      The PRNG to export
 
165
  @return CRYPT_OK if successful
 
166
*/  
 
167
int rc4_export(unsigned char *out, unsigned long *outlen, prng_state *prng)
 
168
{
 
169
   LTC_ARGCHK(outlen != NULL);
 
170
   LTC_ARGCHK(out    != NULL);
 
171
   LTC_ARGCHK(prng   != NULL);
 
172
 
 
173
   if (*outlen < 32) {
 
174
      return CRYPT_BUFFER_OVERFLOW;
 
175
   }
 
176
 
 
177
   if (rc4_read(out, 32, prng) != 32) {
 
178
      return CRYPT_ERROR_READPRNG;
 
179
   }
 
180
   *outlen = 32;
 
181
 
 
182
   return CRYPT_OK;
 
183
}
 
184
 
 
185
/**
 
186
  Import a PRNG state
 
187
  @param in       The PRNG state
 
188
  @param inlen    Size of the state
 
189
  @param prng     The PRNG to import
 
190
  @return CRYPT_OK if successful
 
191
*/  
 
192
int rc4_import(const unsigned char *in, unsigned long inlen, prng_state *prng)
 
193
{
 
194
   int err;
 
195
   LTC_ARGCHK(in   != NULL);
 
196
   LTC_ARGCHK(prng != NULL);
 
197
 
 
198
   if (inlen != 32) {
 
199
      return CRYPT_INVALID_ARG;
 
200
   }
 
201
   
 
202
   if ((err = rc4_start(prng)) != CRYPT_OK) {
 
203
      return err;
 
204
   }
 
205
   return rc4_add_entropy(in, 32, prng);
 
206
}
 
207
 
 
208
/**
 
209
  PRNG self-test
 
210
  @return CRYPT_OK if successful, CRYPT_NOP if self-testing has been disabled
 
211
*/  
 
212
int rc4_test(void)
 
213
{
 
214
#ifndef LTC_TEST
 
215
   return CRYPT_NOP;
 
216
#else
 
217
   static const struct {
 
218
      unsigned char key[8], pt[8], ct[8];
 
219
   } tests[] = {
 
220
{
 
221
   { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef },
 
222
   { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef },
 
223
   { 0x75, 0xb7, 0x87, 0x80, 0x99, 0xe0, 0xc5, 0x96 }
 
224
}
 
225
};
 
226
   prng_state prng;
 
227
   unsigned char dst[8];
 
228
   int err, x;
 
229
 
 
230
   for (x = 0; x < (int)(sizeof(tests)/sizeof(tests[0])); x++) {
 
231
       if ((err = rc4_start(&prng)) != CRYPT_OK) {
 
232
          return err;
 
233
       }
 
234
       if ((err = rc4_add_entropy(tests[x].key, 8, &prng)) != CRYPT_OK) {
 
235
          return err;
 
236
       }
 
237
       if ((err = rc4_ready(&prng)) != CRYPT_OK) {
 
238
          return err;
 
239
       }
 
240
       XMEMCPY(dst, tests[x].pt, 8);
 
241
       if (rc4_read(dst, 8, &prng) != 8) {
 
242
          return CRYPT_ERROR_READPRNG;
 
243
       }
 
244
       rc4_done(&prng);
 
245
       if (memcmp(dst, tests[x].ct, 8)) {
 
246
#if 0
 
247
          int y;
 
248
          printf("\n\nRC4 failed, I got:\n"); 
 
249
          for (y = 0; y < 8; y++) printf("%02x ", dst[y]);
 
250
          printf("\n");
 
251
#endif
 
252
          return CRYPT_FAIL_TESTVECTOR;
 
253
       }
 
254
   }
 
255
   return CRYPT_OK;
 
256
#endif
 
257
}
 
258
 
 
259
#endif
 
260
 
 
261
 
 
262
/* $Source: /cvs/libtom/libtomcrypt/src/prngs/rc4.c,v $ */
 
263
/* $Revision: 1.3 $ */
 
264
/* $Date: 2005/05/05 14:35:59 $ */