/src/openssl30/crypto/evp/e_rc4_hmac_md5.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright 2011-2021 The OpenSSL Project Authors. All Rights Reserved. |
3 | | * |
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 |
8 | | */ |
9 | | |
10 | | /* |
11 | | * MD5 and RC4 low level APIs are deprecated for public use, but still ok for |
12 | | * internal use. |
13 | | */ |
14 | | #include "internal/deprecated.h" |
15 | | |
16 | | #include "internal/cryptlib.h" |
17 | | #include <openssl/opensslconf.h> |
18 | | |
19 | | #include <stdio.h> |
20 | | #include <string.h> |
21 | | |
22 | | #if !defined(OPENSSL_NO_RC4) && !defined(OPENSSL_NO_MD5) |
23 | | |
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" |
30 | | |
31 | | typedef struct { |
32 | | RC4_KEY ks; |
33 | | MD5_CTX head, tail, md; |
34 | | size_t payload_length; |
35 | | } EVP_RC4_HMAC_MD5; |
36 | | |
37 | 0 | # define NO_PAYLOAD_LENGTH ((size_t)-1) |
38 | | |
39 | | void rc4_md5_enc(RC4_KEY *key, const void *in0, void *out, |
40 | | MD5_CTX *ctx, const void *inp, size_t blocks); |
41 | | |
42 | 0 | # define data(ctx) ((EVP_RC4_HMAC_MD5 *)EVP_CIPHER_CTX_get_cipher_data(ctx)) |
43 | | |
44 | | static int rc4_hmac_md5_init_key(EVP_CIPHER_CTX *ctx, |
45 | | const unsigned char *inkey, |
46 | | const unsigned char *iv, int enc) |
47 | 0 | { |
48 | 0 | EVP_RC4_HMAC_MD5 *key = data(ctx); |
49 | 0 | const int keylen = EVP_CIPHER_CTX_get_key_length(ctx); |
50 | |
|
51 | 0 | if (keylen <= 0) |
52 | 0 | return 0; |
53 | | |
54 | 0 | RC4_set_key(&key->ks, keylen, inkey); |
55 | |
|
56 | 0 | MD5_Init(&key->head); /* handy when benchmarking */ |
57 | 0 | key->tail = key->head; |
58 | 0 | key->md = key->head; |
59 | |
|
60 | 0 | key->payload_length = NO_PAYLOAD_LENGTH; |
61 | |
|
62 | 0 | return 1; |
63 | 0 | } |
64 | | |
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 |
69 | | # endif |
70 | | |
71 | | # if !defined(STITCHED_CALL) |
72 | | # define rc4_off 0 |
73 | | # define md5_off 0 |
74 | | # endif |
75 | | |
76 | | static int rc4_hmac_md5_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out, |
77 | | const unsigned char *in, size_t len) |
78 | 0 | { |
79 | 0 | EVP_RC4_HMAC_MD5 *key = data(ctx); |
80 | 0 | # if defined(STITCHED_CALL) |
81 | 0 | size_t rc4_off = 32 - 1 - (key->ks.x & (32 - 1)), /* 32 is $MOD from |
82 | | * rc4_md5-x86_64.pl */ |
83 | 0 | md5_off = MD5_CBLOCK - key->md.num, blocks; |
84 | 0 | unsigned int l; |
85 | 0 | # endif |
86 | 0 | size_t plen = key->payload_length; |
87 | |
|
88 | 0 | if (plen != NO_PAYLOAD_LENGTH && len != (plen + MD5_DIGEST_LENGTH)) |
89 | 0 | return 0; |
90 | | |
91 | 0 | if (EVP_CIPHER_CTX_is_encrypting(ctx)) { |
92 | 0 | if (plen == NO_PAYLOAD_LENGTH) |
93 | 0 | plen = len; |
94 | 0 | # if defined(STITCHED_CALL) |
95 | | /* cipher has to "fall behind" */ |
96 | 0 | if (rc4_off > md5_off) |
97 | 0 | md5_off += MD5_CBLOCK; |
98 | |
|
99 | 0 | if (plen > md5_off && (blocks = (plen - md5_off) / MD5_CBLOCK) && |
100 | 0 | (OPENSSL_ia32cap_P[0] & (1 << 20)) == 0) { |
101 | 0 | MD5_Update(&key->md, in, md5_off); |
102 | 0 | RC4(&key->ks, rc4_off, in, out); |
103 | |
|
104 | 0 | rc4_md5_enc(&key->ks, in + rc4_off, out + rc4_off, |
105 | 0 | &key->md, in + md5_off, blocks); |
106 | 0 | blocks *= MD5_CBLOCK; |
107 | 0 | rc4_off += blocks; |
108 | 0 | md5_off += blocks; |
109 | 0 | key->md.Nh += blocks >> 29; |
110 | 0 | key->md.Nl += blocks <<= 3; |
111 | 0 | if (key->md.Nl < (unsigned int)blocks) |
112 | 0 | key->md.Nh++; |
113 | 0 | } else { |
114 | 0 | rc4_off = 0; |
115 | 0 | md5_off = 0; |
116 | 0 | } |
117 | 0 | # endif |
118 | 0 | MD5_Update(&key->md, in + md5_off, plen - md5_off); |
119 | |
|
120 | 0 | if (plen != len) { /* "TLS" mode of operation */ |
121 | 0 | if (in != out) |
122 | 0 | memcpy(out + rc4_off, in + rc4_off, plen - rc4_off); |
123 | | |
124 | | /* calculate HMAC and append it to payload */ |
125 | 0 | MD5_Final(out + plen, &key->md); |
126 | 0 | key->md = key->tail; |
127 | 0 | MD5_Update(&key->md, out + plen, MD5_DIGEST_LENGTH); |
128 | 0 | MD5_Final(out + plen, &key->md); |
129 | | /* encrypt HMAC at once */ |
130 | 0 | RC4(&key->ks, len - rc4_off, out + rc4_off, out + rc4_off); |
131 | 0 | } else { |
132 | 0 | RC4(&key->ks, len - rc4_off, in + rc4_off, out + rc4_off); |
133 | 0 | } |
134 | 0 | } else { |
135 | 0 | unsigned char mac[MD5_DIGEST_LENGTH]; |
136 | 0 | # if defined(STITCHED_CALL) |
137 | | /* digest has to "fall behind" */ |
138 | 0 | if (md5_off > rc4_off) |
139 | 0 | rc4_off += 2 * MD5_CBLOCK; |
140 | 0 | else |
141 | 0 | rc4_off += MD5_CBLOCK; |
142 | |
|
143 | 0 | if (len > rc4_off && (blocks = (len - rc4_off) / MD5_CBLOCK) && |
144 | 0 | (OPENSSL_ia32cap_P[0] & (1 << 20)) == 0) { |
145 | 0 | RC4(&key->ks, rc4_off, in, out); |
146 | 0 | MD5_Update(&key->md, out, md5_off); |
147 | |
|
148 | 0 | rc4_md5_enc(&key->ks, in + rc4_off, out + rc4_off, |
149 | 0 | &key->md, out + md5_off, blocks); |
150 | 0 | blocks *= MD5_CBLOCK; |
151 | 0 | rc4_off += blocks; |
152 | 0 | md5_off += blocks; |
153 | 0 | l = (key->md.Nl + (blocks << 3)) & 0xffffffffU; |
154 | 0 | if (l < key->md.Nl) |
155 | 0 | key->md.Nh++; |
156 | 0 | key->md.Nl = l; |
157 | 0 | key->md.Nh += blocks >> 29; |
158 | 0 | } else { |
159 | 0 | md5_off = 0; |
160 | 0 | rc4_off = 0; |
161 | 0 | } |
162 | 0 | # endif |
163 | | /* decrypt HMAC at once */ |
164 | 0 | RC4(&key->ks, len - rc4_off, in + rc4_off, out + rc4_off); |
165 | 0 | if (plen != NO_PAYLOAD_LENGTH) { /* "TLS" mode of operation */ |
166 | 0 | MD5_Update(&key->md, out + md5_off, plen - md5_off); |
167 | | |
168 | | /* calculate HMAC and verify it */ |
169 | 0 | MD5_Final(mac, &key->md); |
170 | 0 | key->md = key->tail; |
171 | 0 | MD5_Update(&key->md, mac, MD5_DIGEST_LENGTH); |
172 | 0 | MD5_Final(mac, &key->md); |
173 | |
|
174 | 0 | if (CRYPTO_memcmp(out + plen, mac, MD5_DIGEST_LENGTH)) |
175 | 0 | return 0; |
176 | 0 | } else { |
177 | 0 | MD5_Update(&key->md, out + md5_off, len - md5_off); |
178 | 0 | } |
179 | 0 | } |
180 | | |
181 | 0 | key->payload_length = NO_PAYLOAD_LENGTH; |
182 | |
|
183 | 0 | return 1; |
184 | 0 | } |
185 | | |
186 | | static int rc4_hmac_md5_ctrl(EVP_CIPHER_CTX *ctx, int type, int arg, |
187 | | void *ptr) |
188 | 0 | { |
189 | 0 | EVP_RC4_HMAC_MD5 *key = data(ctx); |
190 | |
|
191 | 0 | switch (type) { |
192 | 0 | case EVP_CTRL_AEAD_SET_MAC_KEY: |
193 | 0 | { |
194 | 0 | unsigned int i; |
195 | 0 | unsigned char hmac_key[64]; |
196 | |
|
197 | 0 | memset(hmac_key, 0, sizeof(hmac_key)); |
198 | |
|
199 | 0 | if (arg > (int)sizeof(hmac_key)) { |
200 | 0 | MD5_Init(&key->head); |
201 | 0 | MD5_Update(&key->head, ptr, arg); |
202 | 0 | MD5_Final(hmac_key, &key->head); |
203 | 0 | } else { |
204 | 0 | memcpy(hmac_key, ptr, arg); |
205 | 0 | } |
206 | |
|
207 | 0 | for (i = 0; i < sizeof(hmac_key); i++) |
208 | 0 | hmac_key[i] ^= 0x36; /* ipad */ |
209 | 0 | MD5_Init(&key->head); |
210 | 0 | MD5_Update(&key->head, hmac_key, sizeof(hmac_key)); |
211 | |
|
212 | 0 | for (i = 0; i < sizeof(hmac_key); i++) |
213 | 0 | hmac_key[i] ^= 0x36 ^ 0x5c; /* opad */ |
214 | 0 | MD5_Init(&key->tail); |
215 | 0 | MD5_Update(&key->tail, hmac_key, sizeof(hmac_key)); |
216 | |
|
217 | 0 | OPENSSL_cleanse(hmac_key, sizeof(hmac_key)); |
218 | |
|
219 | 0 | return 1; |
220 | 0 | } |
221 | 0 | case EVP_CTRL_AEAD_TLS1_AAD: |
222 | 0 | { |
223 | 0 | unsigned char *p = ptr; |
224 | 0 | unsigned int len; |
225 | |
|
226 | 0 | if (arg != EVP_AEAD_TLS1_AAD_LEN) |
227 | 0 | return -1; |
228 | | |
229 | 0 | len = p[arg - 2] << 8 | p[arg - 1]; |
230 | |
|
231 | 0 | if (!EVP_CIPHER_CTX_is_encrypting(ctx)) { |
232 | 0 | if (len < MD5_DIGEST_LENGTH) |
233 | 0 | return -1; |
234 | 0 | len -= MD5_DIGEST_LENGTH; |
235 | 0 | p[arg - 2] = len >> 8; |
236 | 0 | p[arg - 1] = len; |
237 | 0 | } |
238 | 0 | key->payload_length = len; |
239 | 0 | key->md = key->head; |
240 | 0 | MD5_Update(&key->md, p, arg); |
241 | |
|
242 | 0 | return MD5_DIGEST_LENGTH; |
243 | 0 | } |
244 | 0 | default: |
245 | 0 | return -1; |
246 | 0 | } |
247 | 0 | } |
248 | | |
249 | | static EVP_CIPHER r4_hmac_md5_cipher = { |
250 | | # ifdef NID_rc4_hmac_md5 |
251 | | NID_rc4_hmac_md5, |
252 | | # else |
253 | | NID_undef, |
254 | | # endif |
255 | | 1, EVP_RC4_KEY_SIZE, 0, |
256 | | EVP_CIPH_STREAM_CIPHER | EVP_CIPH_VARIABLE_LENGTH | |
257 | | EVP_CIPH_FLAG_AEAD_CIPHER, |
258 | | EVP_ORIG_GLOBAL, |
259 | | rc4_hmac_md5_init_key, |
260 | | rc4_hmac_md5_cipher, |
261 | | NULL, |
262 | | sizeof(EVP_RC4_HMAC_MD5), |
263 | | NULL, |
264 | | NULL, |
265 | | rc4_hmac_md5_ctrl, |
266 | | NULL |
267 | | }; |
268 | | |
269 | | const EVP_CIPHER *EVP_rc4_hmac_md5(void) |
270 | 71 | { |
271 | 71 | return &r4_hmac_md5_cipher; |
272 | 71 | } |
273 | | #endif |