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/crypto.h>
58 # include <openssl/evp.h>
59 # include <openssl/objects.h>
60 # include <openssl/rc4.h>
61 # include <openssl/md5.h>
62 # include "internal/evp_int.h"
64 # ifndef EVP_CIPH_FLAG_AEAD_CIPHER
65 # define EVP_CIPH_FLAG_AEAD_CIPHER 0x200000
66 # define EVP_CTRL_AEAD_TLS1_AAD 0x16
67 # define EVP_CTRL_AEAD_SET_MAC_KEY 0x17
70 /* FIXME: surely this is available elsewhere? */
71 # define EVP_RC4_KEY_SIZE 16
75 MD5_CTX head
, tail
, md
;
76 size_t payload_length
;
79 # define NO_PAYLOAD_LENGTH ((size_t)-1)
81 void rc4_md5_enc(RC4_KEY
*key
, const void *in0
, void *out
,
82 MD5_CTX
*ctx
, const void *inp
, size_t blocks
);
84 # define data(ctx) ((EVP_RC4_HMAC_MD5 *)EVP_CIPHER_CTX_get_cipher_data(ctx))
86 static int rc4_hmac_md5_init_key(EVP_CIPHER_CTX
*ctx
,
87 const unsigned char *inkey
,
88 const unsigned char *iv
, int enc
)
90 EVP_RC4_HMAC_MD5
*key
= data(ctx
);
92 RC4_set_key(&key
->ks
, EVP_CIPHER_CTX_key_length(ctx
), inkey
);
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 # define STITCHED_CALL
109 # if !defined(STITCHED_CALL)
114 static int rc4_hmac_md5_cipher(EVP_CIPHER_CTX
*ctx
, unsigned char *out
,
115 const unsigned char *in
, size_t len
)
117 EVP_RC4_HMAC_MD5
*key
= data(ctx
);
118 # if defined(STITCHED_CALL)
119 size_t rc4_off
= 32 - 1 - (key
->ks
.x
& (32 - 1)), /* 32 is $MOD from
120 * rc4_md5-x86_64.pl */
121 md5_off
= MD5_CBLOCK
- key
->md
.num
, blocks
;
123 extern unsigned int OPENSSL_ia32cap_P
[];
125 size_t plen
= key
->payload_length
;
127 if (plen
!= NO_PAYLOAD_LENGTH
&& len
!= (plen
+ MD5_DIGEST_LENGTH
))
130 if (EVP_CIPHER_CTX_encrypting(ctx
)) {
131 if (plen
== NO_PAYLOAD_LENGTH
)
133 # if defined(STITCHED_CALL)
134 /* cipher has to "fall behind" */
135 if (rc4_off
> md5_off
)
136 md5_off
+= MD5_CBLOCK
;
138 if (plen
> md5_off
&& (blocks
= (plen
- md5_off
) / MD5_CBLOCK
) &&
139 (OPENSSL_ia32cap_P
[0] & (1 << 20)) == 0) {
140 MD5_Update(&key
->md
, in
, md5_off
);
141 RC4(&key
->ks
, rc4_off
, in
, out
);
143 rc4_md5_enc(&key
->ks
, in
+ rc4_off
, out
+ rc4_off
,
144 &key
->md
, in
+ md5_off
, blocks
);
145 blocks
*= MD5_CBLOCK
;
148 key
->md
.Nh
+= blocks
>> 29;
149 key
->md
.Nl
+= blocks
<<= 3;
150 if (key
->md
.Nl
< (unsigned int)blocks
)
157 MD5_Update(&key
->md
, in
+ md5_off
, plen
- md5_off
);
159 if (plen
!= len
) { /* "TLS" mode of operation */
161 memcpy(out
+ rc4_off
, in
+ rc4_off
, plen
- rc4_off
);
163 /* calculate HMAC and append it to payload */
164 MD5_Final(out
+ plen
, &key
->md
);
166 MD5_Update(&key
->md
, out
+ plen
, MD5_DIGEST_LENGTH
);
167 MD5_Final(out
+ plen
, &key
->md
);
168 /* encrypt HMAC at once */
169 RC4(&key
->ks
, len
- rc4_off
, out
+ rc4_off
, out
+ rc4_off
);
171 RC4(&key
->ks
, len
- rc4_off
, in
+ rc4_off
, out
+ rc4_off
);
174 unsigned char mac
[MD5_DIGEST_LENGTH
];
175 # if defined(STITCHED_CALL)
176 /* digest has to "fall behind" */
177 if (md5_off
> rc4_off
)
178 rc4_off
+= 2 * MD5_CBLOCK
;
180 rc4_off
+= MD5_CBLOCK
;
182 if (len
> rc4_off
&& (blocks
= (len
- rc4_off
) / MD5_CBLOCK
) &&
183 (OPENSSL_ia32cap_P
[0] & (1 << 20)) == 0) {
184 RC4(&key
->ks
, rc4_off
, in
, out
);
185 MD5_Update(&key
->md
, out
, md5_off
);
187 rc4_md5_enc(&key
->ks
, in
+ rc4_off
, out
+ rc4_off
,
188 &key
->md
, out
+ md5_off
, blocks
);
189 blocks
*= MD5_CBLOCK
;
192 l
= (key
->md
.Nl
+ (blocks
<< 3)) & 0xffffffffU
;
196 key
->md
.Nh
+= blocks
>> 29;
202 /* decrypt HMAC at once */
203 RC4(&key
->ks
, len
- rc4_off
, in
+ rc4_off
, out
+ rc4_off
);
204 if (plen
!= NO_PAYLOAD_LENGTH
) { /* "TLS" mode of operation */
205 MD5_Update(&key
->md
, out
+ md5_off
, plen
- md5_off
);
207 /* calculate HMAC and verify it */
208 MD5_Final(mac
, &key
->md
);
210 MD5_Update(&key
->md
, mac
, MD5_DIGEST_LENGTH
);
211 MD5_Final(mac
, &key
->md
);
213 if (CRYPTO_memcmp(out
+ plen
, mac
, MD5_DIGEST_LENGTH
))
216 MD5_Update(&key
->md
, out
+ md5_off
, len
- md5_off
);
220 key
->payload_length
= NO_PAYLOAD_LENGTH
;
225 static int rc4_hmac_md5_ctrl(EVP_CIPHER_CTX
*ctx
, int type
, int arg
,
228 EVP_RC4_HMAC_MD5
*key
= data(ctx
);
231 case EVP_CTRL_AEAD_SET_MAC_KEY
:
234 unsigned char hmac_key
[64];
236 memset(hmac_key
, 0, sizeof(hmac_key
));
238 if (arg
> (int)sizeof(hmac_key
)) {
239 MD5_Init(&key
->head
);
240 MD5_Update(&key
->head
, ptr
, arg
);
241 MD5_Final(hmac_key
, &key
->head
);
243 memcpy(hmac_key
, ptr
, arg
);
246 for (i
= 0; i
< sizeof(hmac_key
); i
++)
247 hmac_key
[i
] ^= 0x36; /* ipad */
248 MD5_Init(&key
->head
);
249 MD5_Update(&key
->head
, hmac_key
, sizeof(hmac_key
));
251 for (i
= 0; i
< sizeof(hmac_key
); i
++)
252 hmac_key
[i
] ^= 0x36 ^ 0x5c; /* opad */
253 MD5_Init(&key
->tail
);
254 MD5_Update(&key
->tail
, hmac_key
, sizeof(hmac_key
));
258 case EVP_CTRL_AEAD_TLS1_AAD
:
260 unsigned char *p
= ptr
;
263 if (arg
!= EVP_AEAD_TLS1_AAD_LEN
)
266 len
= p
[arg
- 2] << 8 | p
[arg
- 1];
268 if (!EVP_CIPHER_CTX_encrypting(ctx
)) {
269 len
-= MD5_DIGEST_LENGTH
;
270 p
[arg
- 2] = len
>> 8;
273 key
->payload_length
= len
;
275 MD5_Update(&key
->md
, p
, arg
);
277 return MD5_DIGEST_LENGTH
;
284 static EVP_CIPHER r4_hmac_md5_cipher
= {
285 # ifdef NID_rc4_hmac_md5
290 1, EVP_RC4_KEY_SIZE
, 0,
291 EVP_CIPH_STREAM_CIPHER
| EVP_CIPH_VARIABLE_LENGTH
|
292 EVP_CIPH_FLAG_AEAD_CIPHER
,
293 rc4_hmac_md5_init_key
,
296 sizeof(EVP_RC4_HMAC_MD5
),
303 const EVP_CIPHER
*EVP_rc4_hmac_md5(void)
305 return (&r4_hmac_md5_cipher
);