12c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org/* ====================================================================
22c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org * Copyright (c) 2011 The OpenSSL Project.  All rights reserved.
32c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org *
42c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org * Redistribution and use in source and binary forms, with or without
52c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org * modification, are permitted provided that the following conditions
62c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org * are met:
72c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org *
82c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org * 1. Redistributions of source code must retain the above copyright
92c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org *    notice, this list of conditions and the following disclaimer.
102c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org *
112c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org * 2. Redistributions in binary form must reproduce the above copyright
122c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org *    notice, this list of conditions and the following disclaimer in
132c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org *    the documentation and/or other materials provided with the
142c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org *    distribution.
152c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org *
162c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org * 3. All advertising materials mentioning features or use of this
172c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org *    software must display the following acknowledgment:
182c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org *    "This product includes software developed by the OpenSSL Project
192c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
202c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org *
212c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
222c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org *    endorse or promote products derived from this software without
232c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org *    prior written permission. For written permission, please contact
242c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org *    licensing@OpenSSL.org.
252c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org *
262c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org * 5. Products derived from this software may not be called "OpenSSL"
272c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org *    nor may "OpenSSL" appear in their names without prior written
282c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org *    permission of the OpenSSL Project.
292c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org *
302c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org * 6. Redistributions of any form whatsoever must retain the following
312c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org *    acknowledgment:
322c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org *    "This product includes software developed by the OpenSSL Project
332c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
342c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org *
352c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
362c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
372c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
382c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
392c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
402c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
412c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
422c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
432c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
442c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
452c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
462c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org * OF THE POSSIBILITY OF SUCH DAMAGE.
472c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org * ====================================================================
482c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org */
492c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
502c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org#include <openssl/opensslconf.h>
512c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
522c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org#include <stdio.h>
532c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org#include <string.h>
542c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
552c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org#if !defined(OPENSSL_NO_RC4) && !defined(OPENSSL_NO_MD5)
562c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
572c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org#include <openssl/evp.h>
582c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org#include <openssl/objects.h>
592c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org#include <openssl/rc4.h>
602c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org#include <openssl/md5.h>
612c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
622c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org#ifndef EVP_CIPH_FLAG_AEAD_CIPHER
632c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org#define EVP_CIPH_FLAG_AEAD_CIPHER	0x200000
642c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org#define EVP_CTRL_AEAD_TLS1_AAD		0x16
652c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org#define EVP_CTRL_AEAD_SET_MAC_KEY	0x17
662c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org#endif
672c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
682c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org/* FIXME: surely this is available elsewhere? */
692c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org#define EVP_RC4_KEY_SIZE		16
702c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
712c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.orgtypedef struct
722c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org    {
732c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org    RC4_KEY		ks;
742c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org    MD5_CTX		head,tail,md;
752c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org    size_t		payload_length;
762c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org    } EVP_RC4_HMAC_MD5;
772c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
782c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org#define NO_PAYLOAD_LENGTH	((size_t)-1)
792c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
802c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.orgvoid rc4_md5_enc (RC4_KEY *key, const void *in0, void *out,
812c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		MD5_CTX *ctx,const void *inp,size_t blocks);
822c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
832c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org#define data(ctx) ((EVP_RC4_HMAC_MD5 *)(ctx)->cipher_data)
842c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
852c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.orgstatic int rc4_hmac_md5_init_key(EVP_CIPHER_CTX *ctx,
862c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org			const unsigned char *inkey,
872c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org			const unsigned char *iv, int enc)
882c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	{
892c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	EVP_RC4_HMAC_MD5 *key = data(ctx);
902c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
912c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	RC4_set_key(&key->ks,EVP_CIPHER_CTX_key_length(ctx),
922c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		    inkey);
932c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
942c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	MD5_Init(&key->head);	/* handy when benchmarking */
952c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	key->tail = key->head;
962c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	key->md   = key->head;
972c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
982c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	key->payload_length = NO_PAYLOAD_LENGTH;
992c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
1002c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	return 1;
1012c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	}
1022c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
1032c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org#if	!defined(OPENSSL_NO_ASM) &&	( \
1042c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	defined(__x86_64)	|| defined(__x86_64__)	|| \
1052c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	defined(_M_AMD64)	|| defined(_M_X64)	|| \
1062c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	defined(__INTEL__)		) && \
1072c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	!(defined(__APPLE__) && defined(__MACH__))
1082c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org#define	STITCHED_CALL
1092c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org#endif
1102c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
1112c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org#if !defined(STITCHED_CALL)
1122c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org#define	rc4_off 0
1132c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org#define	md5_off 0
1142c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org#endif
1152c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
1162c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.orgstatic int rc4_hmac_md5_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
1172c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		      const unsigned char *in, size_t len)
1182c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	{
1192c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	EVP_RC4_HMAC_MD5 *key = data(ctx);
1202c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org#if defined(STITCHED_CALL)
1212c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	size_t	rc4_off = 32-1-(key->ks.x&(32-1)),	/* 32 is $MOD from rc4_md5-x86_64.pl */
1222c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		md5_off = MD5_CBLOCK-key->md.num,
1232c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		blocks;
1242c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	unsigned int l;
1252c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	extern unsigned int OPENSSL_ia32cap_P[];
1262c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org#endif
1272c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	size_t	plen = key->payload_length;
1282c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
1292c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	if (plen!=NO_PAYLOAD_LENGTH && len!=(plen+MD5_DIGEST_LENGTH)) return 0;
1302c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
1312c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	if (ctx->encrypt) {
1322c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		if (plen==NO_PAYLOAD_LENGTH) plen = len;
1332c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org#if defined(STITCHED_CALL)
1342c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		/* cipher has to "fall behind" */
1352c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		if (rc4_off>md5_off) md5_off+=MD5_CBLOCK;
1362c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
1372c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		if (plen>md5_off && (blocks=(plen-md5_off)/MD5_CBLOCK) &&
1382c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		    (OPENSSL_ia32cap_P[0]&(1<<20))==0) {
1392c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org			MD5_Update(&key->md,in,md5_off);
1402c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org			RC4(&key->ks,rc4_off,in,out);
1412c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
1422c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org			rc4_md5_enc(&key->ks,in+rc4_off,out+rc4_off,
1432c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org				&key->md,in+md5_off,blocks);
1442c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org			blocks *= MD5_CBLOCK;
1452c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org			rc4_off += blocks;
1462c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org			md5_off += blocks;
1472c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org			key->md.Nh += blocks>>29;
1482c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org			key->md.Nl += blocks<<=3;
1492c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org			if (key->md.Nl<(unsigned int)blocks) key->md.Nh++;
1502c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		} else {
1512c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org			rc4_off = 0;
1522c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org			md5_off = 0;
1532c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		}
1542c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org#endif
1552c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		MD5_Update(&key->md,in+md5_off,plen-md5_off);
1562c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
1572c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		if (plen!=len) {	/* "TLS" mode of operation */
1582c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org			if (in!=out)
1592c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org				memcpy(out+rc4_off,in+rc4_off,plen-rc4_off);
1602c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
1612c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org			/* calculate HMAC and append it to payload */
1622c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org			MD5_Final(out+plen,&key->md);
1632c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org			key->md = key->tail;
1642c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org			MD5_Update(&key->md,out+plen,MD5_DIGEST_LENGTH);
1652c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org			MD5_Final(out+plen,&key->md);
1662c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org			/* encrypt HMAC at once */
1672c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org			RC4(&key->ks,len-rc4_off,out+rc4_off,out+rc4_off);
1682c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		} else {
1692c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org			RC4(&key->ks,len-rc4_off,in+rc4_off,out+rc4_off);
1702c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		}
1712c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	} else {
1722c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		unsigned char mac[MD5_DIGEST_LENGTH];
1732c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org#if defined(STITCHED_CALL)
1742c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		/* digest has to "fall behind" */
1752c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		if (md5_off>rc4_off)	rc4_off += 2*MD5_CBLOCK;
1762c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		else			rc4_off += MD5_CBLOCK;
1772c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
1782c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		if (len>rc4_off && (blocks=(len-rc4_off)/MD5_CBLOCK) &&
1792c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		    (OPENSSL_ia32cap_P[0]&(1<<20))==0) {
1802c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org			RC4(&key->ks,rc4_off,in,out);
1812c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org			MD5_Update(&key->md,out,md5_off);
1822c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
1832c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org			rc4_md5_enc(&key->ks,in+rc4_off,out+rc4_off,
1842c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org				&key->md,out+md5_off,blocks);
1852c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org			blocks *= MD5_CBLOCK;
1862c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org			rc4_off += blocks;
1872c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org			md5_off += blocks;
1882c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org			l = (key->md.Nl+(blocks<<3))&0xffffffffU;
1892c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org			if (l<key->md.Nl) key->md.Nh++;
1902c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org			key->md.Nl  = l;
1912c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org			key->md.Nh += blocks>>29;
1922c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		} else {
1932c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org			md5_off=0;
1942c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org			rc4_off=0;
1952c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		}
1962c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org#endif
1972c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		/* decrypt HMAC at once */
1982c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		RC4(&key->ks,len-rc4_off,in+rc4_off,out+rc4_off);
1992c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		if (plen!=NO_PAYLOAD_LENGTH) {	/* "TLS" mode of operation */
2002c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org			MD5_Update(&key->md,out+md5_off,plen-md5_off);
2012c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
2022c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org			/* calculate HMAC and verify it */
2032c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org			MD5_Final(mac,&key->md);
2042c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org			key->md = key->tail;
2052c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org			MD5_Update(&key->md,mac,MD5_DIGEST_LENGTH);
2062c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org			MD5_Final(mac,&key->md);
2072c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
2082c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org			if (memcmp(out+plen,mac,MD5_DIGEST_LENGTH))
2092c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org				return 0;
2102c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		} else {
2112c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org			MD5_Update(&key->md,out+md5_off,len-md5_off);
2122c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		}
2132c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	}
2142c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
2152c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	key->payload_length = NO_PAYLOAD_LENGTH;
2162c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
2172c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	return 1;
2182c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	}
2192c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
2202c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.orgstatic int rc4_hmac_md5_ctrl(EVP_CIPHER_CTX *ctx, int type, int arg, void *ptr)
2212c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	{
2222c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	EVP_RC4_HMAC_MD5 *key = data(ctx);
2232c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
2242c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	switch (type)
2252c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		{
2262c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	case EVP_CTRL_AEAD_SET_MAC_KEY:
2272c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		{
2282c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		unsigned int  i;
2292c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		unsigned char hmac_key[64];
2302c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
2312c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		memset (hmac_key,0,sizeof(hmac_key));
2322c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
2332c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		if (arg > (int)sizeof(hmac_key)) {
2342c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org			MD5_Init(&key->head);
2352c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org			MD5_Update(&key->head,ptr,arg);
2362c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org			MD5_Final(hmac_key,&key->head);
2372c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		} else {
2382c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org			memcpy(hmac_key,ptr,arg);
2392c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		}
2402c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
2412c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		for (i=0;i<sizeof(hmac_key);i++)
2422c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org			hmac_key[i] ^= 0x36;		/* ipad */
2432c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		MD5_Init(&key->head);
2442c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		MD5_Update(&key->head,hmac_key,sizeof(hmac_key));
2452c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
2462c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		for (i=0;i<sizeof(hmac_key);i++)
2472c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org			hmac_key[i] ^= 0x36^0x5c;	/* opad */
2482c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		MD5_Init(&key->tail);
2492c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		MD5_Update(&key->tail,hmac_key,sizeof(hmac_key));
2502c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
2512c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		return 1;
2522c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		}
2532c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	case EVP_CTRL_AEAD_TLS1_AAD:
2542c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		{
2552c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		unsigned char *p=ptr;
2562c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		unsigned int   len=p[arg-2]<<8|p[arg-1];
2572c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
2582c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		if (!ctx->encrypt)
2592c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org			{
2602c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org			len -= MD5_DIGEST_LENGTH;
2612c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org			p[arg-2] = len>>8;
2622c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org			p[arg-1] = len;
2632c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org			}
2642c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		key->payload_length=len;
2652c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		key->md = key->head;
2662c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		MD5_Update(&key->md,p,arg);
2672c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
2682c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		return MD5_DIGEST_LENGTH;
2692c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		}
2702c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	default:
2712c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		return -1;
2722c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		}
2732c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	}
2742c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
2752c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.orgstatic EVP_CIPHER r4_hmac_md5_cipher=
2762c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	{
2772c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org#ifdef NID_rc4_hmac_md5
2782c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	NID_rc4_hmac_md5,
2792c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org#else
2802c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	NID_undef,
2812c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org#endif
2822c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	1,EVP_RC4_KEY_SIZE,0,
2832c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	EVP_CIPH_STREAM_CIPHER|EVP_CIPH_VARIABLE_LENGTH|EVP_CIPH_FLAG_AEAD_CIPHER,
2842c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	rc4_hmac_md5_init_key,
2852c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	rc4_hmac_md5_cipher,
2862c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	NULL,
2872c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	sizeof(EVP_RC4_HMAC_MD5),
2882c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	NULL,
2892c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	NULL,
2902c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	rc4_hmac_md5_ctrl,
2912c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	NULL
2922c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	};
2932c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
2942c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.orgconst EVP_CIPHER *EVP_rc4_hmac_md5(void)
2952c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	{
2962c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	return(&r4_hmac_md5_cipher);
2972c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	}
2982c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org#endif
299