public override byte[] ClientUdpPreEncrypt(byte[] plaindata, int datalength, out int outlength) { byte[] outdata = new byte[datalength + 1024]; if (user_key == null) { user_id = new byte[4]; int index_of_split = Server.param.IndexOf(':'); if (index_of_split > 0) { try { uint user = uint.Parse(Server.param.Substring(0, index_of_split)); user_key = System.Text.Encoding.UTF8.GetBytes(Server.param.Substring(index_of_split + 1)); BitConverter.GetBytes(user).CopyTo(user_id, 0); } catch (Exception ex) { Logging.Log(LogLevel.Warn, $"Faild to parse auth param, fallback to basic mode. {ex}"); } } if (user_key == null) { random.NextBytes(user_id); user_key = Server.key; } } byte[] auth_data = new byte[3]; random.NextBytes(auth_data); byte[] md5data = MbedTLS.ComputeHash(Server.key, auth_data, 0, auth_data.Length); int rand_len = UdpGetRandLen(random_client, md5data); byte[] rand_data = new byte[rand_len]; random.NextBytes(rand_data); outlength = datalength + rand_len + 8; encryptor = EncryptorFactory.GetEncryptor("rc4", Convert.ToBase64String(user_key) + Convert.ToBase64String(md5data, 0, 16)); encryptor.Encrypt(plaindata, datalength, outdata, out datalength); rand_data.CopyTo(outdata, datalength); auth_data.CopyTo(outdata, outlength - 8); byte[] uid = new byte[4]; for (int i = 0; i < 4; ++i) { uid[i] = (byte)(user_id[i] ^ md5data[i]); } uid.CopyTo(outdata, outlength - 5); md5data = MbedTLS.ComputeHash(user_key, outdata, 0, outlength - 1); return(outdata); }
public void PackData(byte[] data, int datalength, byte[] outdata, out int outlength) { int rand_len = GetRandLen(datalength); outlength = rand_len + datalength + 2; outdata[0] = (byte)(datalength ^ last_client_hash[14]); outdata[1] = (byte)((datalength >> 8) ^ last_client_hash[15]); { byte[] rnd_data = new byte[rand_len]; random.NextBytes(rnd_data); encryptor.Encrypt(data, datalength, data, out datalength); if (datalength > 0) { if (rand_len > 0) { int start_pos = GetRandStartPos(rand_len, random_client); Array.Copy(data, 0, outdata, 2 + start_pos, datalength); Array.Copy(rnd_data, 0, outdata, 2, start_pos); Array.Copy(rnd_data, start_pos, outdata, 2 + start_pos + datalength, rand_len - start_pos); } else { Array.Copy(data, 0, outdata, 2, datalength); } } else { rnd_data.CopyTo(outdata, 2); } } byte[] key = new byte[user_key.Length + 4]; user_key.CopyTo(key, 0); BitConverter.GetBytes(pack_id).CopyTo(key, key.Length - 4); ++pack_id; byte[] md5data = MbedTLS.ComputeHash(key, outdata, 0, outlength); last_client_hash = md5data; Array.Copy(md5data, 0, outdata, outlength, 2); outlength += 2; }
public override byte[] ClientUdpPostDecrypt(byte[] plaindata, int datalength, out int outlength) { if (datalength <= 8) { outlength = 0; return(plaindata); } byte[] md5data = MbedTLS.ComputeHash(user_key, plaindata, 0, datalength - 1); if (md5data[0] != plaindata[datalength - 1]) { outlength = 0; return(plaindata); } md5data = MbedTLS.ComputeHash(Server.key, plaindata, datalength - 8, 7); int rand_len = UdpGetRandLen(random_server, md5data); outlength = datalength - rand_len - 8; encryptor = EncryptorFactory.GetEncryptor("rc4", Convert.ToBase64String(user_key) + Convert.ToBase64String(md5data, 0, 16)); encryptor.Decrypt(plaindata, outlength, plaindata, out outlength); return(plaindata); }
public override byte[] ClientPostDecrypt(byte[] plaindata, int datalength, out int outlength) { byte[] outdata = new byte[recv_buf_len + datalength]; Array.Copy(plaindata, 0, recv_buf, recv_buf_len, datalength); recv_buf_len += datalength; outlength = 0; byte[] key = new byte[user_key.Length + 4]; user_key.CopyTo(key, 0); while (recv_buf_len > 4) { BitConverter.GetBytes(recv_id).CopyTo(key, key.Length - 4); int data_len = ((recv_buf[1] ^ last_server_hash[15]) << 8) + (recv_buf[0] ^ last_server_hash[14]); int rand_len = GetRandLen(data_len, random_server, last_server_hash); int len = rand_len + data_len; if (len >= 4096) { throw new ObfsException("ClientPostDecrypt data error"); } if (len + 4 > recv_buf_len) { break; } byte[] md5data = MbedTLS.ComputeHash(key, recv_buf, 0, len + 2); if (md5data[0] != recv_buf[len + 2] || md5data[1] != recv_buf[len + 3]) { throw new ObfsException("ClientPostDecrypt data uncorrect checksum"); } int pos; if (data_len > 0 && rand_len > 0) { pos = 2 + GetRandStartPos(rand_len, random_server); } else { pos = 2; } int outlen = data_len; Util.Utils.SetArrayMinSize2(ref outdata, outlength + outlen); byte[] data = new byte[outlen]; Array.Copy(recv_buf, pos, data, 0, outlen); encryptor.Decrypt(data, outlen, data, out outlen); last_server_hash = md5data; if (recv_id == 1) { Server.tcp_mss = data[0] | (data[1] << 8); pos = 2; outlen -= 2; } else { pos = 0; } Array.Copy(data, pos, outdata, outlength, outlen); outlength += outlen; recv_buf_len -= len + 4; Array.Copy(recv_buf, len + 4, recv_buf, 0, recv_buf_len); ++recv_id; } return(outdata); }
public void PackAuthData(byte[] data, int datalength, byte[] outdata, out int outlength) { const int authhead_len = 4 + 8 + 4 + 16 + 4; byte[] encrypt = new byte[24]; AuthDataAesChain authData = Server.data as AuthDataAesChain; lock (authData) { if (authData.connectionID > 0xFF000000) { authData.clientID = null; } if (authData.clientID == null) { authData.clientID = new byte[4]; g_random.GetBytes(authData.clientID); authData.connectionID = (UInt32)BitConverter.ToInt32(authData.clientID, 0) % 0xFFFFFD; } authData.connectionID += 1; Array.Copy(authData.clientID, 0, encrypt, 4, 4); Array.Copy(BitConverter.GetBytes(authData.connectionID), 0, encrypt, 8, 4); } outlength = authhead_len; byte[] encrypt_data = new byte[32]; byte[] key = new byte[Server.iv.Length + Server.key.Length]; Server.iv.CopyTo(key, 0); Server.key.CopyTo(key, Server.iv.Length); UInt64 utc_time_second = (UInt64)Math.Floor(DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1, 0, 0, 0)).TotalSeconds); UInt32 utc_time = (UInt32)(utc_time_second); Array.Copy(BitConverter.GetBytes(utc_time), 0, encrypt, 0, 4); encrypt[12] = (byte)(Server.overhead); encrypt[13] = (byte)(Server.overhead >> 8); // first 12 bytes { byte[] rnd = new byte[4]; random.NextBytes(rnd); rnd.CopyTo(outdata, 0); byte[] md5data = MbedTLS.ComputeHash(key, rnd, 0, rnd.Length); last_client_hash = md5data; Array.Copy(md5data, 0, outdata, rnd.Length, 8); } // uid & 16 bytes auth data { byte[] uid = new byte[4]; int index_of_split = Server.param.IndexOf(':'); if (index_of_split > 0) { try { uint user = uint.Parse(Server.param.Substring(0, index_of_split)); user_key = System.Text.Encoding.UTF8.GetBytes(Server.param.Substring(index_of_split + 1)); BitConverter.GetBytes(user).CopyTo(uid, 0); } catch (Exception ex) { Logging.Log(LogLevel.Warn, $"Faild to parse auth param, fallback to basic mode. {ex}"); } } if (user_key == null) { random.NextBytes(uid); user_key = Server.key; } for (int i = 0; i < 4; ++i) { uid[i] ^= last_client_hash[8 + i]; } byte[] encrypt_key = user_key; IEncryptor encryptor = EncryptorFactory.GetEncryptor("aes-128-cbc", Convert.ToBase64String(encrypt_key) + SALT); encryptor.SetIV(new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }); encryptor.Encrypt(encrypt, 16, encrypt_data, out int enc_outlen); encryptor.Dispose(); Array.Copy(encrypt_data, 16, encrypt, 4, 16); uid.CopyTo(encrypt, 0); } // final HMAC { byte[] md5data = MbedTLS.ComputeHash(user_key, encrypt, 0, 20); last_server_hash = md5data; Array.Copy(md5data, 0, encrypt, 20, 4); } encrypt.CopyTo(outdata, 12); encryptor = EncryptorFactory.GetEncryptor("rc4", Convert.ToBase64String(user_key) + Convert.ToBase64String(last_client_hash, 0, 16)); // combine first chunk { byte[] pack_outdata = new byte[outdata.Length]; PackData(data, datalength, pack_outdata, out int pack_outlength); Array.Copy(pack_outdata, 0, outdata, outlength, pack_outlength); outlength += pack_outlength; } }