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;
}