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.

StreamRc4NativeCrypto.cs 3.4 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Runtime.CompilerServices;
  4. namespace Shadowsocks.Crypto.Stream
  5. {
  6. public class StreamRc4NativeCrypto : StreamCrypto
  7. {
  8. byte[] realkey = new byte[256];
  9. byte[] sbox = new byte[256];
  10. public StreamRc4NativeCrypto(string method, string password) : base(method, password)
  11. {
  12. }
  13. protected override void InitCipher(byte[] iv, bool isEncrypt)
  14. {
  15. base.InitCipher(iv, isEncrypt);
  16. // rc4-md5 is rc4 with md5 based session key
  17. if (cipherFamily == CipherFamily.Rc4Md5)
  18. {
  19. byte[] temp = new byte[keyLen + ivLen];
  20. Array.Copy(key, 0, temp, 0, keyLen);
  21. Array.Copy(iv, 0, temp, keyLen, ivLen);
  22. realkey = CryptoUtils.MD5(temp);
  23. }
  24. else
  25. {
  26. realkey = key;
  27. }
  28. sbox = SBox(realkey);
  29. }
  30. protected override int CipherEncrypt(ReadOnlySpan<byte> plain, Span<byte> cipher)
  31. {
  32. return CipherUpdate(plain, cipher);
  33. }
  34. protected override int CipherDecrypt(Span<byte> plain, ReadOnlySpan<byte> cipher)
  35. {
  36. return CipherUpdate(cipher, plain);
  37. }
  38. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  39. private int CipherUpdate(ReadOnlySpan<byte> i, Span<byte> o)
  40. {
  41. // don't know why we need third array, but it works...
  42. Span<byte> t = new byte[i.Length];
  43. i.CopyTo(t);
  44. RC4(sbox, t, t.Length);
  45. t.CopyTo(o);
  46. return t.Length;
  47. }
  48. #region Cipher Info
  49. private static readonly Dictionary<string, CipherInfo> _ciphers = new Dictionary<string, CipherInfo>
  50. {
  51. // original RC4 doesn't use IV
  52. { "rc4", new CipherInfo("rc4", 16, 0, CipherFamily.Rc4) },
  53. { "rc4-md5", new CipherInfo("rc4-md5", 16, 16, CipherFamily.Rc4Md5) },
  54. };
  55. public static Dictionary<string, CipherInfo> SupportedCiphers()
  56. {
  57. return _ciphers;
  58. }
  59. protected override Dictionary<string, CipherInfo> GetCiphers()
  60. {
  61. return _ciphers;
  62. }
  63. #endregion
  64. #region RC4
  65. int index1 = 0;
  66. int index2 = 0;
  67. private byte[] SBox(byte[] key)
  68. {
  69. byte[] s = new byte[256];
  70. for (int i = 0; i < 256; i++)
  71. {
  72. s[i] = (byte)i;
  73. }
  74. for (int i = 0, j = 0; i < 256; i++)
  75. {
  76. j = (j + key[i % key.Length] + s[i]) & 255;
  77. Swap(s, i, j);
  78. }
  79. return s;
  80. }
  81. private void RC4(Span<byte> s, Span<byte> data, int length)
  82. {
  83. for (int n = 0; n < length; n++)
  84. {
  85. byte b = data[n];
  86. index1 = (index1 + 1) & 255;
  87. index2 = (index2 + s[index1]) & 255;
  88. Swap(s, index1, index2);
  89. data[n] = (byte)(b ^ s[(s[index1] + s[index2]) & 255]);
  90. }
  91. }
  92. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  93. private static void Swap(Span<byte> s, int i, int j)
  94. {
  95. byte c = s[i];
  96. s[i] = s[j];
  97. s[j] = c;
  98. }
  99. #endregion
  100. }
  101. }