1/* ==================================================================== 2 * Copyright (c) 2011 The OpenSSL Project. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in 13 * the documentation and/or other materials provided with the 14 * distribution. 15 * 16 * 3. All advertising materials mentioning features or use of this 17 * software must display the following acknowledgment: 18 * "This product includes software developed by the OpenSSL Project 19 * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" 20 * 21 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to 22 * endorse or promote products derived from this software without 23 * prior written permission. For written permission, please contact 24 * licensing@OpenSSL.org. 25 * 26 * 5. Products derived from this software may not be called "OpenSSL" 27 * nor may "OpenSSL" appear in their names without prior written 28 * permission of the OpenSSL Project. 29 * 30 * 6. Redistributions of any form whatsoever must retain the following 31 * acknowledgment: 32 * "This product includes software developed by the OpenSSL Project 33 * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" 34 * 35 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY 36 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 37 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 38 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR 39 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 40 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 41 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 42 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 43 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 44 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 45 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 46 * OF THE POSSIBILITY OF SUCH DAMAGE. 47 * ==================================================================== 48 */ 49 50#include <openssl/opensslconf.h> 51 52#include <stdio.h> 53#include <string.h> 54 55#if !defined(OPENSSL_NO_RC4) && !defined(OPENSSL_NO_MD5) 56 57# include <openssl/crypto.h> 58# include <openssl/evp.h> 59# include <openssl/objects.h> 60# include <openssl/rc4.h> 61# include <openssl/md5.h> 62 63# ifndef EVP_CIPH_FLAG_AEAD_CIPHER 64# define EVP_CIPH_FLAG_AEAD_CIPHER 0x200000 65# define EVP_CTRL_AEAD_TLS1_AAD 0x16 66# define EVP_CTRL_AEAD_SET_MAC_KEY 0x17 67# endif 68 69/* FIXME: surely this is available elsewhere? */ 70# define EVP_RC4_KEY_SIZE 16 71 72typedef struct { 73 RC4_KEY ks; 74 MD5_CTX head, tail, md; 75 size_t payload_length; 76} EVP_RC4_HMAC_MD5; 77 78# define NO_PAYLOAD_LENGTH ((size_t)-1) 79 80void rc4_md5_enc(RC4_KEY *key, const void *in0, void *out, 81 MD5_CTX *ctx, const void *inp, size_t blocks); 82 83# define data(ctx) ((EVP_RC4_HMAC_MD5 *)(ctx)->cipher_data) 84 85static int rc4_hmac_md5_init_key(EVP_CIPHER_CTX *ctx, 86 const unsigned char *inkey, 87 const unsigned char *iv, int enc) 88{ 89 EVP_RC4_HMAC_MD5 *key = data(ctx); 90 91 RC4_set_key(&key->ks, EVP_CIPHER_CTX_key_length(ctx), inkey); 92 93 MD5_Init(&key->head); /* handy when benchmarking */ 94 key->tail = key->head; 95 key->md = key->head; 96 97 key->payload_length = NO_PAYLOAD_LENGTH; 98 99 return 1; 100} 101 102# if !defined(OPENSSL_NO_ASM) && ( \ 103 defined(__x86_64) || defined(__x86_64__) || \ 104 defined(_M_AMD64) || defined(_M_X64) || \ 105 defined(__INTEL__) ) && \ 106 !(defined(__APPLE__) && defined(__MACH__)) 107# define STITCHED_CALL 108# endif 109 110# if !defined(STITCHED_CALL) 111# define rc4_off 0 112# define md5_off 0 113# endif 114 115static int rc4_hmac_md5_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out, 116 const unsigned char *in, size_t len) 117{ 118 EVP_RC4_HMAC_MD5 *key = data(ctx); 119# if defined(STITCHED_CALL) 120 size_t rc4_off = 32 - 1 - (key->ks.x & (32 - 1)), /* 32 is $MOD from 121 * rc4_md5-x86_64.pl */ 122 md5_off = MD5_CBLOCK - key->md.num, blocks; 123 unsigned int l; 124 extern unsigned int OPENSSL_ia32cap_P[]; 125# endif 126 size_t plen = key->payload_length; 127 128 if (plen != NO_PAYLOAD_LENGTH && len != (plen + MD5_DIGEST_LENGTH)) 129 return 0; 130 131 if (ctx->encrypt) { 132 if (plen == NO_PAYLOAD_LENGTH) 133 plen = len; 134# if defined(STITCHED_CALL) 135 /* cipher has to "fall behind" */ 136 if (rc4_off > md5_off) 137 md5_off += MD5_CBLOCK; 138 139 if (plen > md5_off && (blocks = (plen - md5_off) / MD5_CBLOCK) && 140 (OPENSSL_ia32cap_P[0] & (1 << 20)) == 0) { 141 MD5_Update(&key->md, in, md5_off); 142 RC4(&key->ks, rc4_off, in, out); 143 144 rc4_md5_enc(&key->ks, in + rc4_off, out + rc4_off, 145 &key->md, in + md5_off, blocks); 146 blocks *= MD5_CBLOCK; 147 rc4_off += blocks; 148 md5_off += blocks; 149 key->md.Nh += blocks >> 29; 150 key->md.Nl += blocks <<= 3; 151 if (key->md.Nl < (unsigned int)blocks) 152 key->md.Nh++; 153 } else { 154 rc4_off = 0; 155 md5_off = 0; 156 } 157# endif 158 MD5_Update(&key->md, in + md5_off, plen - md5_off); 159 160 if (plen != len) { /* "TLS" mode of operation */ 161 if (in != out) 162 memcpy(out + rc4_off, in + rc4_off, plen - rc4_off); 163 164 /* calculate HMAC and append it to payload */ 165 MD5_Final(out + plen, &key->md); 166 key->md = key->tail; 167 MD5_Update(&key->md, out + plen, MD5_DIGEST_LENGTH); 168 MD5_Final(out + plen, &key->md); 169 /* encrypt HMAC at once */ 170 RC4(&key->ks, len - rc4_off, out + rc4_off, out + rc4_off); 171 } else { 172 RC4(&key->ks, len - rc4_off, in + rc4_off, out + rc4_off); 173 } 174 } else { 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; 180 else 181 rc4_off += MD5_CBLOCK; 182 183 if (len > rc4_off && (blocks = (len - rc4_off) / MD5_CBLOCK) && 184 (OPENSSL_ia32cap_P[0] & (1 << 20)) == 0) { 185 RC4(&key->ks, rc4_off, in, out); 186 MD5_Update(&key->md, out, md5_off); 187 188 rc4_md5_enc(&key->ks, in + rc4_off, out + rc4_off, 189 &key->md, out + md5_off, blocks); 190 blocks *= MD5_CBLOCK; 191 rc4_off += blocks; 192 md5_off += blocks; 193 l = (key->md.Nl + (blocks << 3)) & 0xffffffffU; 194 if (l < key->md.Nl) 195 key->md.Nh++; 196 key->md.Nl = l; 197 key->md.Nh += blocks >> 29; 198 } else { 199 md5_off = 0; 200 rc4_off = 0; 201 } 202# endif 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); 207 208 /* calculate HMAC and verify it */ 209 MD5_Final(mac, &key->md); 210 key->md = key->tail; 211 MD5_Update(&key->md, mac, MD5_DIGEST_LENGTH); 212 MD5_Final(mac, &key->md); 213 214 if (CRYPTO_memcmp(out + plen, mac, MD5_DIGEST_LENGTH)) 215 return 0; 216 } else { 217 MD5_Update(&key->md, out + md5_off, len - md5_off); 218 } 219 } 220 221 key->payload_length = NO_PAYLOAD_LENGTH; 222 223 return 1; 224} 225 226static int rc4_hmac_md5_ctrl(EVP_CIPHER_CTX *ctx, int type, int arg, 227 void *ptr) 228{ 229 EVP_RC4_HMAC_MD5 *key = data(ctx); 230 231 switch (type) { 232 case EVP_CTRL_AEAD_SET_MAC_KEY: 233 { 234 unsigned int i; 235 unsigned char hmac_key[64]; 236 237 memset(hmac_key, 0, sizeof(hmac_key)); 238 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); 243 } else { 244 memcpy(hmac_key, ptr, arg); 245 } 246 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)); 251 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)); 256 257 return 1; 258 } 259 case EVP_CTRL_AEAD_TLS1_AAD: 260 { 261 unsigned char *p = ptr; 262 unsigned int len; 263 264 if (arg != EVP_AEAD_TLS1_AAD_LEN) 265 return -1; 266 267 len = p[arg - 2] << 8 | p[arg - 1]; 268 269 if (!ctx->encrypt) { 270 if (len < MD5_DIGEST_LENGTH) 271 return -1; 272 len -= MD5_DIGEST_LENGTH; 273 p[arg - 2] = len >> 8; 274 p[arg - 1] = len; 275 } 276 key->payload_length = len; 277 key->md = key->head; 278 MD5_Update(&key->md, p, arg); 279 280 return MD5_DIGEST_LENGTH; 281 } 282 default: 283 return -1; 284 } 285} 286 287static EVP_CIPHER r4_hmac_md5_cipher = { 288# ifdef NID_rc4_hmac_md5 289 NID_rc4_hmac_md5, 290# else 291 NID_undef, 292# endif 293 1, EVP_RC4_KEY_SIZE, 0, 294 EVP_CIPH_STREAM_CIPHER | EVP_CIPH_VARIABLE_LENGTH | 295 EVP_CIPH_FLAG_AEAD_CIPHER, 296 rc4_hmac_md5_init_key, 297 rc4_hmac_md5_cipher, 298 NULL, 299 sizeof(EVP_RC4_HMAC_MD5), 300 NULL, 301 NULL, 302 rc4_hmac_md5_ctrl, 303 NULL 304}; 305 306const EVP_CIPHER *EVP_rc4_hmac_md5(void) 307{ 308 return (&r4_hmac_md5_cipher); 309} 310#endif 311