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 "internal/evp_int.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 # 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 # 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 { 41 EVP_RC4_HMAC_MD5 *key = data(ctx); 42 43 RC4_set_key(&key->ks, EVP_CIPHER_CTX_key_length(ctx), inkey); 44 45 MD5_Init(&key->head); /* handy when benchmarking */ 46 key->tail = key->head; 47 key->md = key->head; 48 49 key->payload_length = NO_PAYLOAD_LENGTH; 50 51 return 1; 52 } 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 { 68 EVP_RC4_HMAC_MD5 *key = data(ctx); 69 # if defined(STITCHED_CALL) 70 size_t rc4_off = 32 - 1 - (key->ks.x & (32 - 1)), /* 32 is $MOD from 71 * rc4_md5-x86_64.pl */ 72 md5_off = MD5_CBLOCK - key->md.num, blocks; 73 unsigned int l; 74 extern unsigned int OPENSSL_ia32cap_P[]; 75 # endif 76 size_t plen = key->payload_length; 77 78 if (plen != NO_PAYLOAD_LENGTH && len != (plen + MD5_DIGEST_LENGTH)) 79 return 0; 80 81 if (EVP_CIPHER_CTX_encrypting(ctx)) { 82 if (plen == NO_PAYLOAD_LENGTH) 83 plen = len; 84 # if defined(STITCHED_CALL) 85 /* cipher has to "fall behind" */ 86 if (rc4_off > md5_off) 87 md5_off += MD5_CBLOCK; 88 89 if (plen > md5_off && (blocks = (plen - md5_off) / MD5_CBLOCK) && 90 (OPENSSL_ia32cap_P[0] & (1 << 20)) == 0) { 91 MD5_Update(&key->md, in, md5_off); 92 RC4(&key->ks, rc4_off, in, out); 93 94 rc4_md5_enc(&key->ks, in + rc4_off, out + rc4_off, 95 &key->md, in + md5_off, blocks); 96 blocks *= MD5_CBLOCK; 97 rc4_off += blocks; 98 md5_off += blocks; 99 key->md.Nh += blocks >> 29; 100 key->md.Nl += blocks <<= 3; 101 if (key->md.Nl < (unsigned int)blocks) 102 key->md.Nh++; 103 } else { 104 rc4_off = 0; 105 md5_off = 0; 106 } 107 # endif 108 MD5_Update(&key->md, in + md5_off, plen - md5_off); 109 110 if (plen != len) { /* "TLS" mode of operation */ 111 if (in != out) 112 memcpy(out + rc4_off, in + rc4_off, plen - rc4_off); 113 114 /* calculate HMAC and append it to payload */ 115 MD5_Final(out + plen, &key->md); 116 key->md = key->tail; 117 MD5_Update(&key->md, out + plen, MD5_DIGEST_LENGTH); 118 MD5_Final(out + plen, &key->md); 119 /* encrypt HMAC at once */ 120 RC4(&key->ks, len - rc4_off, out + rc4_off, out + rc4_off); 121 } else { 122 RC4(&key->ks, len - rc4_off, in + rc4_off, out + rc4_off); 123 } 124 } else { 125 unsigned char mac[MD5_DIGEST_LENGTH]; 126 # if defined(STITCHED_CALL) 127 /* digest has to "fall behind" */ 128 if (md5_off > rc4_off) 129 rc4_off += 2 * MD5_CBLOCK; 130 else 131 rc4_off += MD5_CBLOCK; 132 133 if (len > rc4_off && (blocks = (len - rc4_off) / MD5_CBLOCK) && 134 (OPENSSL_ia32cap_P[0] & (1 << 20)) == 0) { 135 RC4(&key->ks, rc4_off, in, out); 136 MD5_Update(&key->md, out, md5_off); 137 138 rc4_md5_enc(&key->ks, in + rc4_off, out + rc4_off, 139 &key->md, out + md5_off, blocks); 140 blocks *= MD5_CBLOCK; 141 rc4_off += blocks; 142 md5_off += blocks; 143 l = (key->md.Nl + (blocks << 3)) & 0xffffffffU; 144 if (l < key->md.Nl) 145 key->md.Nh++; 146 key->md.Nl = l; 147 key->md.Nh += blocks >> 29; 148 } else { 149 md5_off = 0; 150 rc4_off = 0; 151 } 152 # endif 153 /* decrypt HMAC at once */ 154 RC4(&key->ks, len - rc4_off, in + rc4_off, out + rc4_off); 155 if (plen != NO_PAYLOAD_LENGTH) { /* "TLS" mode of operation */ 156 MD5_Update(&key->md, out + md5_off, plen - md5_off); 157 158 /* calculate HMAC and verify it */ 159 MD5_Final(mac, &key->md); 160 key->md = key->tail; 161 MD5_Update(&key->md, mac, MD5_DIGEST_LENGTH); 162 MD5_Final(mac, &key->md); 163 164 if (CRYPTO_memcmp(out + plen, mac, MD5_DIGEST_LENGTH)) 165 return 0; 166 } else { 167 MD5_Update(&key->md, out + md5_off, len - md5_off); 168 } 169 } 170 171 key->payload_length = NO_PAYLOAD_LENGTH; 172 173 return 1; 174 } 175 176 static int rc4_hmac_md5_ctrl(EVP_CIPHER_CTX *ctx, int type, int arg, 177 void *ptr) 178 { 179 EVP_RC4_HMAC_MD5 *key = data(ctx); 180 181 switch (type) { 182 case EVP_CTRL_AEAD_SET_MAC_KEY: 183 { 184 unsigned int i; 185 unsigned char hmac_key[64]; 186 187 memset(hmac_key, 0, sizeof(hmac_key)); 188 189 if (arg > (int)sizeof(hmac_key)) { 190 MD5_Init(&key->head); 191 MD5_Update(&key->head, ptr, arg); 192 MD5_Final(hmac_key, &key->head); 193 } else { 194 memcpy(hmac_key, ptr, arg); 195 } 196 197 for (i = 0; i < sizeof(hmac_key); i++) 198 hmac_key[i] ^= 0x36; /* ipad */ 199 MD5_Init(&key->head); 200 MD5_Update(&key->head, hmac_key, sizeof(hmac_key)); 201 202 for (i = 0; i < sizeof(hmac_key); i++) 203 hmac_key[i] ^= 0x36 ^ 0x5c; /* opad */ 204 MD5_Init(&key->tail); 205 MD5_Update(&key->tail, hmac_key, sizeof(hmac_key)); 206 207 OPENSSL_cleanse(hmac_key, sizeof(hmac_key)); 208 209 return 1; 210 } 211 case EVP_CTRL_AEAD_TLS1_AAD: 212 { 213 unsigned char *p = ptr; 214 unsigned int len; 215 216 if (arg != EVP_AEAD_TLS1_AAD_LEN) 217 return -1; 218 219 len = p[arg - 2] << 8 | p[arg - 1]; 220 221 if (!EVP_CIPHER_CTX_encrypting(ctx)) { 222 if (len < MD5_DIGEST_LENGTH) 223 return -1; 224 len -= MD5_DIGEST_LENGTH; 225 p[arg - 2] = len >> 8; 226 p[arg - 1] = len; 227 } 228 key->payload_length = len; 229 key->md = key->head; 230 MD5_Update(&key->md, p, arg); 231 232 return MD5_DIGEST_LENGTH; 233 } 234 default: 235 return -1; 236 } 237 } 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 { 260 return &r4_hmac_md5_cipher; 261 } 262 #endif 263