blob: df1bc11ed6cf7320b5ad320699f220b9d791e619 [file] [log] [blame]
Adam Langley95c29f32014-06-20 12:00:00 -07001/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
2 * All rights reserved.
3 *
4 * This package is an SSL implementation written
5 * by Eric Young (eay@cryptsoft.com).
6 * The implementation was written so as to conform with Netscapes SSL.
7 *
8 * This library is free for commercial and non-commercial use as long as
9 * the following conditions are aheared to. The following conditions
10 * apply to all code found in this distribution, be it the RC4, RSA,
11 * lhash, DES, etc., code; not just the SSL code. The SSL documentation
12 * included with this distribution is covered by the same copyright terms
13 * except that the holder is Tim Hudson (tjh@cryptsoft.com).
14 *
15 * Copyright remains Eric Young's, and as such any Copyright notices in
16 * the code are not to be removed.
17 * If this package is used in a product, Eric Young should be given attribution
18 * as the author of the parts of the library used.
19 * This can be in the form of a textual message at program startup or
20 * in documentation (online or textual) provided with the package.
21 *
22 * Redistribution and use in source and binary forms, with or without
23 * modification, are permitted provided that the following conditions
24 * are met:
25 * 1. Redistributions of source code must retain the copyright
26 * notice, this list of conditions and the following disclaimer.
27 * 2. Redistributions in binary form must reproduce the above copyright
28 * notice, this list of conditions and the following disclaimer in the
29 * documentation and/or other materials provided with the distribution.
30 * 3. All advertising materials mentioning features or use of this software
31 * must display the following acknowledgement:
32 * "This product includes cryptographic software written by
33 * Eric Young (eay@cryptsoft.com)"
34 * The word 'cryptographic' can be left out if the rouines from the library
35 * being used are not cryptographic related :-).
36 * 4. If you include any Windows specific code (or a derivative thereof) from
37 * the apps directory (application code) you must include an acknowledgement:
38 * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
39 *
40 * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
41 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
43 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
44 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
45 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
46 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
48 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
49 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
50 * SUCH DAMAGE.
51 *
52 * The licence and distribution terms for any publically available version or
53 * derivative of this code cannot be changed. i.e. this code cannot simply be
54 * copied and put under another distribution licence
55 * [including the GNU Public Licence.] */
56
Adam Langley45ec21b2014-06-24 17:26:59 -070057#include <openssl/aead.h>
58
59#include <assert.h>
60
Adam Langley95c29f32014-06-20 12:00:00 -070061#include <openssl/cipher.h>
Adam Langley45ec21b2014-06-24 17:26:59 -070062#include <openssl/err.h>
Adam Langley95c29f32014-06-20 12:00:00 -070063#include <openssl/md5.h>
Adam Langley45ec21b2014-06-24 17:26:59 -070064#include <openssl/mem.h>
Adam Langley95c29f32014-06-20 12:00:00 -070065#include <openssl/obj.h>
66#include <openssl/rc4.h>
67
68#include "internal.h"
69
70
71static int rc4_init_key(EVP_CIPHER_CTX *ctx, const uint8_t *key,
72 const uint8_t *iv, int enc) {
73 RC4_KEY *rc4key = (RC4_KEY *)ctx->cipher_data;
74
75 RC4_set_key(rc4key, EVP_CIPHER_CTX_key_length(ctx), key);
76 return 1;
77}
78
79static int rc4_cipher(EVP_CIPHER_CTX *ctx, uint8_t *out, const uint8_t *in,
80 size_t in_len) {
81 RC4_KEY *rc4key = (RC4_KEY *)ctx->cipher_data;
82
83 RC4(rc4key, in_len, in, out);
84 return 1;
85}
86
87static const EVP_CIPHER rc4 = {
88 NID_rc4, 1 /* block_size */, 16 /* key_size */,
89 0 /* iv_len */, sizeof(RC4_KEY), EVP_CIPH_VARIABLE_LENGTH,
90 NULL /* app_data */, rc4_init_key, rc4_cipher,
91 NULL /* cleanup */, NULL /* ctrl */, };
92
93const EVP_CIPHER *EVP_rc4(void) { return &rc4; }
Adam Langley45ec21b2014-06-24 17:26:59 -070094
95
96struct aead_rc4_md5_tls_ctx {
97 RC4_KEY rc4;
98 MD5_CTX head, tail, md;
99 size_t payload_length;
100 unsigned char tag_len;
101};
102
103
104static int
105aead_rc4_md5_tls_init(EVP_AEAD_CTX *ctx, const uint8_t *key, size_t key_len,
106 size_t tag_len) {
107 struct aead_rc4_md5_tls_ctx *rc4_ctx;
108 size_t i;
109 uint8_t hmac_key[MD5_CBLOCK];
110
111 if (tag_len == EVP_AEAD_DEFAULT_TAG_LENGTH) {
112 tag_len = MD5_DIGEST_LENGTH;
113 }
114
115 if (tag_len > MD5_DIGEST_LENGTH) {
116 OPENSSL_PUT_ERROR(CIPHER, aead_rc4_md5_tls_init, CIPHER_R_TOO_LARGE);
117 return 0;
118 }
119
120 /* The keys consists of |MD5_DIGEST_LENGTH| bytes of HMAC(MD5) key followed
121 * by some number of bytes of RC4 key. */
122 if (key_len <= MD5_DIGEST_LENGTH) {
123 OPENSSL_PUT_ERROR(CIPHER, aead_rc4_md5_tls_init, CIPHER_R_BAD_KEY_LENGTH);
124 return 0;
125 }
126
127 rc4_ctx = OPENSSL_malloc(sizeof(struct aead_rc4_md5_tls_ctx));
128 if (rc4_ctx == NULL) {
129 OPENSSL_PUT_ERROR(CIPHER, aead_rc4_md5_tls_init, ERR_R_MALLOC_FAILURE);
130 return 0;
131 }
132 memset(rc4_ctx, 0, sizeof(struct aead_rc4_md5_tls_ctx));
133
134 RC4_set_key(&rc4_ctx->rc4, key_len - MD5_DIGEST_LENGTH,
135 key + MD5_DIGEST_LENGTH);
136
137 memset(hmac_key, 0, sizeof(hmac_key));
138 memcpy(hmac_key, key, MD5_DIGEST_LENGTH);
139 for (i = 0; i < sizeof(hmac_key); i++) {
140 hmac_key[i] ^= 0x36;
141 }
142 MD5_Init(&rc4_ctx->head);
143 MD5_Update(&rc4_ctx->head, hmac_key, sizeof(hmac_key));
144 for (i = 0; i < sizeof(hmac_key); i++) {
145 hmac_key[i] ^= 0x36 ^ 0x5c;
146 }
147 MD5_Init(&rc4_ctx->tail);
148 MD5_Update(&rc4_ctx->tail, hmac_key, sizeof(hmac_key));
149
150 rc4_ctx->tag_len = tag_len;
151 ctx->aead_state = rc4_ctx;
152
153 return 1;
154}
155
156static void aead_rc4_md5_tls_cleanup(EVP_AEAD_CTX *ctx) {
157 struct aead_rc4_md5_tls_ctx *rc4_ctx = ctx->aead_state;
158 OPENSSL_cleanse(rc4_ctx, sizeof(struct aead_rc4_md5_tls_ctx));
159 OPENSSL_free(rc4_ctx);
160}
161
162#if !defined(OPENSSL_NO_ASM) && defined(OPENSSL_X86_64)
163#define STITCHED_CALL
164
165/* rc4_md5_enc is defined in rc4_md5-x86_64.pl */
166void rc4_md5_enc(RC4_KEY *key, const void *in0, void *out, MD5_CTX *ctx,
167 const void *inp, size_t blocks);
168#endif
169
170static int aead_rc4_md5_tls_seal(const EVP_AEAD_CTX *ctx, uint8_t *out,
171 size_t *out_len, size_t max_out_len,
172 const uint8_t *nonce, size_t nonce_len,
173 const uint8_t *in, size_t in_len,
174 const uint8_t *ad, size_t ad_len) {
175 struct aead_rc4_md5_tls_ctx *rc4_ctx = ctx->aead_state;
176 MD5_CTX md;
177#if defined(STITCHED_CALL)
178 size_t rc4_off, md5_off, blocks;
179 extern unsigned int OPENSSL_ia32cap_P[];
180#else
181 const size_t rc4_off = 0;
182 const size_t md5_off = 0;
183#endif
184 uint8_t digest[MD5_DIGEST_LENGTH];
185
186 if (in_len + rc4_ctx->tag_len < in_len) {
187 OPENSSL_PUT_ERROR(CIPHER, aead_rc4_md5_tls_seal, CIPHER_R_TOO_LARGE);
188 return 0;
189 }
190
191 if (nonce_len != 0) {
192 OPENSSL_PUT_ERROR(CIPHER, aead_rc4_md5_tls_seal, CIPHER_R_IV_TOO_LARGE);
193 return 0;
194 }
195
196 if (max_out_len < in_len + rc4_ctx->tag_len) {
197 OPENSSL_PUT_ERROR(CIPHER, aead_rc4_md5_tls_seal, CIPHER_R_BUFFER_TOO_SMALL);
198 return 0;
199 }
200
201 if (nonce_len != 0) {
202 OPENSSL_PUT_ERROR(CIPHER, aead_rc4_md5_tls_seal, CIPHER_R_TOO_LARGE);
203 return 0;
204 }
205
206 memcpy(&md, &rc4_ctx->head, sizeof(MD5_CTX));
207 /* The MAC's payload begins with the additional data. See
208 * https://tools.ietf.org/html/rfc5246#section-6.2.3.1 */
209 MD5_Update(&md, ad, ad_len);
210
211#if defined(STITCHED_CALL)
212 /* 32 is $MOD from rc4_md5-x86_64.pl. */
213 rc4_off = 32 - 1 - (rc4_ctx->rc4.x & (32 - 1));
214 md5_off = MD5_CBLOCK - md.num;
215 /* Ensure RC4 is behind MD5. */
216 if (rc4_off > md5_off) {
217 md5_off += MD5_CBLOCK;
218 }
219 assert(md5_off >= rc4_off);
220
221 if (in_len > md5_off && (blocks = (in_len - md5_off) / MD5_CBLOCK) &&
222 (OPENSSL_ia32cap_P[0] & (1 << 20)) == 0) {
223 /* Process the initial portions of the plaintext normally. */
224 MD5_Update(&md, in, md5_off);
225 RC4(&rc4_ctx->rc4, rc4_off, in, out);
226
227 /* Process the next |blocks| blocks of plaintext with stitched routines. */
228 rc4_md5_enc(&rc4_ctx->rc4, in + rc4_off, out + rc4_off, &md, in + md5_off,
229 blocks);
230 blocks *= MD5_CBLOCK;
231 rc4_off += blocks;
232 md5_off += blocks;
233 md.Nh += blocks >> 29;
234 md.Nl += blocks <<= 3;
235 if (md.Nl < (unsigned int)blocks) {
236 md.Nh++;
237 }
238 } else {
239 rc4_off = 0;
240 md5_off = 0;
241 }
242#endif
243 /* Finish computing the MAC. */
244 MD5_Update(&md, in + md5_off, in_len - md5_off);
245 MD5_Final(digest, &md);
246
247 memcpy(&md, &rc4_ctx->tail, sizeof(MD5_CTX));
248 MD5_Update(&md, digest, sizeof(digest));
249 if (rc4_ctx->tag_len == MD5_DIGEST_LENGTH) {
250 MD5_Final(out + in_len, &md);
251 } else {
252 MD5_Final(digest, &md);
253 memcpy(out + in_len, digest, rc4_ctx->tag_len);
254 }
255
256 /* Encrypt the remainder of the plaintext and the MAC. */
257 RC4(&rc4_ctx->rc4, in_len - rc4_off, in + rc4_off, out + rc4_off);
258 RC4(&rc4_ctx->rc4, MD5_DIGEST_LENGTH, out + in_len, out + in_len);
259
260 *out_len = in_len + rc4_ctx->tag_len;
261 return 1;
262}
263
264static int aead_rc4_md5_tls_open(const EVP_AEAD_CTX *ctx, uint8_t *out,
265 size_t *out_len, size_t max_out_len,
266 const uint8_t *nonce, size_t nonce_len,
267 const uint8_t *in, size_t in_len,
268 const uint8_t *ad, size_t ad_len) {
269 struct aead_rc4_md5_tls_ctx *rc4_ctx = ctx->aead_state;
270 MD5_CTX md;
271 size_t plaintext_len;
272#if defined(STITCHED_CALL)
273 unsigned int l;
274 size_t rc4_off, md5_off, blocks;
275 extern unsigned int OPENSSL_ia32cap_P[];
276#else
277 const size_t rc4_off = 0;
278 const size_t md5_off = 0;
279#endif
280 uint8_t digest[MD5_DIGEST_LENGTH];
281
282 if (in_len < rc4_ctx->tag_len) {
283 OPENSSL_PUT_ERROR(CIPHER, aead_rc4_md5_tls_open, CIPHER_R_BAD_DECRYPT);
284 return 0;
285 }
286
287 plaintext_len = in_len - rc4_ctx->tag_len;
288
289 if (nonce_len != 0) {
290 OPENSSL_PUT_ERROR(CIPHER, aead_rc4_md5_tls_seal, CIPHER_R_TOO_LARGE);
291 return 0;
292 }
293
294 if (max_out_len < plaintext_len) {
295 OPENSSL_PUT_ERROR(CIPHER, aead_rc4_md5_tls_open, CIPHER_R_BUFFER_TOO_SMALL);
296 return 0;
297 }
298
299 memcpy(&md, &rc4_ctx->head, sizeof(MD5_CTX));
300 /* The MAC's payload begins with the additional data. See
301 * https://tools.ietf.org/html/rfc5246#section-6.2.3.1 */
302 MD5_Update(&md, ad, ad_len);
303
304#if defined(STITCHED_CALL)
305 rc4_off = 32 - 1 - (rc4_ctx->rc4.x & (32 - 1));
306 md5_off = MD5_CBLOCK - md.num;
307 /* Ensure MD5 is a full block behind RC4 so it has plaintext to operate on in
308 * both normal and stitched routines. */
309 if (md5_off > rc4_off) {
310 rc4_off += 2 * MD5_CBLOCK;
311 } else {
312 rc4_off += MD5_CBLOCK;
313 }
314
315 if (in_len > rc4_off && (blocks = (in_len - rc4_off) / MD5_CBLOCK) &&
316 (OPENSSL_ia32cap_P[0] & (1 << 20)) == 0) {
317 /* Decrypt the initial portion of the ciphertext and digest the plaintext
318 * normally. */
319 RC4(&rc4_ctx->rc4, rc4_off, in, out);
320 MD5_Update(&md, out, md5_off);
321
322 /* Decrypt and digest the next |blocks| blocks of ciphertext with the
323 * stitched routines. */
324 rc4_md5_enc(&rc4_ctx->rc4, in + rc4_off, out + rc4_off, &md, out + md5_off,
325 blocks);
326 blocks *= MD5_CBLOCK;
327 rc4_off += blocks;
328 md5_off += blocks;
329 l = (md.Nl + (blocks << 3)) & 0xffffffffU;
330 if (l < md.Nl) {
331 md.Nh++;
332 }
333 md.Nl = l;
334 md.Nh += blocks >> 29;
335 } else {
336 md5_off = 0;
337 rc4_off = 0;
338 }
339#endif
340
341 /* Process the remainder of the input. */
342 RC4(&rc4_ctx->rc4, in_len - rc4_off, in + rc4_off, out + rc4_off);
343 MD5_Update(&md, out + md5_off, plaintext_len - md5_off);
344 MD5_Final(digest, &md);
345
346 /* Calculate HMAC and verify it */
347 memcpy(&md, &rc4_ctx->tail, sizeof(MD5_CTX));
348 MD5_Update(&md, digest, MD5_DIGEST_LENGTH);
349 MD5_Final(digest, &md);
350
351 if (CRYPTO_memcmp(out + plaintext_len, digest, rc4_ctx->tag_len)) {
352 OPENSSL_PUT_ERROR(CIPHER, aead_rc4_md5_tls_open, CIPHER_R_BAD_DECRYPT);
353 return 0;
354 }
355
356 *out_len = plaintext_len;
357 return 1;
358}
359
360static const EVP_AEAD aead_rc4_md5_tls = {
361 16 + MD5_DIGEST_LENGTH, /* key len (RC4 + MD5) */
362 0, /* nonce len */
363 MD5_DIGEST_LENGTH, /* overhead */
364 MD5_DIGEST_LENGTH, /* max tag length */
365 aead_rc4_md5_tls_init, aead_rc4_md5_tls_cleanup,
366 aead_rc4_md5_tls_seal, aead_rc4_md5_tls_open,
367};
368
369const EVP_AEAD *EVP_aead_rc4_md5_tls() { return &aead_rc4_md5_tls; }