HTTPSの実装 TSL 5


C#でPRFの実装しました。データ元はwirsharのSSL debug fileです。
pre master secretからmaster_secretさらにmac,key,ivを取り出せます。
PRFの詳しい説明はここにあります。


from wireshark debug file.

ssl_generate_keyring_material:PRF(pre_master_secret)
pre master secret[48]:

03 01 61 18 fe 4d b1 5a bc 6d 88 f5 d7 9a 7a dd
bc 2a 33 bf 0c 7c 82 ae e5 7c e5 86 14 ff 18 d5
fa 3f df df 80 01 1d d0 f1 f2 3b e7 e6 26 df d9

client random[32]:

51 b3 de 65 2a ee 66 71 5a 76 5a 5c 2d e5 27 b1
fe 1d a0 3e 69 00 9b f8 37 35 eb ff b6 e8 07 06

server random[32]:

51 b3 de 57 8d 58 11 99 72 fd b2 92 2f 8a 73 6c
8d 90 70 30 e2 e4 5f 3d ea dc c6 b5 59 f2 ad e5

このデータをC#で変換。

byte pre_master_secret = {0x03,0x01,0x61,0x18,0xfe,0x4d,0xb1,0x5a,0xbc,0x6d,0x88,0xf5,0xd7,0x9a,0x7a,0xdd,0xbc,0x2a,0x33,0xbf,0x0c,0x7c,0x82,0xae,0xe5,0x7c,0xe5,0x86,0x14,0xff,0x18,0xd5,0xfa,0x3f,0xdf,0xdf,0x80,0x01,0x1d,0xd0,0xf1,0xf2,0x3b,0xe7,0xe6,0x26,0xdf,0xd9};
byte
client_random = {0x51,0xb3,0xde,0x65,0x2a,0xee,0x66,0x71,0x5a,0x76,0x5a,0x5c,0x2d,0xe5,0x27,0xb1,0xfe,0x1d,0xa0,0x3e,0x69,0x00,0x9b,0xf8,0x37,0x35,0xeb,0xff,0xb6,0xe8,0x07,0x06};
byte [] server_random = {0x51,0xb3,0xde,0x57,0x8d,0x58,0x11,0x99,0x72,0xfd,0xb2,0x92,0x2f,0x8a,0x73,0x6c,0x8d,0x90,0x70,0x30,0xe2,0xe4,0x5f,0x3d,0xea,0xdc,0xc6,0xb5,0x59,0xf2,0xad,0xe5};

var master_secret = Tsl.PRF(pre_master_secret, System.Text.Encoding.ASCII.GetBytes("master secret"), Tsl.marge(client_random, server_random), 4);

master_secretは下と一致します。

master secret[48]:

5b 58 d6 41 df e4 ac ba 0e 07 cd b5 72 72 21 1e
48 69 53 d0 3b 6d 51 2b fd 35 7b 78 c8 cf b4 74
69 23 b2 fa 49 bf e1 a5 26 64 aa 8b 76 e0 51 d2

そして、master_secretからkeyblockを計算。

var keyblock = Tsl.PRF(master_secret, System.Text.Encoding.ASCII.GetBytes("key expansion"), Tsl.marge(server_random, client_random), 10);

Wiresharkのデータと一致します。

Client MAC key[20]:

d2 4d 4e 98 bb 6c a9 d1 58 c1 41 6a a3 81 89 39
64 33 d6 6c

Server MAC key[20]:

5c a7 f7 4e 68 84 5a ee 30 ab 6e 6e f9 d4 c7 a0
44 96 c6 9e

Client Write key[16]:

57 5e 62 c3 b1 77 86 69 c6 96 49 75 bd d2 89 07

Server Write key[16]:

13 7a 1e f1 7e 30 40 68 f5 1c a8 c4 77 3c 65 23

Client Write IV[16]:

bd a6 65 21 17 30 b8 8c 28 84 b8 f8 49 4b 59 fd

Server Write IV[16]:

0f b8 dd c1 ef 72 36 2e 5c 16 0c 05 cf cb 03 60


//--------------------------------------------------------------------------------------------------------
using System;
using System.Text;
using System.Security.Cryptography;
using System.IO;
namespace rsatest
{
public class Tsl
{
static byte HMAC_MD5(byte d, byte key)
{
var sh = new HMACMD5(key);
return sh.ComputeHash(d);
}
static byte
HMAC_SHA1(byte d, byte key)
{
var sh = new HMACSHA1(key);
return sh.ComputeHash(d);
}

static public byte marge(byte a, byte b)
{
MemoryStream ms = new MemoryStream();
ms.Write(a, 0, a.Length);
ms.Write(b, 0, b.Length);
return ms.ToArray();
}

static byte ShortenData(byte data, int pos, int len)
{
MemoryStream ms = new MemoryStream();
ms.Write(data, pos, len);
return ms.ToArray();
}

static byte P_MD5(byte sec, byte seed, int cnt)
{
byte aa = new byte[cnt];
byte
bb = new byte[cnt];

aa[0] = HMAC_MD5(seed, sec);
for (int i = 1; i < cnt; i++)
{
bb[i] = HMAC_MD5(marge(aa[i - 1], seed), sec);
aa[i] = HMAC_MD5(aa[i - 1], sec);
}

MemoryStream ms = new MemoryStream();

for (int i = 1; i < cnt; i++)
{
ms.Write(bb[i], 0, bb[i].Length);
}
return ms.ToArray();

}
static byte P_SHA1(byte sec, byte seed, int cnt)
{
byte
aa = new byte[cnt];
byte bb = new byte[cnt];

aa[0] = HMAC_SHA1(seed, sec);
for (int i = 1; i < cnt; i++)
{
bb[i] = HMAC_SHA1(marge(aa[i - 1], seed), sec);
aa[i] = HMAC_SHA1(aa[i - 1], sec);
}

MemoryStream ms = new MemoryStream();

for (int i = 1; i < cnt; i++)
{
ms.Write(bb[i], 0, bb[i].Length);
}
return ms.ToArray();
}

static public byte PRF(byte secret, byte label, byte seed, int loopcnt)
{
int len = secret.Length;
var S1 = ShortenData(secret, 0, len/2);
var S2 = ShortenData(secret, len / 2, len / 2);

byte md = P_MD5(S1, marge(label, seed), 4); // 16BYTE
byte [] sh = P_SHA1(S2, marge(label, seed), 4); // 20BYTE

var r = new byte[len];

int cnt = Math.Min( len, md.Length );
for (int i = 0; i < cnt; i++)
{
r[i] = (byte)(md[i] ^ sh[i]);// XOR
}
return r;
}