1 /* $OpenBSD: e_rc4_hmac_md5.c,v 1.8 2017/01/31 13:17:21 inoguchi Exp $ */
2 /* ====================================================================
3 * Copyright (c) 2011 The OpenSSL Project. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in
14 * the documentation and/or other materials provided with the
17 * 3. All advertising materials mentioning features or use of this
18 * software must display the following acknowledgment:
19 * "This product includes software developed by the OpenSSL Project
20 * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
22 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
23 * endorse or promote products derived from this software without
24 * prior written permission. For written permission, please contact
25 * licensing@OpenSSL.org.
27 * 5. Products derived from this software may not be called "OpenSSL"
28 * nor may "OpenSSL" appear in their names without prior written
29 * permission of the OpenSSL Project.
31 * 6. Redistributions of any form whatsoever must retain the following
33 * "This product includes software developed by the OpenSSL Project
34 * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
36 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
37 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
38 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
39 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
40 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
41 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
42 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
43 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
44 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
45 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
46 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
47 * OF THE POSSIBILITY OF SUCH DAMAGE.
48 * ====================================================================
54 #include <openssl/opensslconf.h>
56 #if !defined(OPENSSL_NO_RC4) && !defined(OPENSSL_NO_MD5)
58 #include <openssl/evp.h>
59 #include <openssl/objects.h>
60 #include <openssl/rc4.h>
61 #include <openssl/md5.h>
63 /* FIXME: surely this is available elsewhere? */
64 #define EVP_RC4_KEY_SIZE 16
68 MD5_CTX head
, tail
, md
;
69 size_t payload_length
;
72 #define NO_PAYLOAD_LENGTH ((size_t)-1)
74 void rc4_md5_enc (RC4_KEY
*key
, const void *in0
, void *out
,
75 MD5_CTX
*ctx
, const void *inp
, size_t blocks
);
77 #define data(ctx) ((EVP_RC4_HMAC_MD5 *)(ctx)->cipher_data)
80 rc4_hmac_md5_init_key(EVP_CIPHER_CTX
*ctx
, const unsigned char *inkey
,
81 const unsigned char *iv
, int enc
)
83 EVP_RC4_HMAC_MD5
*key
= data(ctx
);
85 RC4_set_key(&key
->ks
, EVP_CIPHER_CTX_key_length(ctx
), inkey
);
87 MD5_Init(&key
->head
); /* handy when benchmarking */
88 key
->tail
= key
->head
;
91 key
->payload_length
= NO_PAYLOAD_LENGTH
;
96 #if !defined(OPENSSL_NO_ASM) && defined(RC4_MD5_ASM) && ( \
97 defined(__x86_64) || defined(__x86_64__) || \
98 defined(_M_AMD64) || defined(_M_X64) || \
99 defined(__INTEL__) ) && \
100 !(defined(__APPLE__) && defined(__MACH__))
101 #define STITCHED_CALL
102 #include "x86_arch.h"
105 #if !defined(STITCHED_CALL)
111 rc4_hmac_md5_cipher(EVP_CIPHER_CTX
*ctx
, unsigned char *out
,
112 const unsigned char *in
, size_t len
)
114 EVP_RC4_HMAC_MD5
*key
= data(ctx
);
115 #if defined(STITCHED_CALL)
116 size_t rc4_off
= 32-1-(key
->ks
.x
&(32-1)), /* 32 is $MOD from rc4_md5-x86_64.pl */
117 md5_off
= MD5_CBLOCK
- key
->md
.num
,
121 size_t plen
= key
->payload_length
;
123 if (plen
!= NO_PAYLOAD_LENGTH
&& len
!= (plen
+ MD5_DIGEST_LENGTH
))
127 if (plen
== NO_PAYLOAD_LENGTH
)
129 #if defined(STITCHED_CALL)
130 /* cipher has to "fall behind" */
131 if (rc4_off
> md5_off
)
132 md5_off
+= MD5_CBLOCK
;
134 if (plen
> md5_off
&&
135 (blocks
= (plen
- md5_off
) / MD5_CBLOCK
) &&
136 (OPENSSL_cpu_caps() & CPUCAP_MASK_INTELP4
) == 0) {
137 MD5_Update(&key
->md
, in
, md5_off
);
138 RC4(&key
->ks
, rc4_off
, in
, out
);
140 rc4_md5_enc(&key
->ks
, in
+ rc4_off
, out
+ rc4_off
,
141 &key
->md
, in
+ md5_off
, blocks
);
142 blocks
*= MD5_CBLOCK
;
145 key
->md
.Nh
+= blocks
>> 29;
146 key
->md
.Nl
+= blocks
<<= 3;
147 if (key
->md
.Nl
< (unsigned int)blocks
)
154 MD5_Update(&key
->md
, in
+ md5_off
, plen
- md5_off
);
156 if (plen
!=len
) { /* "TLS" mode of operation */
158 memcpy(out
+ rc4_off
, in
+ rc4_off
,
161 /* calculate HMAC and append it to payload */
162 MD5_Final(out
+ plen
, &key
->md
);
164 MD5_Update(&key
->md
, out
+ plen
, MD5_DIGEST_LENGTH
);
165 MD5_Final(out
+ plen
, &key
->md
);
167 /* encrypt HMAC at once */
168 RC4(&key
->ks
, len
- rc4_off
, out
+ rc4_off
,
171 RC4(&key
->ks
, len
- rc4_off
, in
+ rc4_off
,
175 unsigned char mac
[MD5_DIGEST_LENGTH
];
176 #if defined(STITCHED_CALL)
177 /* digest has to "fall behind" */
178 if (md5_off
> rc4_off
)
179 rc4_off
+= 2*MD5_CBLOCK
;
181 rc4_off
+= MD5_CBLOCK
;
183 if (len
> rc4_off
&& (blocks
= (len
- rc4_off
) / MD5_CBLOCK
) &&
184 (OPENSSL_cpu_caps() & CPUCAP_MASK_INTELP4
) == 0) {
185 RC4(&key
->ks
, rc4_off
, in
, out
);
186 MD5_Update(&key
->md
, out
, md5_off
);
188 rc4_md5_enc(&key
->ks
, in
+ rc4_off
, out
+ rc4_off
,
189 &key
->md
, out
+ md5_off
, blocks
);
190 blocks
*= MD5_CBLOCK
;
193 l
= (key
->md
.Nl
+ (blocks
<< 3)) & 0xffffffffU
;
197 key
->md
.Nh
+= blocks
>> 29;
203 /* decrypt HMAC at once */
204 RC4(&key
->ks
, len
- rc4_off
, in
+ rc4_off
, out
+ rc4_off
);
205 if (plen
!=NO_PAYLOAD_LENGTH
) { /* "TLS" mode of operation */
206 MD5_Update(&key
->md
, out
+ md5_off
, plen
- md5_off
);
208 /* calculate HMAC and verify it */
209 MD5_Final(mac
, &key
->md
);
211 MD5_Update(&key
->md
, mac
, MD5_DIGEST_LENGTH
);
212 MD5_Final(mac
, &key
->md
);
214 if (memcmp(out
+ plen
, mac
, MD5_DIGEST_LENGTH
))
217 MD5_Update(&key
->md
, out
+ md5_off
, len
- md5_off
);
221 key
->payload_length
= NO_PAYLOAD_LENGTH
;
227 rc4_hmac_md5_ctrl(EVP_CIPHER_CTX
*ctx
, int type
, int arg
, void *ptr
)
229 EVP_RC4_HMAC_MD5
*key
= data(ctx
);
232 case EVP_CTRL_AEAD_SET_MAC_KEY
:
235 unsigned char hmac_key
[64];
237 memset (hmac_key
, 0, sizeof(hmac_key
));
239 if (arg
> (int)sizeof(hmac_key
)) {
240 MD5_Init(&key
->head
);
241 MD5_Update(&key
->head
, ptr
, arg
);
242 MD5_Final(hmac_key
, &key
->head
);
244 memcpy(hmac_key
, ptr
, arg
);
247 for (i
= 0; i
< sizeof(hmac_key
); i
++)
248 hmac_key
[i
] ^= 0x36; /* ipad */
249 MD5_Init(&key
->head
);
250 MD5_Update(&key
->head
, hmac_key
, sizeof(hmac_key
));
252 for (i
= 0; i
< sizeof(hmac_key
); i
++)
253 hmac_key
[i
] ^= 0x36 ^ 0x5c; /* opad */
254 MD5_Init(&key
->tail
);
255 MD5_Update(&key
->tail
, hmac_key
, sizeof(hmac_key
));
259 case EVP_CTRL_AEAD_TLS1_AAD
:
261 unsigned char *p
= ptr
;
262 unsigned int len
= p
[arg
- 2] << 8 | p
[arg
- 1];
265 if (len
< MD5_DIGEST_LENGTH
)
267 len
-= MD5_DIGEST_LENGTH
;
268 p
[arg
- 2] = len
>> 8;
271 key
->payload_length
= len
;
273 MD5_Update(&key
->md
, p
, arg
);
275 return MD5_DIGEST_LENGTH
;
282 static EVP_CIPHER r4_hmac_md5_cipher
= {
283 #ifdef NID_rc4_hmac_md5
288 1, EVP_RC4_KEY_SIZE
, 0,
289 EVP_CIPH_STREAM_CIPHER
|EVP_CIPH_VARIABLE_LENGTH
|EVP_CIPH_FLAG_AEAD_CIPHER
,
290 rc4_hmac_md5_init_key
,
293 sizeof(EVP_RC4_HMAC_MD5
),
301 EVP_rc4_hmac_md5(void)
303 return (&r4_hmac_md5_cipher
);