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.

StreamChachaNaClEncryptor.cs 2.5 kB

6 years ago
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Runtime.CompilerServices;
  4. using NaCl.Core;
  5. namespace Shadowsocks.Encryption.Stream
  6. {
  7. public class StreamChachaNaClEncryptor : StreamEncryptor
  8. {
  9. const int BlockSize = 64;
  10. // tcp is stream, which can split into chunks at unexpected position...
  11. // so we need some special handling, as we can't read all data before encrypt
  12. // we did it in AEADEncryptor.cs for AEAD, it can operate at block level
  13. // but we need do it ourselves in stream cipher.
  14. // when new data arrive, put it on correct offset
  15. // and update it, ignore other data, get it in correct offset...
  16. readonly byte[] chachaBuf = new byte[MaxInputSize + BlockSize];
  17. // the 'correct offset', always in 0~BlockSize range, so input data always fit into buffer
  18. int remain = 0;
  19. // increase counter manually...
  20. int ic = 0;
  21. public StreamChachaNaClEncryptor(string method, string password) : base(method, password)
  22. {
  23. }
  24. protected override int CipherDecrypt(Span<byte> plain, ReadOnlySpan<byte> cipher)
  25. {
  26. return CipherUpdate(cipher, plain, false);
  27. }
  28. protected override int CipherEncrypt(ReadOnlySpan<byte> plain, Span<byte> cipher)
  29. {
  30. return CipherUpdate(plain, cipher, true);
  31. }
  32. [MethodImpl(MethodImplOptions.AggressiveOptimization | MethodImplOptions.AggressiveInlining)]
  33. private int CipherUpdate(ReadOnlySpan<byte> i, Span<byte> o, bool enc)
  34. {
  35. int len = i.Length;
  36. int pad = remain;
  37. i.CopyTo(chachaBuf.AsSpan(pad));
  38. var chacha = new ChaCha20(key, ic);
  39. var p = enc ? chacha.Encrypt(chachaBuf, iv) : chacha.Decrypt(chachaBuf, iv);
  40. p.AsSpan(pad, len).CopyTo(o);
  41. pad += len;
  42. ic += pad / BlockSize;
  43. remain = pad % BlockSize;
  44. return len;
  45. }
  46. #region Cipher Info
  47. private static readonly Dictionary<string, CipherInfo> _ciphers = new Dictionary<string, CipherInfo>
  48. {
  49. { "chacha20-ietf", new CipherInfo("chacha20-ietf", 32, 12, CipherFamily.Chacha20) },
  50. };
  51. public static Dictionary<string, CipherInfo> SupportedCiphers()
  52. {
  53. return _ciphers;
  54. }
  55. protected override Dictionary<string, CipherInfo> GetCiphers()
  56. {
  57. return _ciphers;
  58. }
  59. #endregion
  60. }
  61. }