e_rc4_hmac_md5.c revision 280304
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/evp.h> 58# include <openssl/objects.h> 59# include <openssl/rc4.h> 60# include <openssl/md5.h> 61 62# ifndef EVP_CIPH_FLAG_AEAD_CIPHER 63# define EVP_CIPH_FLAG_AEAD_CIPHER 0x200000 64# define EVP_CTRL_AEAD_TLS1_AAD 0x16 65# define EVP_CTRL_AEAD_SET_MAC_KEY 0x17 66# endif 67 68/* FIXME: surely this is available elsewhere? */ 69# define EVP_RC4_KEY_SIZE 16 70 71typedef struct { 72 RC4_KEY ks; 73 MD5_CTX head, tail, md; 74 size_t payload_length; 75} EVP_RC4_HMAC_MD5; 76 77# define NO_PAYLOAD_LENGTH ((size_t)-1) 78 79void rc4_md5_enc(RC4_KEY *key, const void *in0, void *out, 80 MD5_CTX *ctx, const void *inp, size_t blocks); 81 82# define data(ctx) ((EVP_RC4_HMAC_MD5 *)(ctx)->cipher_data) 83 84static int rc4_hmac_md5_init_key(EVP_CIPHER_CTX *ctx, 85 const unsigned char *inkey, 86 const unsigned char *iv, int enc) 87{ 88 EVP_RC4_HMAC_MD5 *key = data(ctx); 89 90 RC4_set_key(&key->ks, EVP_CIPHER_CTX_key_length(ctx), inkey); 91 92 MD5_Init(&key->head); /* handy when benchmarking */ 93 key->tail = key->head; 94 key->md = key->head; 95 96 key->payload_length = NO_PAYLOAD_LENGTH; 97 98 return 1; 99} 100 101# if !defined(OPENSSL_NO_ASM) && ( \ 102 defined(__x86_64) || defined(__x86_64__) || \ 103 defined(_M_AMD64) || defined(_M_X64) || \ 104 defined(__INTEL__) ) && \ 105 !(defined(__APPLE__) && defined(__MACH__)) 106# define STITCHED_CALL 107# endif 108 109# if !defined(STITCHED_CALL) 110# define rc4_off 0 111# define md5_off 0 112# endif 113 114static int rc4_hmac_md5_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out, 115 const unsigned char *in, size_t len) 116{ 117 EVP_RC4_HMAC_MD5 *key = data(ctx); 118# if defined(STITCHED_CALL) 119 size_t rc4_off = 32 - 1 - (key->ks.x & (32 - 1)), /* 32 is $MOD from 120 * rc4_md5-x86_64.pl */ 121 md5_off = MD5_CBLOCK - key->md.num, blocks; 122 unsigned int l; 123 extern unsigned int OPENSSL_ia32cap_P[]; 124# endif 125 size_t plen = key->payload_length; 126 127 if (plen != NO_PAYLOAD_LENGTH && len != (plen + MD5_DIGEST_LENGTH)) 128 return 0; 129 130 if (ctx->encrypt) { 131 if (plen == NO_PAYLOAD_LENGTH) 132 plen = len; 133# if defined(STITCHED_CALL) 134 /* cipher has to "fall behind" */ 135 if (rc4_off > md5_off) 136 md5_off += MD5_CBLOCK; 137 138 if (plen > md5_off && (blocks = (plen - md5_off) / MD5_CBLOCK) && 139 (OPENSSL_ia32cap_P[0] & (1 << 20)) == 0) { 140 MD5_Update(&key->md, in, md5_off); 141 RC4(&key->ks, rc4_off, in, out); 142 143 rc4_md5_enc(&key->ks, in + rc4_off, out + rc4_off, 144 &key->md, in + md5_off, blocks); 145 blocks *= MD5_CBLOCK; 146 rc4_off += blocks; 147 md5_off += blocks; 148 key->md.Nh += blocks >> 29; 149 key->md.Nl += blocks <<= 3; 150 if (key->md.Nl < (unsigned int)blocks) 151 key->md.Nh++; 152 } else { 153 rc4_off = 0; 154 md5_off = 0; 155 } 156# endif 157 MD5_Update(&key->md, in + md5_off, plen - md5_off); 158 159 if (plen != len) { /* "TLS" mode of operation */ 160 if (in != out) 161 memcpy(out + rc4_off, in + rc4_off, plen - rc4_off); 162 163 /* calculate HMAC and append it to payload */ 164 MD5_Final(out + plen, &key->md); 165 key->md = key->tail; 166 MD5_Update(&key->md, out + plen, MD5_DIGEST_LENGTH); 167 MD5_Final(out + plen, &key->md); 168 /* encrypt HMAC at once */ 169 RC4(&key->ks, len - rc4_off, out + rc4_off, out + rc4_off); 170 } else { 171 RC4(&key->ks, len - rc4_off, in + rc4_off, out + rc4_off); 172 } 173 } else { 174 unsigned char mac[MD5_DIGEST_LENGTH]; 175# if defined(STITCHED_CALL) 176 /* digest has to "fall behind" */ 177 if (md5_off > rc4_off) 178 rc4_off += 2 * MD5_CBLOCK; 179 else 180 rc4_off += MD5_CBLOCK; 181 182 if (len > rc4_off && (blocks = (len - rc4_off) / MD5_CBLOCK) && 183 (OPENSSL_ia32cap_P[0] & (1 << 20)) == 0) { 184 RC4(&key->ks, rc4_off, in, out); 185 MD5_Update(&key->md, out, md5_off); 186 187 rc4_md5_enc(&key->ks, in + rc4_off, out + rc4_off, 188 &key->md, out + md5_off, blocks); 189 blocks *= MD5_CBLOCK; 190 rc4_off += blocks; 191 md5_off += blocks; 192 l = (key->md.Nl + (blocks << 3)) & 0xffffffffU; 193 if (l < key->md.Nl) 194 key->md.Nh++; 195 key->md.Nl = l; 196 key->md.Nh += blocks >> 29; 197 } else { 198 md5_off = 0; 199 rc4_off = 0; 200 } 201# endif 202 /* decrypt HMAC at once */ 203 RC4(&key->ks, len - rc4_off, in + rc4_off, out + rc4_off); 204 if (plen != NO_PAYLOAD_LENGTH) { /* "TLS" mode of operation */ 205 MD5_Update(&key->md, out + md5_off, plen - md5_off); 206 207 /* calculate HMAC and verify it */ 208 MD5_Final(mac, &key->md); 209 key->md = key->tail; 210 MD5_Update(&key->md, mac, MD5_DIGEST_LENGTH); 211 MD5_Final(mac, &key->md); 212 213 if (memcmp(out + plen, mac, MD5_DIGEST_LENGTH)) 214 return 0; 215 } else { 216 MD5_Update(&key->md, out + md5_off, len - md5_off); 217 } 218 } 219 220 key->payload_length = NO_PAYLOAD_LENGTH; 221 222 return 1; 223} 224 225static int rc4_hmac_md5_ctrl(EVP_CIPHER_CTX *ctx, int type, int arg, 226 void *ptr) 227{ 228 EVP_RC4_HMAC_MD5 *key = data(ctx); 229 230 switch (type) { 231 case EVP_CTRL_AEAD_SET_MAC_KEY: 232 { 233 unsigned int i; 234 unsigned char hmac_key[64]; 235 236 memset(hmac_key, 0, sizeof(hmac_key)); 237 238 if (arg > (int)sizeof(hmac_key)) { 239 MD5_Init(&key->head); 240 MD5_Update(&key->head, ptr, arg); 241 MD5_Final(hmac_key, &key->head); 242 } else { 243 memcpy(hmac_key, ptr, arg); 244 } 245 246 for (i = 0; i < sizeof(hmac_key); i++) 247 hmac_key[i] ^= 0x36; /* ipad */ 248 MD5_Init(&key->head); 249 MD5_Update(&key->head, hmac_key, sizeof(hmac_key)); 250 251 for (i = 0; i < sizeof(hmac_key); i++) 252 hmac_key[i] ^= 0x36 ^ 0x5c; /* opad */ 253 MD5_Init(&key->tail); 254 MD5_Update(&key->tail, hmac_key, sizeof(hmac_key)); 255 256 return 1; 257 } 258 case EVP_CTRL_AEAD_TLS1_AAD: 259 { 260 unsigned char *p = ptr; 261 unsigned int len = p[arg - 2] << 8 | p[arg - 1]; 262 263 if (!ctx->encrypt) { 264 len -= MD5_DIGEST_LENGTH; 265 p[arg - 2] = len >> 8; 266 p[arg - 1] = len; 267 } 268 key->payload_length = len; 269 key->md = key->head; 270 MD5_Update(&key->md, p, arg); 271 272 return MD5_DIGEST_LENGTH; 273 } 274 default: 275 return -1; 276 } 277} 278 279static EVP_CIPHER r4_hmac_md5_cipher = { 280# ifdef NID_rc4_hmac_md5 281 NID_rc4_hmac_md5, 282# else 283 NID_undef, 284# endif 285 1, EVP_RC4_KEY_SIZE, 0, 286 EVP_CIPH_STREAM_CIPHER | EVP_CIPH_VARIABLE_LENGTH | 287 EVP_CIPH_FLAG_AEAD_CIPHER, 288 rc4_hmac_md5_init_key, 289 rc4_hmac_md5_cipher, 290 NULL, 291 sizeof(EVP_RC4_HMAC_MD5), 292 NULL, 293 NULL, 294 rc4_hmac_md5_ctrl, 295 NULL 296}; 297 298const EVP_CIPHER *EVP_rc4_hmac_md5(void) 299{ 300 return (&r4_hmac_md5_cipher); 301} 302#endif 303