Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / third_party / boringssl / src / crypto / cipher / e_rc4.c
1 /* 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
57 #include <openssl/aead.h>
58
59 #include <assert.h>
60
61 #include <openssl/cipher.h>
62 #include <openssl/err.h>
63 #include <openssl/md5.h>
64 #include <openssl/mem.h>
65 #include <openssl/obj.h>
66 #include <openssl/rc4.h>
67
68 #include "internal.h"
69
70
71 static 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
79 static 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
87 static 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
93 const EVP_CIPHER *EVP_rc4(void) { return &rc4; }
94
95
96 struct 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
104 static int
105 aead_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
156 static 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 */
166 void rc4_md5_enc(RC4_KEY *key, const void *in0, void *out, MD5_CTX *ctx,
167                  const void *inp, size_t blocks);
168 #endif
169
170 static 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
264 static 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
360 static 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
369 const EVP_AEAD *EVP_aead_rc4_md5_tls(void) { return &aead_rc4_md5_tls; }