2 * Copyright 2011-2021 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
);
49 const int keylen
= EVP_CIPHER_CTX_key_length(ctx
);
54 RC4_set_key(&key
->ks
, keylen
, inkey
);
56 MD5_Init(&key
->head
); /* handy when benchmarking */
57 key
->tail
= key
->head
;
60 key
->payload_length
= NO_PAYLOAD_LENGTH
;
65 # if defined(RC4_ASM) && defined(MD5_ASM) && ( \
66 defined(__x86_64) || defined(__x86_64__) || \
67 defined(_M_AMD64) || defined(_M_X64) )
68 # define STITCHED_CALL
71 # if !defined(STITCHED_CALL)
76 static int rc4_hmac_md5_cipher(EVP_CIPHER_CTX
*ctx
, unsigned char *out
,
77 const unsigned char *in
, size_t len
)
79 EVP_RC4_HMAC_MD5
*key
= data(ctx
);
80 # if defined(STITCHED_CALL)
81 size_t rc4_off
= 32 - 1 - (key
->ks
.x
& (32 - 1)), /* 32 is $MOD from
82 * rc4_md5-x86_64.pl */
83 md5_off
= MD5_CBLOCK
- key
->md
.num
, blocks
;
86 size_t plen
= key
->payload_length
;
88 if (plen
!= NO_PAYLOAD_LENGTH
&& len
!= (plen
+ MD5_DIGEST_LENGTH
))
91 if (EVP_CIPHER_CTX_encrypting(ctx
)) {
92 if (plen
== NO_PAYLOAD_LENGTH
)
94 # if defined(STITCHED_CALL)
95 /* cipher has to "fall behind" */
96 if (rc4_off
> md5_off
)
97 md5_off
+= MD5_CBLOCK
;
99 if (plen
> md5_off
&& (blocks
= (plen
- md5_off
) / MD5_CBLOCK
) &&
100 (OPENSSL_ia32cap_P
[0] & (1 << 20)) == 0) {
101 MD5_Update(&key
->md
, in
, md5_off
);
102 RC4(&key
->ks
, rc4_off
, in
, out
);
104 rc4_md5_enc(&key
->ks
, in
+ rc4_off
, out
+ rc4_off
,
105 &key
->md
, in
+ md5_off
, blocks
);
106 blocks
*= MD5_CBLOCK
;
109 key
->md
.Nh
+= blocks
>> 29;
110 key
->md
.Nl
+= blocks
<<= 3;
111 if (key
->md
.Nl
< (unsigned int)blocks
)
118 MD5_Update(&key
->md
, in
+ md5_off
, plen
- md5_off
);
120 if (plen
!= len
) { /* "TLS" mode of operation */
122 memcpy(out
+ rc4_off
, in
+ rc4_off
, plen
- rc4_off
);
124 /* calculate HMAC and append it to payload */
125 MD5_Final(out
+ plen
, &key
->md
);
127 MD5_Update(&key
->md
, out
+ plen
, MD5_DIGEST_LENGTH
);
128 MD5_Final(out
+ plen
, &key
->md
);
129 /* encrypt HMAC at once */
130 RC4(&key
->ks
, len
- rc4_off
, out
+ rc4_off
, out
+ rc4_off
);
132 RC4(&key
->ks
, len
- rc4_off
, in
+ rc4_off
, out
+ rc4_off
);
135 unsigned char mac
[MD5_DIGEST_LENGTH
];
136 # if defined(STITCHED_CALL)
137 /* digest has to "fall behind" */
138 if (md5_off
> rc4_off
)
139 rc4_off
+= 2 * MD5_CBLOCK
;
141 rc4_off
+= MD5_CBLOCK
;
143 if (len
> rc4_off
&& (blocks
= (len
- rc4_off
) / MD5_CBLOCK
) &&
144 (OPENSSL_ia32cap_P
[0] & (1 << 20)) == 0) {
145 RC4(&key
->ks
, rc4_off
, in
, out
);
146 MD5_Update(&key
->md
, out
, md5_off
);
148 rc4_md5_enc(&key
->ks
, in
+ rc4_off
, out
+ rc4_off
,
149 &key
->md
, out
+ md5_off
, blocks
);
150 blocks
*= MD5_CBLOCK
;
153 l
= (key
->md
.Nl
+ (blocks
<< 3)) & 0xffffffffU
;
157 key
->md
.Nh
+= blocks
>> 29;
163 /* decrypt HMAC at once */
164 RC4(&key
->ks
, len
- rc4_off
, in
+ rc4_off
, out
+ rc4_off
);
165 if (plen
!= NO_PAYLOAD_LENGTH
) { /* "TLS" mode of operation */
166 MD5_Update(&key
->md
, out
+ md5_off
, plen
- md5_off
);
168 /* calculate HMAC and verify it */
169 MD5_Final(mac
, &key
->md
);
171 MD5_Update(&key
->md
, mac
, MD5_DIGEST_LENGTH
);
172 MD5_Final(mac
, &key
->md
);
174 if (CRYPTO_memcmp(out
+ plen
, mac
, MD5_DIGEST_LENGTH
))
177 MD5_Update(&key
->md
, out
+ md5_off
, len
- md5_off
);
181 key
->payload_length
= NO_PAYLOAD_LENGTH
;
186 static int rc4_hmac_md5_ctrl(EVP_CIPHER_CTX
*ctx
, int type
, int arg
,
189 EVP_RC4_HMAC_MD5
*key
= data(ctx
);
192 case EVP_CTRL_AEAD_SET_MAC_KEY
:
195 unsigned char hmac_key
[64];
197 memset(hmac_key
, 0, sizeof(hmac_key
));
199 if (arg
> (int)sizeof(hmac_key
)) {
200 MD5_Init(&key
->head
);
201 MD5_Update(&key
->head
, ptr
, arg
);
202 MD5_Final(hmac_key
, &key
->head
);
204 memcpy(hmac_key
, ptr
, arg
);
207 for (i
= 0; i
< sizeof(hmac_key
); i
++)
208 hmac_key
[i
] ^= 0x36; /* ipad */
209 MD5_Init(&key
->head
);
210 MD5_Update(&key
->head
, hmac_key
, sizeof(hmac_key
));
212 for (i
= 0; i
< sizeof(hmac_key
); i
++)
213 hmac_key
[i
] ^= 0x36 ^ 0x5c; /* opad */
214 MD5_Init(&key
->tail
);
215 MD5_Update(&key
->tail
, hmac_key
, sizeof(hmac_key
));
217 OPENSSL_cleanse(hmac_key
, sizeof(hmac_key
));
221 case EVP_CTRL_AEAD_TLS1_AAD
:
223 unsigned char *p
= ptr
;
226 if (arg
!= EVP_AEAD_TLS1_AAD_LEN
)
229 len
= p
[arg
- 2] << 8 | p
[arg
- 1];
231 if (!EVP_CIPHER_CTX_encrypting(ctx
)) {
232 if (len
< MD5_DIGEST_LENGTH
)
234 len
-= MD5_DIGEST_LENGTH
;
235 p
[arg
- 2] = len
>> 8;
238 key
->payload_length
= len
;
240 MD5_Update(&key
->md
, p
, arg
);
242 return MD5_DIGEST_LENGTH
;
249 static EVP_CIPHER r4_hmac_md5_cipher
= {
250 # ifdef NID_rc4_hmac_md5
255 1, EVP_RC4_KEY_SIZE
, 0,
256 EVP_CIPH_STREAM_CIPHER
| EVP_CIPH_VARIABLE_LENGTH
|
257 EVP_CIPH_FLAG_AEAD_CIPHER
,
258 rc4_hmac_md5_init_key
,
261 sizeof(EVP_RC4_HMAC_MD5
),
268 const EVP_CIPHER
*EVP_rc4_hmac_md5(void)
270 return &r4_hmac_md5_cipher
;