2 * Copyright 2011-2020 The OpenSSL Project Authors. All Rights Reserved.
4 * Licensed under the Apache License 2.0 (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
11 * MD5 and RC4 low level APIs are deprecated for public use, but still ok for
14 #include "internal/deprecated.h"
16 #include <internal/cryptlib.h>
17 #include <openssl/opensslconf.h>
22 #if !defined(OPENSSL_NO_RC4) && !defined(OPENSSL_NO_MD5)
24 # include <openssl/crypto.h>
25 # include <openssl/evp.h>
26 # include <openssl/objects.h>
27 # include <openssl/rc4.h>
28 # include <openssl/md5.h>
29 # include "crypto/evp.h"
33 MD5_CTX head
, tail
, md
;
34 size_t payload_length
;
37 # define NO_PAYLOAD_LENGTH ((size_t)-1)
39 void rc4_md5_enc(RC4_KEY
*key
, const void *in0
, void *out
,
40 MD5_CTX
*ctx
, const void *inp
, size_t blocks
);
42 # define data(ctx) ((EVP_RC4_HMAC_MD5 *)EVP_CIPHER_CTX_get_cipher_data(ctx))
44 static int rc4_hmac_md5_init_key(EVP_CIPHER_CTX
*ctx
,
45 const unsigned char *inkey
,
46 const unsigned char *iv
, int enc
)
48 EVP_RC4_HMAC_MD5
*key
= data(ctx
);
50 RC4_set_key(&key
->ks
, EVP_CIPHER_CTX_key_length(ctx
), inkey
);
52 MD5_Init(&key
->head
); /* handy when benchmarking */
53 key
->tail
= key
->head
;
56 key
->payload_length
= NO_PAYLOAD_LENGTH
;
61 # if defined(RC4_ASM) && defined(MD5_ASM) && ( \
62 defined(__x86_64) || defined(__x86_64__) || \
63 defined(_M_AMD64) || defined(_M_X64) )
64 # define STITCHED_CALL
67 # if !defined(STITCHED_CALL)
72 static int rc4_hmac_md5_cipher(EVP_CIPHER_CTX
*ctx
, unsigned char *out
,
73 const unsigned char *in
, size_t len
)
75 EVP_RC4_HMAC_MD5
*key
= data(ctx
);
76 # if defined(STITCHED_CALL)
77 size_t rc4_off
= 32 - 1 - (key
->ks
.x
& (32 - 1)), /* 32 is $MOD from
78 * rc4_md5-x86_64.pl */
79 md5_off
= MD5_CBLOCK
- key
->md
.num
, blocks
;
82 size_t plen
= key
->payload_length
;
84 if (plen
!= NO_PAYLOAD_LENGTH
&& len
!= (plen
+ MD5_DIGEST_LENGTH
))
87 if (EVP_CIPHER_CTX_encrypting(ctx
)) {
88 if (plen
== NO_PAYLOAD_LENGTH
)
90 # if defined(STITCHED_CALL)
91 /* cipher has to "fall behind" */
92 if (rc4_off
> md5_off
)
93 md5_off
+= MD5_CBLOCK
;
95 if (plen
> md5_off
&& (blocks
= (plen
- md5_off
) / MD5_CBLOCK
) &&
96 (OPENSSL_ia32cap_P
[0] & (1 << 20)) == 0) {
97 MD5_Update(&key
->md
, in
, md5_off
);
98 RC4(&key
->ks
, rc4_off
, in
, out
);
100 rc4_md5_enc(&key
->ks
, in
+ rc4_off
, out
+ rc4_off
,
101 &key
->md
, in
+ md5_off
, blocks
);
102 blocks
*= MD5_CBLOCK
;
105 key
->md
.Nh
+= blocks
>> 29;
106 key
->md
.Nl
+= blocks
<<= 3;
107 if (key
->md
.Nl
< (unsigned int)blocks
)
114 MD5_Update(&key
->md
, in
+ md5_off
, plen
- md5_off
);
116 if (plen
!= len
) { /* "TLS" mode of operation */
118 memcpy(out
+ rc4_off
, in
+ rc4_off
, plen
- rc4_off
);
120 /* calculate HMAC and append it to payload */
121 MD5_Final(out
+ plen
, &key
->md
);
123 MD5_Update(&key
->md
, out
+ plen
, MD5_DIGEST_LENGTH
);
124 MD5_Final(out
+ plen
, &key
->md
);
125 /* encrypt HMAC at once */
126 RC4(&key
->ks
, len
- rc4_off
, out
+ rc4_off
, out
+ rc4_off
);
128 RC4(&key
->ks
, len
- rc4_off
, in
+ rc4_off
, out
+ rc4_off
);
131 unsigned char mac
[MD5_DIGEST_LENGTH
];
132 # if defined(STITCHED_CALL)
133 /* digest has to "fall behind" */
134 if (md5_off
> rc4_off
)
135 rc4_off
+= 2 * MD5_CBLOCK
;
137 rc4_off
+= MD5_CBLOCK
;
139 if (len
> rc4_off
&& (blocks
= (len
- rc4_off
) / MD5_CBLOCK
) &&
140 (OPENSSL_ia32cap_P
[0] & (1 << 20)) == 0) {
141 RC4(&key
->ks
, rc4_off
, in
, out
);
142 MD5_Update(&key
->md
, out
, md5_off
);
144 rc4_md5_enc(&key
->ks
, in
+ rc4_off
, out
+ rc4_off
,
145 &key
->md
, out
+ md5_off
, blocks
);
146 blocks
*= MD5_CBLOCK
;
149 l
= (key
->md
.Nl
+ (blocks
<< 3)) & 0xffffffffU
;
153 key
->md
.Nh
+= blocks
>> 29;
159 /* decrypt HMAC at once */
160 RC4(&key
->ks
, len
- rc4_off
, in
+ rc4_off
, out
+ rc4_off
);
161 if (plen
!= NO_PAYLOAD_LENGTH
) { /* "TLS" mode of operation */
162 MD5_Update(&key
->md
, out
+ md5_off
, plen
- md5_off
);
164 /* calculate HMAC and verify it */
165 MD5_Final(mac
, &key
->md
);
167 MD5_Update(&key
->md
, mac
, MD5_DIGEST_LENGTH
);
168 MD5_Final(mac
, &key
->md
);
170 if (CRYPTO_memcmp(out
+ plen
, mac
, MD5_DIGEST_LENGTH
))
173 MD5_Update(&key
->md
, out
+ md5_off
, len
- md5_off
);
177 key
->payload_length
= NO_PAYLOAD_LENGTH
;
182 static int rc4_hmac_md5_ctrl(EVP_CIPHER_CTX
*ctx
, int type
, int arg
,
185 EVP_RC4_HMAC_MD5
*key
= data(ctx
);
188 case EVP_CTRL_AEAD_SET_MAC_KEY
:
191 unsigned char hmac_key
[64];
193 memset(hmac_key
, 0, sizeof(hmac_key
));
195 if (arg
> (int)sizeof(hmac_key
)) {
196 MD5_Init(&key
->head
);
197 MD5_Update(&key
->head
, ptr
, arg
);
198 MD5_Final(hmac_key
, &key
->head
);
200 memcpy(hmac_key
, ptr
, arg
);
203 for (i
= 0; i
< sizeof(hmac_key
); i
++)
204 hmac_key
[i
] ^= 0x36; /* ipad */
205 MD5_Init(&key
->head
);
206 MD5_Update(&key
->head
, hmac_key
, sizeof(hmac_key
));
208 for (i
= 0; i
< sizeof(hmac_key
); i
++)
209 hmac_key
[i
] ^= 0x36 ^ 0x5c; /* opad */
210 MD5_Init(&key
->tail
);
211 MD5_Update(&key
->tail
, hmac_key
, sizeof(hmac_key
));
213 OPENSSL_cleanse(hmac_key
, sizeof(hmac_key
));
217 case EVP_CTRL_AEAD_TLS1_AAD
:
219 unsigned char *p
= ptr
;
222 if (arg
!= EVP_AEAD_TLS1_AAD_LEN
)
225 len
= p
[arg
- 2] << 8 | p
[arg
- 1];
227 if (!EVP_CIPHER_CTX_encrypting(ctx
)) {
228 if (len
< MD5_DIGEST_LENGTH
)
230 len
-= MD5_DIGEST_LENGTH
;
231 p
[arg
- 2] = len
>> 8;
234 key
->payload_length
= len
;
236 MD5_Update(&key
->md
, p
, arg
);
238 return MD5_DIGEST_LENGTH
;
245 static EVP_CIPHER r4_hmac_md5_cipher
= {
246 # ifdef NID_rc4_hmac_md5
251 1, EVP_RC4_KEY_SIZE
, 0,
252 EVP_CIPH_STREAM_CIPHER
| EVP_CIPH_VARIABLE_LENGTH
|
253 EVP_CIPH_FLAG_AEAD_CIPHER
,
254 rc4_hmac_md5_init_key
,
257 sizeof(EVP_RC4_HMAC_MD5
),
264 const EVP_CIPHER
*EVP_rc4_hmac_md5(void)
266 return &r4_hmac_md5_cipher
;