/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  |