xref: /freebsd/crypto/krb5/src/lib/crypto/builtin/enc_provider/rc4.c (revision 7f2fe78b9dd5f51c821d771b63d2e096f6fd49e9)
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