gpt4 book ai didi

C# TLS 1.1 实现

转载 作者:太空宇宙 更新时间:2023-11-03 13:42:00 25 4
gpt4 key购买 nike

一段时间以来,我一直在拼命地尝试在我的应用程序中实现 TLS 1.1。这背后的原因是使用了 SocketType.Raw 套接字,因此我无法使用 SslStream 或其他更高级别的类。

到目前为止,我一直停留在 TLS 握手协议(protocol)中的 Finished 消息 - 继续在服务器响应中接收 bad_record_mac(20)。密码套件是 0x0005 - TLS_RSA_WITH_RC4_128_SHA。

下面是一些关于正在发生的事情的示例代码:

    byte[] client_random, server_random = new byte[28];
byte[] pre_master_secret, master_secret;
byte[] client_write_MAC_secret, server_write_MAC_secret, client_write_key, server_write_key;
byte[] handshake_messages, verify_data;

RSACryptoServiceProvider rsa;
List<X509Certificate2> certificates = new List<X509Certificate2>();

//certificates are added
rsa = (RSACryptoServiceProvider)certificates.First().PublicKey.Key;

private byte[] ClientKeyExchange()
{
pre_master_secret = new byte[48];
(new Random()).NextBytes(pre_master_secret);

//version 0302 for TLS 1.1
pre_master_secret[0] = 3;
pre_master_secret[1] = 2;

byte[] cryptedData = rsa.Encrypt(pre_master_secret, false);
//"1603020086"
string tmp_string = "100000820080" + Utils.BitConverter.ToString(cryptedData).Replace("-", "");
AddHandShakeData(Utils.BitConverter.StringToByteArray(tmp_string));
tmp_string =
"1603020086"
+ tmp_string
+ "140302000101" //Cipher Change Spec
+ "";

return Utils.BitConverter.StringToByteArray(tmp_string);
}

private void ComputeMasterSecret()
{
byte[] label = Utils.BitConverter.StringToByteArray(Utils.BitConverter.ConvertStringToHex("master secret", Encoding.ASCII));

byte[] seed = new byte[client_random.Length + server_random.Length];
Buffer.BlockCopy(client_random, 0, seed, 0, client_random.Length);
Buffer.BlockCopy(server_random, 0, seed, client_random.Length, server_random.Length);

master_secret = PRF(pre_master_secret, label, seed, 48);
}

private void ComputeKeys()
{
byte[] label = Utils.BitConverter.StringToByteArray(Utils.BitConverter.ConvertStringToHex("key expansion", Encoding.ASCII));

byte[] seed = new byte[client_random.Length + server_random.Length];
Buffer.BlockCopy(client_random, 0, seed, 0, client_random.Length);
Buffer.BlockCopy(server_random, 0, seed, client_random.Length, server_random.Length);

byte[] key_material = PRF(master_secret, label, seed, 72);

client_write_MAC_secret = new byte[20];
Buffer.BlockCopy(key_material, 0, client_write_MAC_secret, 0, 20);
server_write_MAC_secret = new byte[20];
Buffer.BlockCopy(key_material, 20, server_write_MAC_secret, 0, 20);
client_write_key = new byte[16];
Buffer.BlockCopy(key_material, 40, client_write_key, 0, 16);
server_write_key = new byte[16];
Buffer.BlockCopy(key_material, 56, server_write_key, 0, 16);
}

private void ComputeVerifyData()
{
byte[] label = Utils.BitConverter.StringToByteArray(Utils.BitConverter.ConvertStringToHex("client finished", Encoding.ASCII));

SHA1 sha1 = SHA1.Create();
MD5 md5 = MD5.Create();
md5.ComputeHash(handshake_messages);
sha1.ComputeHash(handshake_messages);

byte[] seed = new byte[md5.HashSize / 8 + sha1.HashSize / 8];
Buffer.BlockCopy(md5.Hash, 0, seed, 0, md5.HashSize / 8);
Buffer.BlockCopy(sha1.Hash, 0, seed, md5.HashSize / 8, sha1.HashSize / 8);

verify_data = PRF(master_secret, label, seed, 12);
}

private byte[] PRF(byte[] secret, byte[] label, byte[] seed, int output_size)
{
int md5_iterations = (int)Math.Ceiling((double)output_size / 16),
sha1_iterations = (int)Math.Ceiling((double)output_size / 20);

byte[] md5_data = new byte[output_size],
sha1_data = new byte[output_size];

//особое колдунство для нечетного числа
byte[] secret_1 = new byte[(int)Math.Ceiling((double)secret.Length / 2)],
secret_2 = new byte[(int)Math.Ceiling((double)secret.Length / 2)];
Buffer.BlockCopy(secret, 0, secret_1, 0, secret_1.Length);
Buffer.BlockCopy(secret, secret.Length / 2, secret_2, 0, secret_2.Length);

byte[] A = new byte[label.Length + seed.Length];
Buffer.BlockCopy(label, 0, A, 0, label.Length);
Buffer.BlockCopy(seed, 0, A, label.Length, seed.Length);

byte[] tmp = new byte[md5_iterations * 16];

//A(1) ?
//A = P_MD5(secret_1, A);

for (int i = 0; i < md5_iterations; i++)
{
A = P_MD5(secret_1, A);
Buffer.BlockCopy(A, 0, tmp, i * A.Length, A.Length);
}
Buffer.BlockCopy(tmp, 0, md5_data, 0, md5_data.Length); //output_size = md5_data.Length

tmp = new byte[sha1_iterations * 20];

//does it have to start with A(1) ?
//A = P_SHA1(secret_2, A);


for (int i = 0; i < sha1_iterations; i++)
{
A = P_SHA1(secret_2, A);
Buffer.BlockCopy(A, 0, tmp, i * A.Length, A.Length);
}
Buffer.BlockCopy(tmp, 0, sha1_data, 0, sha1_data.Length); //output_size = sha1_data.Length

for (int i = 0; i < output_size; i++)
md5_data[i] = (byte)(md5_data[i] ^ sha1_data[i]);

return md5_data;
}

private byte[] P_MD5(byte[] secret /*это ключ?*/, byte[] seed /*это дата?*/)
{
HMACMD5 HMD5 = new HMACMD5(secret);
HMD5.ComputeHash(seed);
return HMD5.Hash;
}

private byte[] P_SHA1(byte[] secret /*это ключ?*/, byte[] seed /*это дата?*/)
{
HMACSHA1 HSHA1 = new HMACSHA1(secret);
HSHA1.ComputeHash(seed);
return HSHA1.Hash;
}

private byte[] MAC(byte[] secret, byte[] data)
{
byte[] secret_64 = new byte[64];
Buffer.BlockCopy(secret, 0, secret_64, 0, secret.Length);

for (int i = 0; i < 64; i++)
secret_64[i] = (byte)(secret_64[i] ^ (byte)54);

byte[] xor_output_data = new byte[64 + data.Length];
Buffer.BlockCopy(secret_64, 0, xor_output_data, 0, 64);
Buffer.BlockCopy(data, 0, xor_output_data, 64, data.Length);

SHA1 sha1 = SHA1.Create();
sha1.ComputeHash(xor_output_data);

secret_64 = new byte[64];
Buffer.BlockCopy(secret, 0, secret_64, 0, secret.Length);

for (int i = 0; i < 64; i++)
secret_64[i] = (byte)(secret_64[i] ^ (byte)92);

xor_output_data = new byte[64 + sha1.HashSize / 8];
Buffer.BlockCopy(secret_64, 0, xor_output_data, 0, 64);
Buffer.BlockCopy(sha1.Hash, 0, xor_output_data, 64, sha1.HashSize / 8);

sha1.ComputeHash(xor_output_data);

return sha1.Hash;
}

public void RC4(ref Byte[] bytes, Byte[] key)
{
Byte[] s = new Byte[128];
Byte[] k = new Byte[128];
Byte temp;
int i, j;

for (i = 0; i < 128; i++)
{
s[i] = (Byte)i;
k[i] = key[i % key.GetLength(0)];
}

j = 0;
for (i = 0; i < 128; i++)
{
j = (j + s[i] + k[i]) % 128;
temp = s[i];
s[i] = s[j];
s[j] = temp;
}

i = j = 0;
for (int x = 0; x < bytes.GetLength(0); x++)
{
i = (i + 1) % 128;
j = (j + s[i]) % 128;
temp = s[i];
s[i] = s[j];
s[j] = temp;
int t = (s[i] + s[j]) % 128;
bytes[x] ^= s[t];
}
}

显然,阅读这么多代码并不是打发时间的最佳方式,所以我想补充一些问题,希望能对您有所帮助:

HMAC_MD5 和 HMAC_SHA1 - 在 .Net 实现中,它们采用 key 并采用输入 byte[] 来计算散列。根据RFC4346 :首先,我们定义一个数据扩展函数,P_hash(secret, data)它使用单个散列函数将 secret 和种子扩展为任意数量的输出:

   P_hash(secret, seed) = HMAC_hash(secret, A(1) + seed) +
HMAC_hash(secret, A(2) + seed) +
HMAC_hash(secret, A(3) + seed) + ...

Where + indicates concatenation.

A() is defined as:

A(0) = seed
A(i) = HMAC_hash(secret, A(i-1))

什么是种子?我们从中计算哈希值的数据吗? secret =关键,到目前为止我明白了。另外,我们是否以 A(1) 开始 P_hash?

提前致谢!

最佳答案

种子是 Client_random + Server_random。您需要从握手的前面步骤中保留它们,即 client_hello 和 server_hello。

A(0) = seed 
A(i) = HMAC_hash(secret,A(i-1)) for i>0

A()函数的输出由A(1)、A(2)、A(3)...组成

关于C# TLS 1.1 实现,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17582210/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com