You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

UnsafeClient.cs 3.0 kB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. using Shadowsocks.Protocol.Shadowsocks.Crypto;
  2. using System;
  3. using System.IO.Pipelines;
  4. using System.Net;
  5. using System.Threading.Tasks;
  6. namespace Shadowsocks.Protocol.Shadowsocks
  7. {
  8. // 'original' shadowsocks encryption layer
  9. internal class UnsafeClient : IStreamClient
  10. {
  11. CryptoParameter parameter;
  12. string password;
  13. public UnsafeClient(CryptoParameter parameter, string password)
  14. {
  15. this.password = password;
  16. this.parameter = parameter;
  17. }
  18. public Task Connect(EndPoint destination, IDuplexPipe client, IDuplexPipe server) =>
  19. // destination is ignored, this is just a converter
  20. Task.WhenAll(ConvertUplink(client, server), ConvertDownlink(client, server));
  21. public async Task ConvertUplink(IDuplexPipe client, IDuplexPipe server)
  22. {
  23. var up = parameter.GetCrypto();
  24. var pmp = new ProtocolMessagePipe(server);
  25. var key = CryptoUtils.SSKDF(password, parameter.KeySize);
  26. var salt = new SaltMessage(parameter.NonceSize, true);
  27. await pmp.WriteAsync(salt);
  28. up.Init(key, salt.Salt.ToArray());
  29. Memory<byte> nonce = new byte[parameter.NonceSize];
  30. nonce.Span.Fill(0);
  31. // TODO write salt with data
  32. while (true)
  33. {
  34. var result = await client.Input.ReadAsync();
  35. if (result.IsCanceled || result.IsCompleted) return;
  36. // TODO compress into one chunk when possible
  37. foreach (var item in result.Buffer)
  38. {
  39. var mem = server.Output.GetMemory(item.Length);
  40. var len = up.Encrypt(null, item.Span, mem.Span);
  41. server.Output.Advance(len);
  42. }
  43. client.Input.AdvanceTo(result.Buffer.End);
  44. }
  45. }
  46. public async Task ConvertDownlink(IDuplexPipe client, IDuplexPipe server)
  47. {
  48. var down = parameter.GetCrypto();
  49. var pmp = new ProtocolMessagePipe(server);
  50. var salt = await pmp.ReadAsync(new SaltMessage(parameter.NonceSize));
  51. var key = CryptoUtils.SSKDF(password, parameter.KeySize);
  52. down.Init(key, salt.Salt.ToArray());
  53. while (true)
  54. {
  55. while (true)
  56. {
  57. var result = await server.Input.ReadAsync();
  58. if (result.IsCanceled || result.IsCompleted) return;
  59. // TODO compress into one chunk when possible
  60. foreach (var item in result.Buffer)
  61. {
  62. var mem = client.Output.GetMemory(item.Length);
  63. var len = down.Decrypt(null, mem.Span, item.Span);
  64. client.Output.Advance(len);
  65. }
  66. server.Input.AdvanceTo(result.Buffer.End);
  67. }
  68. }
  69. }
  70. }
  71. }