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