.net - C# TLS 1.1 Implementation -


for time i've been bit desperately trying implement tls 1.1 in application. reason behind usage of sockettype.raw sockets, no sslstream or other higher-level classes available me.

so far i'm stuck @ finished message in tls handshake protocol - keep on receiving bad_record_mac(20) in server response. cipher suite 0x0005 - tls_rsa_with_rc4_128_sha.

here's sample code on what's happening:

    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 added     rsa = (rsacryptoserviceprovider)certificates.first().publickey.key;      private byte[] clientkeyexchange()     {         pre_master_secret = new byte[48];         (new random()).nextbytes(pre_master_secret);          //version 0302 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[] = 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);          (int = 0; < md5_iterations; i++)         {             = p_md5(secret_1, a);             buffer.blockcopy(a, 0, tmp, * 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 have start a(1) ?         //a = p_sha1(secret_2, a);           (int = 0; < sha1_iterations; i++)         {             = p_sha1(secret_2, a);             buffer.blockcopy(a, 0, tmp, * a.length, a.length);         }         buffer.blockcopy(tmp, 0, sha1_data, 0, sha1_data.length); //output_size = sha1_data.length          (int = 0; < 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);          (int = 0; < 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);          (int = 0; < 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;          (i = 0; < 128; i++)         {             s[i] = (byte)i;             k[i] = key[i % key.getlength(0)];         }          j = 0;         (i = 0; < 128; i++)         {             j = (j + s[i] + k[i]) % 128;             temp = s[i];             s[i] = s[j];             s[j] = temp;         }          = j = 0;         (int x = 0; x < bytes.getlength(0); x++)         {             = (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];         }     } 

obviously, reading such bunch of code ain't being best way spend time, i'd add questions that, hopefully, can lot:

hmac_md5 , hmac_sha1 - in .net implementation take key , take input byte[] compute hash from. according rfc4346: first, define data expansion function, p_hash(secret, data) uses single hash function expand secret , seed arbitrary quantity of output:

   p_hash(secret, seed) = hmac_hash(secret, a(1) + seed) +                           hmac_hash(secret, a(2) + seed) +                           hmac_hash(secret, a(3) + seed) + ...     + indicates concatenation.     a() defined as:     a(0) = seed    a(i) = hmac_hash(secret, a(i-1)) 

what seed? data compute hash from? secret = key, far understand. also, start p_hash a(1)?

thanks in advance!

seed client_random + server_random. need preserve them preceding steps of handshake, client_hello , server_hello.

a(0) = seed  a(i) = hmac_hash(secret,a(i-1)) i>0 

the output of a() function consists of a(1), a(2), a(3)...


Comments

Popular posts from this blog

javascript - Count length of each class -

What design pattern is this code in Javascript? -

hadoop - Restrict secondarynamenode to be installed and run on any other node in the cluster -