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