2 * Copyright 2011-2016 The OpenSSL Project Authors. All Rights Reserved.
4 * Licensed under the OpenSSL license (the "License"). You may not use
5 * this file except in compliance with the License. You can obtain a copy
6 * in the file LICENSE in the source distribution or at
7 * https://www.openssl.org/source/license.html
10 #include <openssl/opensslconf.h>
15 #if !defined(OPENSSL_NO_RC4) && !defined(OPENSSL_NO_MD5)
17 # include <openssl/crypto.h>
18 # include <openssl/evp.h>
19 # include <openssl/objects.h>
20 # include <openssl/rc4.h>
21 # include <openssl/md5.h>
22 # include "internal/evp_int.h"
26 MD5_CTX head
, tail
, md
;
27 size_t payload_length
;
30 # define NO_PAYLOAD_LENGTH ((size_t)-1)
32 void rc4_md5_enc(RC4_KEY
*key
, const void *in0
, void *out
,
33 MD5_CTX
*ctx
, const void *inp
, size_t blocks
);
35 # define data(ctx) ((EVP_RC4_HMAC_MD5 *)EVP_CIPHER_CTX_get_cipher_data(ctx))
37 static int rc4_hmac_md5_init_key(EVP_CIPHER_CTX
*ctx
,
38 const unsigned char *inkey
,
39 const unsigned char *iv
, int enc
)
41 EVP_RC4_HMAC_MD5
*key
= data(ctx
);
43 RC4_set_key(&key
->ks
, EVP_CIPHER_CTX_key_length(ctx
), inkey
);
45 MD5_Init(&key
->head
); /* handy when benchmarking */
46 key
->tail
= key
->head
;
49 key
->payload_length
= NO_PAYLOAD_LENGTH
;
54 # if defined(RC4_ASM) && defined(MD5_ASM) && ( \
55 defined(__x86_64) || defined(__x86_64__) || \
56 defined(_M_AMD64) || defined(_M_X64) )
57 # define STITCHED_CALL
60 # if !defined(STITCHED_CALL)
65 static int rc4_hmac_md5_cipher(EVP_CIPHER_CTX
*ctx
, unsigned char *out
,
66 const unsigned char *in
, size_t len
)
68 EVP_RC4_HMAC_MD5
*key
= data(ctx
);
69 # if defined(STITCHED_CALL)
70 size_t rc4_off
= 32 - 1 - (key
->ks
.x
& (32 - 1)), /* 32 is $MOD from
71 * rc4_md5-x86_64.pl */
72 md5_off
= MD5_CBLOCK
- key
->md
.num
, blocks
;
74 extern unsigned int OPENSSL_ia32cap_P
[];
76 size_t plen
= key
->payload_length
;
78 if (plen
!= NO_PAYLOAD_LENGTH
&& len
!= (plen
+ MD5_DIGEST_LENGTH
))
81 if (EVP_CIPHER_CTX_encrypting(ctx
)) {
82 if (plen
== NO_PAYLOAD_LENGTH
)
84 # if defined(STITCHED_CALL)
85 /* cipher has to "fall behind" */
86 if (rc4_off
> md5_off
)
87 md5_off
+= MD5_CBLOCK
;
89 if (plen
> md5_off
&& (blocks
= (plen
- md5_off
) / MD5_CBLOCK
) &&
90 (OPENSSL_ia32cap_P
[0] & (1 << 20)) == 0) {
91 MD5_Update(&key
->md
, in
, md5_off
);
92 RC4(&key
->ks
, rc4_off
, in
, out
);
94 rc4_md5_enc(&key
->ks
, in
+ rc4_off
, out
+ rc4_off
,
95 &key
->md
, in
+ md5_off
, blocks
);
99 key
->md
.Nh
+= blocks
>> 29;
100 key
->md
.Nl
+= blocks
<<= 3;
101 if (key
->md
.Nl
< (unsigned int)blocks
)
108 MD5_Update(&key
->md
, in
+ md5_off
, plen
- md5_off
);
110 if (plen
!= len
) { /* "TLS" mode of operation */
112 memcpy(out
+ rc4_off
, in
+ rc4_off
, plen
- rc4_off
);
114 /* calculate HMAC and append it to payload */
115 MD5_Final(out
+ plen
, &key
->md
);
117 MD5_Update(&key
->md
, out
+ plen
, MD5_DIGEST_LENGTH
);
118 MD5_Final(out
+ plen
, &key
->md
);
119 /* encrypt HMAC at once */
120 RC4(&key
->ks
, len
- rc4_off
, out
+ rc4_off
, out
+ rc4_off
);
122 RC4(&key
->ks
, len
- rc4_off
, in
+ rc4_off
, out
+ rc4_off
);
125 unsigned char mac
[MD5_DIGEST_LENGTH
];
126 # if defined(STITCHED_CALL)
127 /* digest has to "fall behind" */
128 if (md5_off
> rc4_off
)
129 rc4_off
+= 2 * MD5_CBLOCK
;
131 rc4_off
+= MD5_CBLOCK
;
133 if (len
> rc4_off
&& (blocks
= (len
- rc4_off
) / MD5_CBLOCK
) &&
134 (OPENSSL_ia32cap_P
[0] & (1 << 20)) == 0) {
135 RC4(&key
->ks
, rc4_off
, in
, out
);
136 MD5_Update(&key
->md
, out
, md5_off
);
138 rc4_md5_enc(&key
->ks
, in
+ rc4_off
, out
+ rc4_off
,
139 &key
->md
, out
+ md5_off
, blocks
);
140 blocks
*= MD5_CBLOCK
;
143 l
= (key
->md
.Nl
+ (blocks
<< 3)) & 0xffffffffU
;
147 key
->md
.Nh
+= blocks
>> 29;
153 /* decrypt HMAC at once */
154 RC4(&key
->ks
, len
- rc4_off
, in
+ rc4_off
, out
+ rc4_off
);
155 if (plen
!= NO_PAYLOAD_LENGTH
) { /* "TLS" mode of operation */
156 MD5_Update(&key
->md
, out
+ md5_off
, plen
- md5_off
);
158 /* calculate HMAC and verify it */
159 MD5_Final(mac
, &key
->md
);
161 MD5_Update(&key
->md
, mac
, MD5_DIGEST_LENGTH
);
162 MD5_Final(mac
, &key
->md
);
164 if (CRYPTO_memcmp(out
+ plen
, mac
, MD5_DIGEST_LENGTH
))
167 MD5_Update(&key
->md
, out
+ md5_off
, len
- md5_off
);
171 key
->payload_length
= NO_PAYLOAD_LENGTH
;
176 static int rc4_hmac_md5_ctrl(EVP_CIPHER_CTX
*ctx
, int type
, int arg
,
179 EVP_RC4_HMAC_MD5
*key
= data(ctx
);
182 case EVP_CTRL_AEAD_SET_MAC_KEY
:
185 unsigned char hmac_key
[64];
187 memset(hmac_key
, 0, sizeof(hmac_key
));
189 if (arg
> (int)sizeof(hmac_key
)) {
190 MD5_Init(&key
->head
);
191 MD5_Update(&key
->head
, ptr
, arg
);
192 MD5_Final(hmac_key
, &key
->head
);
194 memcpy(hmac_key
, ptr
, arg
);
197 for (i
= 0; i
< sizeof(hmac_key
); i
++)
198 hmac_key
[i
] ^= 0x36; /* ipad */
199 MD5_Init(&key
->head
);
200 MD5_Update(&key
->head
, hmac_key
, sizeof(hmac_key
));
202 for (i
= 0; i
< sizeof(hmac_key
); i
++)
203 hmac_key
[i
] ^= 0x36 ^ 0x5c; /* opad */
204 MD5_Init(&key
->tail
);
205 MD5_Update(&key
->tail
, hmac_key
, sizeof(hmac_key
));
207 OPENSSL_cleanse(hmac_key
, sizeof(hmac_key
));
211 case EVP_CTRL_AEAD_TLS1_AAD
:
213 unsigned char *p
= ptr
;
216 if (arg
!= EVP_AEAD_TLS1_AAD_LEN
)
219 len
= p
[arg
- 2] << 8 | p
[arg
- 1];
221 if (!EVP_CIPHER_CTX_encrypting(ctx
)) {
222 if (len
< MD5_DIGEST_LENGTH
)
224 len
-= MD5_DIGEST_LENGTH
;
225 p
[arg
- 2] = len
>> 8;
228 key
->payload_length
= len
;
230 MD5_Update(&key
->md
, p
, arg
);
232 return MD5_DIGEST_LENGTH
;
239 static EVP_CIPHER r4_hmac_md5_cipher
= {
240 # ifdef NID_rc4_hmac_md5
245 1, EVP_RC4_KEY_SIZE
, 0,
246 EVP_CIPH_STREAM_CIPHER
| EVP_CIPH_VARIABLE_LENGTH
|
247 EVP_CIPH_FLAG_AEAD_CIPHER
,
248 rc4_hmac_md5_init_key
,
251 sizeof(EVP_RC4_HMAC_MD5
),
258 const EVP_CIPHER
*EVP_rc4_hmac_md5(void)
260 return &r4_hmac_md5_cipher
;