1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /* lib/crypto/builtin/enc_provider/rc4.c */
3 /*
4 * Copyright (c) 2000 by Computer Science Laboratory,
5 * Rensselaer Polytechnic Institute
6 *
7 * #include STD_DISCLAIMER
8 */
9
10 #include "crypto_int.h"
11
12 #ifdef K5_BUILTIN_RC4
13
14 typedef struct
15 {
16 unsigned int x;
17 unsigned int y;
18 unsigned char state[256];
19 } ArcfourContext;
20
21 typedef struct {
22 int initialized;
23 ArcfourContext ctx;
24 } ArcFourCipherState;
25
26 /* gets the next byte from the PRNG */
27 #if ((__GNUC__ >= 2) )
28 static __inline__ unsigned int k5_arcfour_byte(ArcfourContext *);
29 #else
30 static unsigned int k5_arcfour_byte(ArcfourContext *);
31 #endif /* gcc inlines*/
32
33 /* Initializes the context and sets the key. */
34 static krb5_error_code k5_arcfour_init(ArcfourContext *ctx, const unsigned char *key,
35 unsigned int keylen);
36
37 /* Encrypts/decrypts data. */
38 static void k5_arcfour_crypt(ArcfourContext *ctx, unsigned char *dest,
39 const unsigned char *src, unsigned int len);
40
k5_arcfour_byte(ArcfourContext * ctx)41 static inline unsigned int k5_arcfour_byte(ArcfourContext * ctx)
42 {
43 unsigned int x;
44 unsigned int y;
45 unsigned int sx, sy;
46 unsigned char *state;
47
48 state = ctx->state;
49 x = (ctx->x + 1) & 0xff;
50 sx = state[x];
51 y = (sx + ctx->y) & 0xff;
52 sy = state[y];
53 ctx->x = x;
54 ctx->y = y;
55 state[y] = sx;
56 state[x] = sy;
57 return state[(sx + sy) & 0xff];
58 }
59
k5_arcfour_crypt(ArcfourContext * ctx,unsigned char * dest,const unsigned char * src,unsigned int len)60 static void k5_arcfour_crypt(ArcfourContext *ctx, unsigned char *dest,
61 const unsigned char *src, unsigned int len)
62 {
63 unsigned int i;
64 for (i = 0; i < len; i++)
65 dest[i] = src[i] ^ k5_arcfour_byte(ctx);
66 }
67
68
69 static krb5_error_code
k5_arcfour_init(ArcfourContext * ctx,const unsigned char * key,unsigned int key_len)70 k5_arcfour_init(ArcfourContext *ctx, const unsigned char *key,
71 unsigned int key_len)
72 {
73 unsigned int t, u;
74 unsigned int keyindex;
75 unsigned int stateindex;
76 unsigned char* state;
77 unsigned int counter;
78
79 if (key_len != 16)
80 return KRB5_BAD_MSIZE; /*this is probably not the correct error code
81 to return */
82 state = &ctx->state[0];
83 ctx->x = 0;
84 ctx->y = 0;
85 for (counter = 0; counter < 256; counter++)
86 state[counter] = counter;
87 keyindex = 0;
88 stateindex = 0;
89 for (counter = 0; counter < 256; counter++)
90 {
91 t = state[counter];
92 stateindex = (stateindex + key[keyindex] + t) & 0xff;
93 u = state[stateindex];
94 state[stateindex] = t;
95 state[counter] = u;
96 if (++keyindex >= key_len)
97 keyindex = 0;
98 }
99 return 0;
100 }
101
102
103 static krb5_error_code
k5_arcfour_docrypt(krb5_key key,const krb5_data * state,krb5_crypto_iov * data,size_t num_data)104 k5_arcfour_docrypt(krb5_key key, const krb5_data *state, krb5_crypto_iov *data,
105 size_t num_data)
106 {
107 ArcfourContext *arcfour_ctx = NULL;
108 ArcFourCipherState *cipher_state = NULL;
109 krb5_error_code ret;
110 size_t i;
111
112 if (key->keyblock.length != 16)
113 return KRB5_BAD_KEYSIZE;
114 if (state != NULL && (state->length != sizeof(ArcFourCipherState)))
115 return KRB5_BAD_MSIZE;
116
117 if (state != NULL) {
118 cipher_state = (ArcFourCipherState *)(void *)state->data;
119 arcfour_ctx = &cipher_state->ctx;
120 if (cipher_state->initialized == 0) {
121 ret = k5_arcfour_init(arcfour_ctx, key->keyblock.contents,
122 key->keyblock.length);
123 if (ret != 0)
124 return ret;
125
126 cipher_state->initialized = 1;
127 }
128 } else {
129 arcfour_ctx = (ArcfourContext *)malloc(sizeof(ArcfourContext));
130 if (arcfour_ctx == NULL)
131 return ENOMEM;
132
133 ret = k5_arcfour_init(arcfour_ctx, key->keyblock.contents,
134 key->keyblock.length);
135 if (ret != 0) {
136 free(arcfour_ctx);
137 return ret;
138 }
139 }
140
141 for (i = 0; i < num_data; i++) {
142 krb5_crypto_iov *iov = &data[i];
143
144 if (ENCRYPT_IOV(iov))
145 k5_arcfour_crypt(arcfour_ctx, (unsigned char *)iov->data.data,
146 (const unsigned char *)iov->data.data, iov->data.length);
147 }
148
149 if (state == NULL)
150 zapfree(arcfour_ctx, sizeof(ArcfourContext));
151
152 return 0;
153 }
154
155 static krb5_error_code
k5_arcfour_init_state(const krb5_keyblock * key,krb5_keyusage keyusage,krb5_data * new_state)156 k5_arcfour_init_state (const krb5_keyblock *key,
157 krb5_keyusage keyusage, krb5_data *new_state)
158 {
159 /* Note that we can't actually set up the state here because the key
160 * will change between now and when encrypt is called
161 * because it is data dependent. Yeah, this has strange
162 * properties. --SDH
163 */
164 new_state->length = sizeof (ArcFourCipherState);
165 new_state->data = malloc (new_state->length);
166 if (new_state->data) {
167 memset (new_state->data, 0 , new_state->length);
168 /* That will set initialized to zero*/
169 }else {
170 return (ENOMEM);
171 }
172 return 0;
173 }
174
175 /* Since the arcfour cipher is identical going forwards and backwards,
176 we just call "docrypt" directly
177 */
178 const struct krb5_enc_provider krb5int_enc_arcfour = {
179 /* This seems to work... although I am not sure what the
180 implications are in other places in the kerberos library */
181 1,
182 /* Keysize is arbitrary in arcfour, but the constraints of the
183 system, and to attempt to work with the MSFT system forces us
184 to 16byte/128bit. Since there is no parity in the key, the
185 byte and length are the same. */
186 16, 16,
187 k5_arcfour_docrypt,
188 k5_arcfour_docrypt,
189 NULL,
190 k5_arcfour_init_state, /*xxx not implemented yet*/
191 krb5int_default_free_state
192 };
193
194 #endif /* K5_BUILTIN_RC4 */
195