クライアント(IE)からの"GET /index.html HTML/1.1..."はなぜか"G"と"ET.."に分かれ暗号化されています。
最初を復号するとG(0x47)+MAC+PADDINGというPlaintextになります。

"G"という文字とclient_macからサーバ側で計算したMACが、d4 90... と一致するか検証します。


詳しい説明はここ
サーバから送信する時も同じ方法でMACを計算後、Plaintxt+MAC+PADを暗号化します。



Wiresharkのダンプは以下のようになっている。

Client MAC key[20]:

ec 3c f8 75 93 fe 63 11 1a cf 09 3a 87 16 50 78
1f b0 08 32

...
Plaintext[32]:

47 d4 90 77 4e 8a ce 95 0e e1 03 af b3 79 e7 58
1d df ae 47 46 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a

ssl_decrypt_record found padding 10 final len 21
checking mac (len 1, version 301, ct 23 seq 1)
tls_check_mac mac type:SHA1 md 2
Mac[20]:

d4 90 77 4e 8a ce 95 0e e1 03 af b3 79 e7 58 1d
df ae 47 46

ssl_decrypt_record: mac ok
...
decrypted app data fragment[1]:

47 G


この計算をC#で。

byte data = {0x47,0xd4,0x90,0x77,0x4e,0x8a,0xce,0x95,0x0e,0xe1,0x03,0xaf,0xb3,0x79,0xe7,0x58,0x1d,0xdf,0xae,0x47,0x46,0x0a,0x0a,0x0a,0x0a,0x0a,0x0a,0x0a,0x0a,0x0a,0x0a,0x0a};
byte
client_mac_ = { 0xec, 0x3c, 0xf8, 0x75, 0x93, 0xfe, 0x63, 0x11, 0x1a, 0xcf, 0x09, 0x3a, 0x87, 0x16, 0x50, 0x78, 0x1f, 0xb0, 0x08, 0x32 };
int client_seqno_ = 1;
byte ct = 23;
int decrypted_data_len = data.Length - 20 - data[data.Length - 1] - 1; // data is decrypted_data + mac(20) + pad(n) + pad_len(1)

byte txt = new byte[decrypted_data_len];
for( int i = 0; i < decrypted_data_len; i++ )
txt[i] = data[i];

var mac = calcmac(client_mac_, txt, client_seqno_++, ct); // txtは'G'の1文字のみ。

// macは0xd4,0x90,0x77,0x4e,0x8a,0xce,0x95,0x0e,0xe1,0x03,0xaf,0xb3,0x79,0xe7,0x58,0x1d,0xdf,0xae,0x47,0x46 となる


/////////////////////////////////////////////////////////////////////////////////////////////////////
using System;
using System.IO;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;

static byte calcmac(byte client_mac, byte data, long client_seqno, byte ContentType)
{
MemoryStream ms = new MemoryStream();
int len = data.Length;

// longをnetwork byte配列へ
byte rdata = new byte[8]; // 8:sizeof(long)
for( int i =0; i < 8; i++ )
rdata[7-i] = (byte)((client_seqno >> i*8) & 0xFF);

ms.Write(rdata, 0, 8);

// shortをnetwork byte配列へ
byteslen = new byte[2]; // 2:sizeof(short)
for (int i = 0; i < 2; i++)
slen[1-i] = (byte)*1;
}

static byte xor( byte a, byte b )
{
System.Diagnostics.Debug.Assert( a.Length == b.Length );

byte r = new byte[a.Length];

for (int i = 0; i < a.Length; i++)
r[i] = (byte)(a[i] ^ b[i]);// xor

return r;
}
static byte memset( byte a, byte val )
{
for (int i = 0; i < a.Length; i++)
a[i] = val;
return a;
}
static byte ComputeHashSHA1(byte data)
{
SHA1CryptoServiceProvider mm = new SHA1CryptoServiceProvider();
return mm.ComputeHash(data);
}

static byte TLSCalcHmac( byte macsecret, byte data )
{
byte
buf = new byte[64];
buf = memset( buf, 0x36 );

byte buf2 = new byte[64];
buf2 = memset( buf2, 0x0 );

for( int i = 0; i < macsecret.Length; i++ )
buf2[i] = macsecret[i];

var a = xor( buf, buf2 );
buf = memset( buf, 0x5c );
var b = xor( buf, buf2 );

MemoryStream h3 = new MemoryStream();
h3.Write( a, 0, a.Length );
h3.Write( data, 0, data.Length );

byte h3r = ComputeHashSHA1( h3.ToArray() );

MemoryStream h4 = new MemoryStream();
h4.Write(b, 0, b.Length);
h4.Write(h3r, 0, h3r.Length);
return ComputeHashSHA1( h4.ToArray() );
}

*1:len >> i*8) & 0xFF); byte[] info = new byte[5]; info[0] = ContentType; info[1] = 0x03; info[2] = 0x01; // SSL3.1 is TSL1.0 info[3] = slen[0]; info[4] = slen[1]; ms.Write( info, 0, 5 ); ms.Write( data, 0, len ); return TLSCalcHmac(client_mac, ms.ToArray(