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.

IVEncryptor.cs 5.1 kB

10 years ago
10 years ago
10 years ago
10 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Security.Cryptography;
  4. using System.Text;
  5. namespace Shadowsocks.Encryption
  6. {
  7. public abstract class IVEncryptor
  8. : EncryptorBase
  9. {
  10. protected static byte[] tempbuf = new byte[MAX_INPUT_SIZE];
  11. protected Dictionary<string, int[]> ciphers;
  12. private static readonly Dictionary<string, byte[]> CachedKeys = new Dictionary<string, byte[]>();
  13. protected byte[] _encryptIV;
  14. protected byte[] _decryptIV;
  15. protected bool _decryptIVReceived;
  16. protected bool _encryptIVSent;
  17. protected int _encryptIVOffset = 0;
  18. protected int _decryptIVOffset = 0;
  19. protected string _method;
  20. protected int _cipher;
  21. protected int[] _cipherInfo;
  22. protected byte[] _key;
  23. protected int keyLen;
  24. protected int ivLen;
  25. public IVEncryptor(string method, string password)
  26. : base(method, password)
  27. {
  28. InitKey(method, password);
  29. }
  30. protected abstract Dictionary<string, int[]> getCiphers();
  31. protected void InitKey(string method, string password)
  32. {
  33. method = method.ToLower();
  34. _method = method;
  35. string k = method + ":" + password;
  36. ciphers = getCiphers();
  37. _cipherInfo = ciphers[_method];
  38. _cipher = _cipherInfo[2];
  39. if (_cipher == 0)
  40. {
  41. throw new Exception("method not found");
  42. }
  43. keyLen = ciphers[_method][0];
  44. ivLen = ciphers[_method][1];
  45. if (CachedKeys.ContainsKey(k))
  46. {
  47. _key = CachedKeys[k];
  48. }
  49. else
  50. {
  51. byte[] passbuf = Encoding.UTF8.GetBytes(password);
  52. _key = new byte[32];
  53. byte[] iv = new byte[16];
  54. bytesToKey(passbuf, _key);
  55. CachedKeys[k] = _key;
  56. }
  57. }
  58. protected void bytesToKey(byte[] password, byte[] key)
  59. {
  60. byte[] result = new byte[password.Length + 16];
  61. int i = 0;
  62. byte[] md5sum = null;
  63. while (i < key.Length)
  64. {
  65. MD5 md5 = MD5.Create();
  66. if (i == 0)
  67. {
  68. md5sum = md5.ComputeHash(password);
  69. }
  70. else
  71. {
  72. md5sum.CopyTo(result, 0);
  73. password.CopyTo(result, md5sum.Length);
  74. md5sum = md5.ComputeHash(result);
  75. }
  76. md5sum.CopyTo(key, i);
  77. i += md5sum.Length;
  78. }
  79. }
  80. protected static void randBytes(byte[] buf, int length)
  81. {
  82. byte[] temp = new byte[length];
  83. new Random().NextBytes(temp);
  84. temp.CopyTo(buf, 0);
  85. }
  86. protected virtual void initCipher(byte[] iv, bool isCipher)
  87. {
  88. if (ivLen > 0)
  89. {
  90. if (isCipher)
  91. {
  92. _encryptIV = new byte[ivLen];
  93. Array.Copy(iv, _encryptIV, ivLen);
  94. }
  95. else
  96. {
  97. _decryptIV = new byte[ivLen];
  98. Array.Copy(iv, _decryptIV, ivLen);
  99. }
  100. }
  101. }
  102. protected abstract void cipherUpdate(bool isCipher, int length, byte[] buf, byte[] outbuf);
  103. public override void Encrypt(byte[] buf, int length, byte[] outbuf, out int outlength)
  104. {
  105. if (!_encryptIVSent)
  106. {
  107. _encryptIVSent = true;
  108. randBytes(outbuf, ivLen);
  109. initCipher(outbuf, true);
  110. outlength = length + ivLen;
  111. lock (tempbuf)
  112. {
  113. cipherUpdate(true, length, buf, tempbuf);
  114. outlength = length + ivLen;
  115. Buffer.BlockCopy(tempbuf, 0, outbuf, ivLen, length);
  116. }
  117. }
  118. else
  119. {
  120. outlength = length;
  121. cipherUpdate(true, length, buf, outbuf);
  122. }
  123. }
  124. public override void Decrypt(byte[] buf, int length, byte[] outbuf, out int outlength)
  125. {
  126. if (!_decryptIVReceived)
  127. {
  128. _decryptIVReceived = true;
  129. initCipher(buf, false);
  130. outlength = length - ivLen;
  131. lock (tempbuf)
  132. {
  133. // C# could be multi-threaded
  134. Buffer.BlockCopy(buf, ivLen, tempbuf, 0, length - ivLen);
  135. cipherUpdate(false, length - ivLen, tempbuf, outbuf);
  136. }
  137. }
  138. else
  139. {
  140. outlength = length;
  141. cipherUpdate(false, length, buf, outbuf);
  142. }
  143. }
  144. }
  145. }