xref: /dragonfly/contrib/wpa_supplicant/src/crypto/crypto_internal-cipher.c (revision bcf9aa4feb4a2fdf8ceac276d271a57f4b27e13d)
1 /*
2  * Crypto wrapper for internal crypto implementation - Cipher wrappers
3  * Copyright (c) 2006-2009, Jouni Malinen <j@w1.fi>
4  *
5  * This software may be distributed under the terms of the BSD license.
6  * See README for more details.
7  */
8 
9 #include "includes.h"
10 
11 #include "common.h"
12 #include "crypto.h"
13 #include "aes.h"
14 #include "des_i.h"
15 
16 
17 struct crypto_cipher {
18           enum crypto_cipher_alg alg;
19           union {
20                     struct {
21                               size_t used_bytes;
22                               u8 key[16];
23                               size_t keylen;
24                     } rc4;
25                     struct {
26                               u8 cbc[32];
27                               void *ctx_enc;
28                               void *ctx_dec;
29                     } aes;
30                     struct {
31                               struct des3_key_s key;
32                               u8 cbc[8];
33                     } des3;
34                     struct {
35                               u32 ek[32];
36                               u32 dk[32];
37                               u8 cbc[8];
38                     } des;
39           } u;
40 };
41 
42 
crypto_cipher_init(enum crypto_cipher_alg alg,const u8 * iv,const u8 * key,size_t key_len)43 struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg,
44                                                     const u8 *iv, const u8 *key,
45                                                     size_t key_len)
46 {
47           struct crypto_cipher *ctx;
48 
49           ctx = os_zalloc(sizeof(*ctx));
50           if (ctx == NULL)
51                     return NULL;
52 
53           ctx->alg = alg;
54 
55           switch (alg) {
56           case CRYPTO_CIPHER_ALG_RC4:
57                     if (key_len > sizeof(ctx->u.rc4.key)) {
58                               os_free(ctx);
59                               return NULL;
60                     }
61                     ctx->u.rc4.keylen = key_len;
62                     os_memcpy(ctx->u.rc4.key, key, key_len);
63                     break;
64           case CRYPTO_CIPHER_ALG_AES:
65                     ctx->u.aes.ctx_enc = aes_encrypt_init(key, key_len);
66                     if (ctx->u.aes.ctx_enc == NULL) {
67                               os_free(ctx);
68                               return NULL;
69                     }
70                     ctx->u.aes.ctx_dec = aes_decrypt_init(key, key_len);
71                     if (ctx->u.aes.ctx_dec == NULL) {
72                               aes_encrypt_deinit(ctx->u.aes.ctx_enc);
73                               os_free(ctx);
74                               return NULL;
75                     }
76                     os_memcpy(ctx->u.aes.cbc, iv, AES_BLOCK_SIZE);
77                     break;
78           case CRYPTO_CIPHER_ALG_3DES:
79                     if (key_len != 24) {
80                               os_free(ctx);
81                               return NULL;
82                     }
83                     des3_key_setup(key, &ctx->u.des3.key);
84                     os_memcpy(ctx->u.des3.cbc, iv, 8);
85                     break;
86           case CRYPTO_CIPHER_ALG_DES:
87                     if (key_len != 8) {
88                               os_free(ctx);
89                               return NULL;
90                     }
91                     des_key_setup(key, ctx->u.des.ek, ctx->u.des.dk);
92                     os_memcpy(ctx->u.des.cbc, iv, 8);
93                     break;
94           default:
95                     os_free(ctx);
96                     return NULL;
97           }
98 
99           return ctx;
100 }
101 
102 
crypto_cipher_encrypt(struct crypto_cipher * ctx,const u8 * plain,u8 * crypt,size_t len)103 int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain,
104                                 u8 *crypt, size_t len)
105 {
106           size_t i, j, blocks;
107 
108           switch (ctx->alg) {
109           case CRYPTO_CIPHER_ALG_RC4:
110                     if (plain != crypt)
111                               os_memcpy(crypt, plain, len);
112                     rc4_skip(ctx->u.rc4.key, ctx->u.rc4.keylen,
113                                ctx->u.rc4.used_bytes, crypt, len);
114                     ctx->u.rc4.used_bytes += len;
115                     break;
116           case CRYPTO_CIPHER_ALG_AES:
117                     if (len % AES_BLOCK_SIZE)
118                               return -1;
119                     blocks = len / AES_BLOCK_SIZE;
120                     for (i = 0; i < blocks; i++) {
121                               for (j = 0; j < AES_BLOCK_SIZE; j++)
122                                         ctx->u.aes.cbc[j] ^= plain[j];
123                               aes_encrypt(ctx->u.aes.ctx_enc, ctx->u.aes.cbc,
124                                             ctx->u.aes.cbc);
125                               os_memcpy(crypt, ctx->u.aes.cbc, AES_BLOCK_SIZE);
126                               plain += AES_BLOCK_SIZE;
127                               crypt += AES_BLOCK_SIZE;
128                     }
129                     break;
130           case CRYPTO_CIPHER_ALG_3DES:
131                     if (len % 8)
132                               return -1;
133                     blocks = len / 8;
134                     for (i = 0; i < blocks; i++) {
135                               for (j = 0; j < 8; j++)
136                                         ctx->u.des3.cbc[j] ^= plain[j];
137                               des3_encrypt(ctx->u.des3.cbc, &ctx->u.des3.key,
138                                              ctx->u.des3.cbc);
139                               os_memcpy(crypt, ctx->u.des3.cbc, 8);
140                               plain += 8;
141                               crypt += 8;
142                     }
143                     break;
144           case CRYPTO_CIPHER_ALG_DES:
145                     if (len % 8)
146                               return -1;
147                     blocks = len / 8;
148                     for (i = 0; i < blocks; i++) {
149                               for (j = 0; j < 8; j++)
150                                         ctx->u.des3.cbc[j] ^= plain[j];
151                               des_block_encrypt(ctx->u.des.cbc, ctx->u.des.ek,
152                                                     ctx->u.des.cbc);
153                               os_memcpy(crypt, ctx->u.des.cbc, 8);
154                               plain += 8;
155                               crypt += 8;
156                     }
157                     break;
158           default:
159                     return -1;
160           }
161 
162           return 0;
163 }
164 
165 
crypto_cipher_decrypt(struct crypto_cipher * ctx,const u8 * crypt,u8 * plain,size_t len)166 int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt,
167                                 u8 *plain, size_t len)
168 {
169           size_t i, j, blocks;
170           u8 tmp[32];
171 
172           switch (ctx->alg) {
173           case CRYPTO_CIPHER_ALG_RC4:
174                     if (plain != crypt)
175                               os_memcpy(plain, crypt, len);
176                     rc4_skip(ctx->u.rc4.key, ctx->u.rc4.keylen,
177                                ctx->u.rc4.used_bytes, plain, len);
178                     ctx->u.rc4.used_bytes += len;
179                     break;
180           case CRYPTO_CIPHER_ALG_AES:
181                     if (len % AES_BLOCK_SIZE)
182                               return -1;
183                     blocks = len / AES_BLOCK_SIZE;
184                     for (i = 0; i < blocks; i++) {
185                               os_memcpy(tmp, crypt, AES_BLOCK_SIZE);
186                               aes_decrypt(ctx->u.aes.ctx_dec, crypt, plain);
187                               for (j = 0; j < AES_BLOCK_SIZE; j++)
188                                         plain[j] ^= ctx->u.aes.cbc[j];
189                               os_memcpy(ctx->u.aes.cbc, tmp, AES_BLOCK_SIZE);
190                               plain += AES_BLOCK_SIZE;
191                               crypt += AES_BLOCK_SIZE;
192                     }
193                     break;
194           case CRYPTO_CIPHER_ALG_3DES:
195                     if (len % 8)
196                               return -1;
197                     blocks = len / 8;
198                     for (i = 0; i < blocks; i++) {
199                               os_memcpy(tmp, crypt, 8);
200                               des3_decrypt(crypt, &ctx->u.des3.key, plain);
201                               for (j = 0; j < 8; j++)
202                                         plain[j] ^= ctx->u.des3.cbc[j];
203                               os_memcpy(ctx->u.des3.cbc, tmp, 8);
204                               plain += 8;
205                               crypt += 8;
206                     }
207                     break;
208           case CRYPTO_CIPHER_ALG_DES:
209                     if (len % 8)
210                               return -1;
211                     blocks = len / 8;
212                     for (i = 0; i < blocks; i++) {
213                               os_memcpy(tmp, crypt, 8);
214                               des_block_decrypt(crypt, ctx->u.des.dk, plain);
215                               for (j = 0; j < 8; j++)
216                                         plain[j] ^= ctx->u.des.cbc[j];
217                               os_memcpy(ctx->u.des.cbc, tmp, 8);
218                               plain += 8;
219                               crypt += 8;
220                     }
221                     break;
222           default:
223                     return -1;
224           }
225 
226           return 0;
227 }
228 
229 
crypto_cipher_deinit(struct crypto_cipher * ctx)230 void crypto_cipher_deinit(struct crypto_cipher *ctx)
231 {
232           switch (ctx->alg) {
233           case CRYPTO_CIPHER_ALG_AES:
234                     aes_encrypt_deinit(ctx->u.aes.ctx_enc);
235                     aes_decrypt_deinit(ctx->u.aes.ctx_dec);
236                     break;
237           case CRYPTO_CIPHER_ALG_3DES:
238                     break;
239           default:
240                     break;
241           }
242           os_free(ctx);
243 }
244