1 /* ====================================================================
2 * Copyright (c) 2011 The OpenSSL Project. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in
13 * the documentation and/or other materials provided with the
16 * 3. All advertising materials mentioning features or use of this
17 * software must display the following acknowledgment:
18 * "This product includes software developed by the OpenSSL Project
19 * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
21 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
22 * endorse or promote products derived from this software without
23 * prior written permission. For written permission, please contact
24 * licensing@OpenSSL.org.
26 * 5. Products derived from this software may not be called "OpenSSL"
27 * nor may "OpenSSL" appear in their names without prior written
28 * permission of the OpenSSL Project.
30 * 6. Redistributions of any form whatsoever must retain the following
32 * "This product includes software developed by the OpenSSL Project
33 * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
35 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
36 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
37 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
38 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
39 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
41 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
42 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
43 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
44 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
45 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
46 * OF THE POSSIBILITY OF SUCH DAMAGE.
47 * ====================================================================
50 #include <openssl/opensslconf.h>
55 #if !defined(OPENSSL_NO_RC4) && !defined(OPENSSL_NO_MD5)
57 #include <openssl/evp.h>
58 #include <openssl/objects.h>
59 #include <openssl/rc4.h>
60 #include <openssl/md5.h>
62 #ifndef EVP_CIPH_FLAG_AEAD_CIPHER
63 #define EVP_CIPH_FLAG_AEAD_CIPHER 0x200000
64 #define EVP_CTRL_AEAD_TLS1_AAD 0x16
65 #define EVP_CTRL_AEAD_SET_MAC_KEY 0x17
68 /* FIXME: surely this is available elsewhere? */
69 #define EVP_RC4_KEY_SIZE 16
75 size_t payload_length
;
78 #define NO_PAYLOAD_LENGTH ((size_t)-1)
80 void rc4_md5_enc (RC4_KEY
*key
, const void *in0
, void *out
,
81 MD5_CTX
*ctx
,const void *inp
,size_t blocks
);
83 #define data(ctx) ((EVP_RC4_HMAC_MD5 *)(ctx)->cipher_data)
85 static int rc4_hmac_md5_init_key(EVP_CIPHER_CTX
*ctx
,
86 const unsigned char *inkey
,
87 const unsigned char *iv
, int enc
)
89 EVP_RC4_HMAC_MD5
*key
= data(ctx
);
91 RC4_set_key(&key
->ks
,EVP_CIPHER_CTX_key_length(ctx
),
94 MD5_Init(&key
->head
); /* handy when benchmarking */
95 key
->tail
= key
->head
;
98 key
->payload_length
= NO_PAYLOAD_LENGTH
;
103 #if !defined(OPENSSL_NO_ASM) && ( \
104 defined(__x86_64) || defined(__x86_64__) || \
105 defined(_M_AMD64) || defined(_M_X64) || \
106 defined(__INTEL__) ) && \
107 !(defined(__APPLE__) && defined(__MACH__))
108 #define STITCHED_CALL
111 #if !defined(STITCHED_CALL)
116 static int rc4_hmac_md5_cipher(EVP_CIPHER_CTX
*ctx
, unsigned char *out
,
117 const unsigned char *in
, size_t len
)
119 EVP_RC4_HMAC_MD5
*key
= data(ctx
);
120 #if defined(STITCHED_CALL)
121 size_t rc4_off
= 32-1-(key
->ks
.x
&(32-1)), /* 32 is $MOD from rc4_md5-x86_64.pl */
122 md5_off
= MD5_CBLOCK
-key
->md
.num
,
125 extern unsigned int OPENSSL_ia32cap_P
[];
127 size_t plen
= key
->payload_length
;
129 if (plen
!=NO_PAYLOAD_LENGTH
&& len
!=(plen
+MD5_DIGEST_LENGTH
)) return 0;
132 if (plen
==NO_PAYLOAD_LENGTH
) plen
= len
;
133 #if defined(STITCHED_CALL)
134 /* cipher has to "fall behind" */
135 if (rc4_off
>md5_off
) md5_off
+=MD5_CBLOCK
;
137 if (plen
>md5_off
&& (blocks
=(plen
-md5_off
)/MD5_CBLOCK
) &&
138 (OPENSSL_ia32cap_P
[0]&(1<<20))==0) {
139 MD5_Update(&key
->md
,in
,md5_off
);
140 RC4(&key
->ks
,rc4_off
,in
,out
);
142 rc4_md5_enc(&key
->ks
,in
+rc4_off
,out
+rc4_off
,
143 &key
->md
,in
+md5_off
,blocks
);
144 blocks
*= MD5_CBLOCK
;
147 key
->md
.Nh
+= blocks
>>29;
148 key
->md
.Nl
+= blocks
<<=3;
149 if (key
->md
.Nl
<(unsigned int)blocks
) key
->md
.Nh
++;
155 MD5_Update(&key
->md
,in
+md5_off
,plen
-md5_off
);
157 if (plen
!=len
) { /* "TLS" mode of operation */
159 memcpy(out
+rc4_off
,in
+rc4_off
,plen
-rc4_off
);
161 /* calculate HMAC and append it to payload */
162 MD5_Final(out
+plen
,&key
->md
);
164 MD5_Update(&key
->md
,out
+plen
,MD5_DIGEST_LENGTH
);
165 MD5_Final(out
+plen
,&key
->md
);
166 /* encrypt HMAC at once */
167 RC4(&key
->ks
,len
-rc4_off
,out
+rc4_off
,out
+rc4_off
);
169 RC4(&key
->ks
,len
-rc4_off
,in
+rc4_off
,out
+rc4_off
);
172 unsigned char mac
[MD5_DIGEST_LENGTH
];
173 #if defined(STITCHED_CALL)
174 /* digest has to "fall behind" */
175 if (md5_off
>rc4_off
) rc4_off
+= 2*MD5_CBLOCK
;
176 else rc4_off
+= MD5_CBLOCK
;
178 if (len
>rc4_off
&& (blocks
=(len
-rc4_off
)/MD5_CBLOCK
) &&
179 (OPENSSL_ia32cap_P
[0]&(1<<20))==0) {
180 RC4(&key
->ks
,rc4_off
,in
,out
);
181 MD5_Update(&key
->md
,out
,md5_off
);
183 rc4_md5_enc(&key
->ks
,in
+rc4_off
,out
+rc4_off
,
184 &key
->md
,out
+md5_off
,blocks
);
185 blocks
*= MD5_CBLOCK
;
188 l
= (key
->md
.Nl
+(blocks
<<3))&0xffffffffU
;
189 if (l
<key
->md
.Nl
) key
->md
.Nh
++;
191 key
->md
.Nh
+= blocks
>>29;
197 /* decrypt HMAC at once */
198 RC4(&key
->ks
,len
-rc4_off
,in
+rc4_off
,out
+rc4_off
);
199 if (plen
!=NO_PAYLOAD_LENGTH
) { /* "TLS" mode of operation */
200 MD5_Update(&key
->md
,out
+md5_off
,plen
-md5_off
);
202 /* calculate HMAC and verify it */
203 MD5_Final(mac
,&key
->md
);
205 MD5_Update(&key
->md
,mac
,MD5_DIGEST_LENGTH
);
206 MD5_Final(mac
,&key
->md
);
208 if (memcmp(out
+plen
,mac
,MD5_DIGEST_LENGTH
))
211 MD5_Update(&key
->md
,out
+md5_off
,len
-md5_off
);
215 key
->payload_length
= NO_PAYLOAD_LENGTH
;
220 static int rc4_hmac_md5_ctrl(EVP_CIPHER_CTX
*ctx
, int type
, int arg
, void *ptr
)
222 EVP_RC4_HMAC_MD5
*key
= data(ctx
);
226 case EVP_CTRL_AEAD_SET_MAC_KEY
:
229 unsigned char hmac_key
[64];
231 memset (hmac_key
,0,sizeof(hmac_key
));
233 if (arg
> (int)sizeof(hmac_key
)) {
234 MD5_Init(&key
->head
);
235 MD5_Update(&key
->head
,ptr
,arg
);
236 MD5_Final(hmac_key
,&key
->head
);
238 memcpy(hmac_key
,ptr
,arg
);
241 for (i
=0;i
<sizeof(hmac_key
);i
++)
242 hmac_key
[i
] ^= 0x36; /* ipad */
243 MD5_Init(&key
->head
);
244 MD5_Update(&key
->head
,hmac_key
,sizeof(hmac_key
));
246 for (i
=0;i
<sizeof(hmac_key
);i
++)
247 hmac_key
[i
] ^= 0x36^0x5c; /* opad */
248 MD5_Init(&key
->tail
);
249 MD5_Update(&key
->tail
,hmac_key
,sizeof(hmac_key
));
253 case EVP_CTRL_AEAD_TLS1_AAD
:
255 unsigned char *p
=ptr
;
256 unsigned int len
=p
[arg
-2]<<8|p
[arg
-1];
260 len
-= MD5_DIGEST_LENGTH
;
264 key
->payload_length
=len
;
266 MD5_Update(&key
->md
,p
,arg
);
268 return MD5_DIGEST_LENGTH
;
275 static EVP_CIPHER r4_hmac_md5_cipher
=
277 #ifdef NID_rc4_hmac_md5
282 1,EVP_RC4_KEY_SIZE
,0,
283 EVP_CIPH_STREAM_CIPHER
|EVP_CIPH_VARIABLE_LENGTH
|EVP_CIPH_FLAG_AEAD_CIPHER
,
284 rc4_hmac_md5_init_key
,
287 sizeof(EVP_RC4_HMAC_MD5
),
294 const EVP_CIPHER
*EVP_rc4_hmac_md5(void)
296 return(&r4_hmac_md5_cipher
);