void ssl3_cbc_digest_record(
	const EVP_MD_CTX *ctx,
	unsigned char* md_out,
	size_t* md_out_size,
	const unsigned char header[13],
	const unsigned char *data,
	size_t data_plus_mac_size,
	size_t data_plus_mac_plus_padding_size,
	const unsigned char *mac_secret,
	unsigned mac_secret_length,
	char is_sslv3)
	{
	union {	double align;
		unsigned char c[sizeof(LARGEST_DIGEST_CTX)]; } md_state;
	void (*md_final_raw)(void *ctx, unsigned char *md_out);
	void (*md_transform)(void *ctx, const unsigned char *block);
	unsigned md_size, md_block_size = 64;
	unsigned sslv3_pad_length = 40, header_length, variance_blocks,
		 len, max_mac_bytes, num_blocks,
		 num_starting_blocks, k, mac_end_offset, c, index_a, index_b;
	unsigned int bits;
	unsigned char length_bytes[MAX_HASH_BIT_COUNT_BYTES];
	unsigned char hmac_pad[MAX_HASH_BLOCK_SIZE];
	unsigned char first_block[MAX_HASH_BLOCK_SIZE];
	unsigned char mac_out[EVP_MAX_MD_SIZE];
	unsigned i, j, md_out_size_u;
	EVP_MD_CTX md_ctx;
	unsigned md_length_size = 8;
	char length_is_big_endian = 1;
	OPENSSL_assert(data_plus_mac_plus_padding_size < 1024*1024);
	switch (EVP_MD_CTX_type(ctx))
		{
		case NID_md5:
			MD5_Init((MD5_CTX*)md_state.c);
			md_final_raw = tls1_md5_final_raw;
			md_transform = (void(*)(void *ctx, const unsigned char *block)) MD5_Transform;
			md_size = 16;
			sslv3_pad_length = 48;
			length_is_big_endian = 0;
			break;
		case NID_sha1:
			SHA1_Init((SHA_CTX*)md_state.c);
			md_final_raw = tls1_sha1_final_raw;
			md_transform = (void(*)(void *ctx, const unsigned char *block)) SHA1_Transform;
			md_size = 20;
			break;
#ifndef OPENSSL_NO_SHA256
		case NID_sha224:
			SHA224_Init((SHA256_CTX*)md_state.c);
			md_final_raw = tls1_sha256_final_raw;
			md_transform = (void(*)(void *ctx, const unsigned char *block)) SHA256_Transform;
			md_size = 224/8;
			break;
		case NID_sha256:
			SHA256_Init((SHA256_CTX*)md_state.c);
			md_final_raw = tls1_sha256_final_raw;
			md_transform = (void(*)(void *ctx, const unsigned char *block)) SHA256_Transform;
			md_size = 32;
			break;
#endif
#ifndef OPENSSL_NO_SHA512
		case NID_sha384:
			SHA384_Init((SHA512_CTX*)md_state.c);
			md_final_raw = tls1_sha512_final_raw;
			md_transform = (void(*)(void *ctx, const unsigned char *block)) SHA512_Transform;
			md_size = 384/8;
			md_block_size = 128;
			md_length_size = 16;
			break;
		case NID_sha512:
			SHA512_Init((SHA512_CTX*)md_state.c);
			md_final_raw = tls1_sha512_final_raw;
			md_transform = (void(*)(void *ctx, const unsigned char *block)) SHA512_Transform;
			md_size = 64;
			md_block_size = 128;
			md_length_size = 16;
			break;
#endif
		default:
			OPENSSL_assert(0);
			if (md_out_size)
				*md_out_size = -1;
			return;
		}
	OPENSSL_assert(md_length_size <= MAX_HASH_BIT_COUNT_BYTES);
	OPENSSL_assert(md_block_size <= MAX_HASH_BLOCK_SIZE);
	OPENSSL_assert(md_size <= EVP_MAX_MD_SIZE);
	header_length = 13;
	if (is_sslv3)
		{
		header_length =
			mac_secret_length +
			sslv3_pad_length +
			8   +
			1   +
			2  ;
		}
	variance_blocks = is_sslv3 ? 2 : 6;
	len = data_plus_mac_plus_padding_size + header_length;
	max_mac_bytes = len - md_size - 1;
	num_blocks = (max_mac_bytes + 1 + md_length_size + md_block_size - 1) / md_block_size;
	num_starting_blocks = 0;
	k = 0;
	mac_end_offset = data_plus_mac_size + header_length - md_size;
	c = mac_end_offset % md_block_size;
	index_a = mac_end_offset / md_block_size;
	index_b = (mac_end_offset + md_length_size) / md_block_size;
	if (num_blocks > variance_blocks + (is_sslv3 ? 1 : 0))
		{
		num_starting_blocks = num_blocks - variance_blocks;
		k = md_block_size*num_starting_blocks;
		}
	bits = 8*mac_end_offset;
	if (!is_sslv3)
		{
		bits += 8*md_block_size;
		memset(hmac_pad, 0, md_block_size);
		OPENSSL_assert(mac_secret_length <= sizeof(hmac_pad));
		memcpy(hmac_pad, mac_secret, mac_secret_length);
		for (i = 0; i < md_block_size; i++)
			hmac_pad[i] ^= 0x36;
		md_transform(md_state.c, hmac_pad);
		}
	if (length_is_big_endian)
		{
		memset(length_bytes,0,md_length_size-4);
		length_bytes[md_length_size-4] = (unsigned char)(bits>>24);
		length_bytes[md_length_size-3] = (unsigned char)(bits>>16);
		length_bytes[md_length_size-2] = (unsigned char)(bits>>8);
		length_bytes[md_length_size-1] = (unsigned char)bits;
		}
	else
		{
		memset(length_bytes,0,md_length_size);
		length_bytes[md_length_size-5] = (unsigned char)(bits>>24);
		length_bytes[md_length_size-6] = (unsigned char)(bits>>16);
		length_bytes[md_length_size-7] = (unsigned char)(bits>>8);
		length_bytes[md_length_size-8] = (unsigned char)bits;
		}
	if (k > 0)
		{
		if (is_sslv3)
			{
			unsigned overhang = header_length-md_block_size;
			md_transform(md_state.c, header);
			memcpy(first_block, header + md_block_size, overhang);
			memcpy(first_block + overhang, data, md_block_size-overhang);
			md_transform(md_state.c, first_block);
			for (i = 1; i < k/md_block_size - 1; i++)
				md_transform(md_state.c, data + md_block_size*i - overhang);
			}
		else
			{
			memcpy(first_block, header, 13);
			memcpy(first_block+13, data, md_block_size-13);
			md_transform(md_state.c, first_block);
			for (i = 1; i < k/md_block_size; i++)
				md_transform(md_state.c, data + md_block_size*i - 13);
			}
		}
	memset(mac_out, 0, sizeof(mac_out));
	for (i = num_starting_blocks; i <= num_starting_blocks+variance_blocks; i++)
		{
		unsigned char block[MAX_HASH_BLOCK_SIZE];
		unsigned char is_block_a = constant_time_eq_8(i, index_a);
		unsigned char is_block_b = constant_time_eq_8(i, index_b);
		for (j = 0; j < md_block_size; j++)
			{
			unsigned char b = 0, is_past_c, is_past_cp1;
			if (k < header_length)
				b = header[k];
			else if (k < data_plus_mac_plus_padding_size + header_length)
				b = data[k-header_length];
			k++;
			is_past_c = is_block_a & constant_time_ge(j, c);
			is_past_cp1 = is_block_a & constant_time_ge(j, c+1);
			b = (b&~is_past_c) | (0x80&is_past_c);
			b = b&~is_past_cp1;
			b &= ~is_block_b | is_block_a;
			if (j >= md_block_size - md_length_size)
				{
				b = (b&~is_block_b) | (is_block_b&length_bytes[j-(md_block_size-md_length_size)]);
				}
			block[j] = b;
			}
		md_transform(md_state.c, block);
		md_final_raw(md_state.c, block);
		for (j = 0; j < md_size; j++)
			mac_out[j] |= block[j]&is_block_b;
		}
	EVP_MD_CTX_init(&md_ctx);
	EVP_DigestInit_ex(&md_ctx, ctx->digest, NULL  );
	if (is_sslv3)
		{
		memset(hmac_pad, 0x5c, sslv3_pad_length);
		EVP_DigestUpdate(&md_ctx, mac_secret, mac_secret_length);
		EVP_DigestUpdate(&md_ctx, hmac_pad, sslv3_pad_length);
		EVP_DigestUpdate(&md_ctx, mac_out, md_size);
		}
	else
		{
		for (i = 0; i < md_block_size; i++)
			hmac_pad[i] ^= 0x6a;
		EVP_DigestUpdate(&md_ctx, hmac_pad, md_block_size);
		EVP_DigestUpdate(&md_ctx, mac_out, md_size);
		}
	EVP_DigestFinal(&md_ctx, md_out, &md_out_size_u);
	if (md_out_size)
		*md_out_size = md_out_size_u;
	EVP_MD_CTX_cleanup(&md_ctx);
	}
['int n_ssl3_mac(SSL *ssl, unsigned char *md, int send)\n\t{\n\tSSL3_RECORD *rec;\n\tunsigned char *mac_sec,*seq;\n\tEVP_MD_CTX md_ctx;\n\tconst EVP_MD_CTX *hash;\n\tunsigned char *p,rec_char;\n\tsize_t md_size;\n\tint npad;\n\tint t;\n\tif (send)\n\t\t{\n\t\trec= &(ssl->s3->wrec);\n\t\tmac_sec= &(ssl->s3->write_mac_secret[0]);\n\t\tseq= &(ssl->s3->write_sequence[0]);\n\t\thash=ssl->write_hash;\n\t\t}\n\telse\n\t\t{\n\t\trec= &(ssl->s3->rrec);\n\t\tmac_sec= &(ssl->s3->read_mac_secret[0]);\n\t\tseq= &(ssl->s3->read_sequence[0]);\n\t\thash=ssl->read_hash;\n\t\t}\n\tt=EVP_MD_CTX_size(hash);\n\tif (t < 0)\n\t\treturn -1;\n\tmd_size=t;\n\tnpad=(48/md_size)*md_size;\n\tif (!send &&\n\t    EVP_CIPHER_CTX_mode(ssl->enc_read_ctx) == EVP_CIPH_CBC_MODE &&\n\t    ssl3_cbc_record_digest_supported(hash))\n\t\t{\n\t\tunsigned char header[75];\n\t\tunsigned j = 0;\n\t\tmemcpy(header+j, mac_sec, md_size);\n\t\tj += md_size;\n\t\tmemcpy(header+j, ssl3_pad_1, npad);\n\t\tj += npad;\n\t\tmemcpy(header+j, seq, 8);\n\t\tj += 8;\n\t\theader[j++] = rec->type;\n\t\theader[j++] = rec->length >> 8;\n\t\theader[j++] = rec->length & 0xff;\n\t\tssl3_cbc_digest_record(\n\t\t\thash,\n\t\t\tmd, &md_size,\n\t\t\theader, rec->input,\n\t\t\trec->length + md_size, rec->orig_len,\n\t\t\tmac_sec, md_size,\n\t\t\t1  );\n\t\t}\n\telse\n\t\t{\n\t\tunsigned int md_size_u;\n\t\tEVP_MD_CTX_init(&md_ctx);\n\t\tEVP_MD_CTX_copy_ex( &md_ctx,hash);\n\t\tEVP_DigestUpdate(&md_ctx,mac_sec,md_size);\n\t\tEVP_DigestUpdate(&md_ctx,ssl3_pad_1,npad);\n\t\tEVP_DigestUpdate(&md_ctx,seq,8);\n\t\trec_char=rec->type;\n\t\tEVP_DigestUpdate(&md_ctx,&rec_char,1);\n\t\tp=md;\n\t\ts2n(rec->length,p);\n\t\tEVP_DigestUpdate(&md_ctx,md,2);\n\t\tEVP_DigestUpdate(&md_ctx,rec->input,rec->length);\n\t\tEVP_DigestFinal_ex( &md_ctx,md,NULL);\n\t\tEVP_MD_CTX_copy_ex( &md_ctx,hash);\n\t\tEVP_DigestUpdate(&md_ctx,mac_sec,md_size);\n\t\tEVP_DigestUpdate(&md_ctx,ssl3_pad_2,npad);\n\t\tEVP_DigestUpdate(&md_ctx,md,md_size);\n\t\tEVP_DigestFinal_ex( &md_ctx,md,&md_size_u);\n\t\tmd_size = md_size_u;\n\t\tEVP_MD_CTX_cleanup(&md_ctx);\n\t}\n\tssl3_record_sequence_update(seq);\n\treturn(md_size);\n\t}', 'void ssl3_cbc_digest_record(\n\tconst EVP_MD_CTX *ctx,\n\tunsigned char* md_out,\n\tsize_t* md_out_size,\n\tconst unsigned char header[13],\n\tconst unsigned char *data,\n\tsize_t data_plus_mac_size,\n\tsize_t data_plus_mac_plus_padding_size,\n\tconst unsigned char *mac_secret,\n\tunsigned mac_secret_length,\n\tchar is_sslv3)\n\t{\n\tunion {\tdouble align;\n\t\tunsigned char c[sizeof(LARGEST_DIGEST_CTX)]; } md_state;\n\tvoid (*md_final_raw)(void *ctx, unsigned char *md_out);\n\tvoid (*md_transform)(void *ctx, const unsigned char *block);\n\tunsigned md_size, md_block_size = 64;\n\tunsigned sslv3_pad_length = 40, header_length, variance_blocks,\n\t\t len, max_mac_bytes, num_blocks,\n\t\t num_starting_blocks, k, mac_end_offset, c, index_a, index_b;\n\tunsigned int bits;\n\tunsigned char length_bytes[MAX_HASH_BIT_COUNT_BYTES];\n\tunsigned char hmac_pad[MAX_HASH_BLOCK_SIZE];\n\tunsigned char first_block[MAX_HASH_BLOCK_SIZE];\n\tunsigned char mac_out[EVP_MAX_MD_SIZE];\n\tunsigned i, j, md_out_size_u;\n\tEVP_MD_CTX md_ctx;\n\tunsigned md_length_size = 8;\n\tchar length_is_big_endian = 1;\n\tOPENSSL_assert(data_plus_mac_plus_padding_size < 1024*1024);\n\tswitch (EVP_MD_CTX_type(ctx))\n\t\t{\n\t\tcase NID_md5:\n\t\t\tMD5_Init((MD5_CTX*)md_state.c);\n\t\t\tmd_final_raw = tls1_md5_final_raw;\n\t\t\tmd_transform = (void(*)(void *ctx, const unsigned char *block)) MD5_Transform;\n\t\t\tmd_size = 16;\n\t\t\tsslv3_pad_length = 48;\n\t\t\tlength_is_big_endian = 0;\n\t\t\tbreak;\n\t\tcase NID_sha1:\n\t\t\tSHA1_Init((SHA_CTX*)md_state.c);\n\t\t\tmd_final_raw = tls1_sha1_final_raw;\n\t\t\tmd_transform = (void(*)(void *ctx, const unsigned char *block)) SHA1_Transform;\n\t\t\tmd_size = 20;\n\t\t\tbreak;\n#ifndef OPENSSL_NO_SHA256\n\t\tcase NID_sha224:\n\t\t\tSHA224_Init((SHA256_CTX*)md_state.c);\n\t\t\tmd_final_raw = tls1_sha256_final_raw;\n\t\t\tmd_transform = (void(*)(void *ctx, const unsigned char *block)) SHA256_Transform;\n\t\t\tmd_size = 224/8;\n\t\t\tbreak;\n\t\tcase NID_sha256:\n\t\t\tSHA256_Init((SHA256_CTX*)md_state.c);\n\t\t\tmd_final_raw = tls1_sha256_final_raw;\n\t\t\tmd_transform = (void(*)(void *ctx, const unsigned char *block)) SHA256_Transform;\n\t\t\tmd_size = 32;\n\t\t\tbreak;\n#endif\n#ifndef OPENSSL_NO_SHA512\n\t\tcase NID_sha384:\n\t\t\tSHA384_Init((SHA512_CTX*)md_state.c);\n\t\t\tmd_final_raw = tls1_sha512_final_raw;\n\t\t\tmd_transform = (void(*)(void *ctx, const unsigned char *block)) SHA512_Transform;\n\t\t\tmd_size = 384/8;\n\t\t\tmd_block_size = 128;\n\t\t\tmd_length_size = 16;\n\t\t\tbreak;\n\t\tcase NID_sha512:\n\t\t\tSHA512_Init((SHA512_CTX*)md_state.c);\n\t\t\tmd_final_raw = tls1_sha512_final_raw;\n\t\t\tmd_transform = (void(*)(void *ctx, const unsigned char *block)) SHA512_Transform;\n\t\t\tmd_size = 64;\n\t\t\tmd_block_size = 128;\n\t\t\tmd_length_size = 16;\n\t\t\tbreak;\n#endif\n\t\tdefault:\n\t\t\tOPENSSL_assert(0);\n\t\t\tif (md_out_size)\n\t\t\t\t*md_out_size = -1;\n\t\t\treturn;\n\t\t}\n\tOPENSSL_assert(md_length_size <= MAX_HASH_BIT_COUNT_BYTES);\n\tOPENSSL_assert(md_block_size <= MAX_HASH_BLOCK_SIZE);\n\tOPENSSL_assert(md_size <= EVP_MAX_MD_SIZE);\n\theader_length = 13;\n\tif (is_sslv3)\n\t\t{\n\t\theader_length =\n\t\t\tmac_secret_length +\n\t\t\tsslv3_pad_length +\n\t\t\t8   +\n\t\t\t1   +\n\t\t\t2  ;\n\t\t}\n\tvariance_blocks = is_sslv3 ? 2 : 6;\n\tlen = data_plus_mac_plus_padding_size + header_length;\n\tmax_mac_bytes = len - md_size - 1;\n\tnum_blocks = (max_mac_bytes + 1 + md_length_size + md_block_size - 1) / md_block_size;\n\tnum_starting_blocks = 0;\n\tk = 0;\n\tmac_end_offset = data_plus_mac_size + header_length - md_size;\n\tc = mac_end_offset % md_block_size;\n\tindex_a = mac_end_offset / md_block_size;\n\tindex_b = (mac_end_offset + md_length_size) / md_block_size;\n\tif (num_blocks > variance_blocks + (is_sslv3 ? 1 : 0))\n\t\t{\n\t\tnum_starting_blocks = num_blocks - variance_blocks;\n\t\tk = md_block_size*num_starting_blocks;\n\t\t}\n\tbits = 8*mac_end_offset;\n\tif (!is_sslv3)\n\t\t{\n\t\tbits += 8*md_block_size;\n\t\tmemset(hmac_pad, 0, md_block_size);\n\t\tOPENSSL_assert(mac_secret_length <= sizeof(hmac_pad));\n\t\tmemcpy(hmac_pad, mac_secret, mac_secret_length);\n\t\tfor (i = 0; i < md_block_size; i++)\n\t\t\thmac_pad[i] ^= 0x36;\n\t\tmd_transform(md_state.c, hmac_pad);\n\t\t}\n\tif (length_is_big_endian)\n\t\t{\n\t\tmemset(length_bytes,0,md_length_size-4);\n\t\tlength_bytes[md_length_size-4] = (unsigned char)(bits>>24);\n\t\tlength_bytes[md_length_size-3] = (unsigned char)(bits>>16);\n\t\tlength_bytes[md_length_size-2] = (unsigned char)(bits>>8);\n\t\tlength_bytes[md_length_size-1] = (unsigned char)bits;\n\t\t}\n\telse\n\t\t{\n\t\tmemset(length_bytes,0,md_length_size);\n\t\tlength_bytes[md_length_size-5] = (unsigned char)(bits>>24);\n\t\tlength_bytes[md_length_size-6] = (unsigned char)(bits>>16);\n\t\tlength_bytes[md_length_size-7] = (unsigned char)(bits>>8);\n\t\tlength_bytes[md_length_size-8] = (unsigned char)bits;\n\t\t}\n\tif (k > 0)\n\t\t{\n\t\tif (is_sslv3)\n\t\t\t{\n\t\t\tunsigned overhang = header_length-md_block_size;\n\t\t\tmd_transform(md_state.c, header);\n\t\t\tmemcpy(first_block, header + md_block_size, overhang);\n\t\t\tmemcpy(first_block + overhang, data, md_block_size-overhang);\n\t\t\tmd_transform(md_state.c, first_block);\n\t\t\tfor (i = 1; i < k/md_block_size - 1; i++)\n\t\t\t\tmd_transform(md_state.c, data + md_block_size*i - overhang);\n\t\t\t}\n\t\telse\n\t\t\t{\n\t\t\tmemcpy(first_block, header, 13);\n\t\t\tmemcpy(first_block+13, data, md_block_size-13);\n\t\t\tmd_transform(md_state.c, first_block);\n\t\t\tfor (i = 1; i < k/md_block_size; i++)\n\t\t\t\tmd_transform(md_state.c, data + md_block_size*i - 13);\n\t\t\t}\n\t\t}\n\tmemset(mac_out, 0, sizeof(mac_out));\n\tfor (i = num_starting_blocks; i <= num_starting_blocks+variance_blocks; i++)\n\t\t{\n\t\tunsigned char block[MAX_HASH_BLOCK_SIZE];\n\t\tunsigned char is_block_a = constant_time_eq_8(i, index_a);\n\t\tunsigned char is_block_b = constant_time_eq_8(i, index_b);\n\t\tfor (j = 0; j < md_block_size; j++)\n\t\t\t{\n\t\t\tunsigned char b = 0, is_past_c, is_past_cp1;\n\t\t\tif (k < header_length)\n\t\t\t\tb = header[k];\n\t\t\telse if (k < data_plus_mac_plus_padding_size + header_length)\n\t\t\t\tb = data[k-header_length];\n\t\t\tk++;\n\t\t\tis_past_c = is_block_a & constant_time_ge(j, c);\n\t\t\tis_past_cp1 = is_block_a & constant_time_ge(j, c+1);\n\t\t\tb = (b&~is_past_c) | (0x80&is_past_c);\n\t\t\tb = b&~is_past_cp1;\n\t\t\tb &= ~is_block_b | is_block_a;\n\t\t\tif (j >= md_block_size - md_length_size)\n\t\t\t\t{\n\t\t\t\tb = (b&~is_block_b) | (is_block_b&length_bytes[j-(md_block_size-md_length_size)]);\n\t\t\t\t}\n\t\t\tblock[j] = b;\n\t\t\t}\n\t\tmd_transform(md_state.c, block);\n\t\tmd_final_raw(md_state.c, block);\n\t\tfor (j = 0; j < md_size; j++)\n\t\t\tmac_out[j] |= block[j]&is_block_b;\n\t\t}\n\tEVP_MD_CTX_init(&md_ctx);\n\tEVP_DigestInit_ex(&md_ctx, ctx->digest, NULL  );\n\tif (is_sslv3)\n\t\t{\n\t\tmemset(hmac_pad, 0x5c, sslv3_pad_length);\n\t\tEVP_DigestUpdate(&md_ctx, mac_secret, mac_secret_length);\n\t\tEVP_DigestUpdate(&md_ctx, hmac_pad, sslv3_pad_length);\n\t\tEVP_DigestUpdate(&md_ctx, mac_out, md_size);\n\t\t}\n\telse\n\t\t{\n\t\tfor (i = 0; i < md_block_size; i++)\n\t\t\thmac_pad[i] ^= 0x6a;\n\t\tEVP_DigestUpdate(&md_ctx, hmac_pad, md_block_size);\n\t\tEVP_DigestUpdate(&md_ctx, mac_out, md_size);\n\t\t}\n\tEVP_DigestFinal(&md_ctx, md_out, &md_out_size_u);\n\tif (md_out_size)\n\t\t*md_out_size = md_out_size_u;\n\tEVP_MD_CTX_cleanup(&md_ctx);\n\t}']