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.

PolarSSLEncryptor.cs 10 kB

10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Runtime.InteropServices;
  4. using System.Security.Cryptography;
  5. using System.Text;
  6. using System.Threading;
  7. namespace Shadowsocks.Encrypt
  8. {
  9. public class PolarSSLEncryptor
  10. : EncryptorBase, IDisposable
  11. {
  12. const int CIPHER_AES = 1;
  13. const int CIPHER_RC4 = 2;
  14. static Dictionary<string, int[]> ciphers = new Dictionary<string, int[]> {
  15. {"aes-128-cfb", new int[]{16, 16, CIPHER_AES, PolarSSL.AES_CTX_SIZE}},
  16. {"aes-192-cfb", new int[]{24, 16, CIPHER_AES, PolarSSL.AES_CTX_SIZE}},
  17. {"aes-256-cfb", new int[]{32, 16, CIPHER_AES, PolarSSL.AES_CTX_SIZE}},
  18. {"rc4", new int[]{16, 0, CIPHER_RC4, PolarSSL.ARC4_CTX_SIZE}},
  19. {"rc4-md5", new int[]{16, 16, CIPHER_RC4, PolarSSL.ARC4_CTX_SIZE}},
  20. };
  21. private static readonly Dictionary<string, byte[]> CachedKeys = new Dictionary<string, byte[]>();
  22. private int _cipher;
  23. private int[] _cipherInfo;
  24. private byte[] _key;
  25. private IntPtr _encryptCtx = IntPtr.Zero;
  26. private IntPtr _decryptCtx = IntPtr.Zero;
  27. private byte[] _encryptIV;
  28. private byte[] _decryptIV;
  29. private int _encryptIVOffset = 0;
  30. private int _decryptIVOffset = 0;
  31. private string _method;
  32. private int keyLen;
  33. private int ivLen;
  34. public PolarSSLEncryptor(string method, string password)
  35. : base(method, password)
  36. {
  37. InitKey(method, password);
  38. }
  39. private static void randBytes(byte[] buf, int length)
  40. {
  41. byte[] temp = new byte[length];
  42. new Random().NextBytes(temp);
  43. temp.CopyTo(buf, 0);
  44. }
  45. private void bytesToKey(byte[] password, byte[] key)
  46. {
  47. byte[] result = new byte[password.Length + 16];
  48. int i = 0;
  49. byte[] md5sum = null;
  50. while (i < key.Length)
  51. {
  52. MD5 md5 = MD5.Create();
  53. if (i == 0)
  54. {
  55. md5sum = md5.ComputeHash(password);
  56. }
  57. else
  58. {
  59. md5sum.CopyTo(result, 0);
  60. password.CopyTo(result, md5sum.Length);
  61. md5sum = md5.ComputeHash(result);
  62. }
  63. md5sum.CopyTo(key, i);
  64. i += md5sum.Length;
  65. }
  66. }
  67. private void InitKey(string method, string password)
  68. {
  69. method = method.ToLower();
  70. _method = method;
  71. string k = method + ":" + password;
  72. _cipherInfo = ciphers[_method];
  73. _cipher = _cipherInfo[2];
  74. if (_cipher == 0)
  75. {
  76. throw new Exception("method not found");
  77. }
  78. keyLen = ciphers[_method][0];
  79. ivLen = ciphers[_method][1];
  80. if (CachedKeys.ContainsKey(k))
  81. {
  82. _key = CachedKeys[k];
  83. }
  84. else
  85. {
  86. byte[] passbuf = Encoding.UTF8.GetBytes(password);
  87. _key = new byte[32];
  88. byte[] iv = new byte[16];
  89. bytesToKey(passbuf, _key);
  90. CachedKeys[k] = _key;
  91. }
  92. }
  93. private void InitCipher(ref IntPtr ctx, byte[] iv, bool isCipher)
  94. {
  95. ctx = Marshal.AllocHGlobal(_cipherInfo[3]);
  96. byte[] realkey;
  97. if (_method == "rc4-md5")
  98. {
  99. byte[] temp = new byte[keyLen + ivLen];
  100. realkey = new byte[keyLen];
  101. Array.Copy(_key, 0, temp, 0, keyLen);
  102. Array.Copy(iv, 0, temp, keyLen, ivLen);
  103. realkey = MD5.Create().ComputeHash(temp);
  104. }
  105. else
  106. {
  107. realkey = _key;
  108. }
  109. if (_cipher == CIPHER_AES)
  110. {
  111. PolarSSL.aes_init(ctx);
  112. // PolarSSL takes key length by bit
  113. // since we'll use CFB mode, here we both do enc, not dec
  114. PolarSSL.aes_setkey_enc(ctx, realkey, keyLen * 8);
  115. if (isCipher)
  116. {
  117. _encryptIV = new byte[ivLen];
  118. Array.Copy(iv, _encryptIV, ivLen);
  119. }
  120. else
  121. {
  122. _decryptIV = new byte[ivLen];
  123. Array.Copy(iv, _decryptIV, ivLen);
  124. }
  125. }
  126. else if (_cipher == CIPHER_RC4)
  127. {
  128. PolarSSL.arc4_init(ctx);
  129. // PolarSSL RC4 takes key length by byte
  130. PolarSSL.arc4_setup(ctx, realkey, keyLen);
  131. }
  132. }
  133. static byte[] tempbuf = new byte[32768];
  134. public override void Encrypt(byte[] buf, int length, byte[] outbuf, out int outlength)
  135. {
  136. if (_encryptCtx == IntPtr.Zero)
  137. {
  138. randBytes(outbuf, ivLen);
  139. InitCipher(ref _encryptCtx, outbuf, true);
  140. outlength = length + ivLen;
  141. lock (tempbuf)
  142. {
  143. // C# could be multi-threaded
  144. if (_disposed)
  145. {
  146. throw new ObjectDisposedException(this.ToString());
  147. }
  148. switch (_cipher)
  149. {
  150. case CIPHER_AES:
  151. PolarSSL.aes_crypt_cfb128(_encryptCtx, PolarSSL.AES_ENCRYPT, length, ref _encryptIVOffset, _encryptIV, buf, tempbuf);
  152. break;
  153. case CIPHER_RC4:
  154. PolarSSL.arc4_crypt(_encryptCtx, length, buf, tempbuf);
  155. break;
  156. }
  157. outlength = length + ivLen;
  158. Buffer.BlockCopy(tempbuf, 0, outbuf, ivLen, length);
  159. }
  160. }
  161. else
  162. {
  163. outlength = length;
  164. if (_disposed)
  165. {
  166. throw new ObjectDisposedException(this.ToString());
  167. }
  168. switch (_cipher)
  169. {
  170. case CIPHER_AES:
  171. PolarSSL.aes_crypt_cfb128(_encryptCtx, PolarSSL.AES_ENCRYPT, length, ref _encryptIVOffset, _encryptIV, buf, outbuf);
  172. break;
  173. case CIPHER_RC4:
  174. PolarSSL.arc4_crypt(_encryptCtx, length, buf, outbuf);
  175. break;
  176. }
  177. }
  178. }
  179. public override void Decrypt(byte[] buf, int length, byte[] outbuf, out int outlength)
  180. {
  181. if (_decryptCtx == IntPtr.Zero)
  182. {
  183. InitCipher(ref _decryptCtx, buf, false);
  184. outlength = length - ivLen;
  185. lock (tempbuf)
  186. {
  187. // C# could be multi-threaded
  188. Buffer.BlockCopy(buf, ivLen, tempbuf, 0, length - ivLen);
  189. if (_disposed)
  190. {
  191. throw new ObjectDisposedException(this.ToString());
  192. }
  193. switch (_cipher)
  194. {
  195. case CIPHER_AES:
  196. PolarSSL.aes_crypt_cfb128(_decryptCtx, PolarSSL.AES_DECRYPT, length - ivLen, ref _decryptIVOffset, _decryptIV, tempbuf, outbuf);
  197. break;
  198. case CIPHER_RC4:
  199. PolarSSL.arc4_crypt(_decryptCtx, length - ivLen, tempbuf, outbuf);
  200. break;
  201. }
  202. }
  203. }
  204. else
  205. {
  206. outlength = length;
  207. if (_disposed)
  208. {
  209. throw new ObjectDisposedException(this.ToString());
  210. }
  211. switch (_cipher)
  212. {
  213. case CIPHER_AES:
  214. PolarSSL.aes_crypt_cfb128(_decryptCtx, PolarSSL.AES_DECRYPT, length, ref _decryptIVOffset, _decryptIV, buf, outbuf);
  215. break;
  216. case CIPHER_RC4:
  217. PolarSSL.arc4_crypt(_decryptCtx, length, buf, outbuf);
  218. break;
  219. }
  220. }
  221. }
  222. #region IDisposable
  223. private bool _disposed;
  224. public override void Dispose()
  225. {
  226. Dispose(true);
  227. GC.SuppressFinalize(this);
  228. }
  229. ~PolarSSLEncryptor()
  230. {
  231. Dispose(false);
  232. }
  233. protected virtual void Dispose(bool disposing)
  234. {
  235. lock (this)
  236. {
  237. if (_disposed)
  238. {
  239. return;
  240. }
  241. _disposed = true;
  242. }
  243. if (disposing)
  244. {
  245. if (_encryptCtx != IntPtr.Zero)
  246. {
  247. switch (_cipher)
  248. {
  249. case CIPHER_AES:
  250. PolarSSL.aes_free(_encryptCtx);
  251. break;
  252. case CIPHER_RC4:
  253. PolarSSL.arc4_free(_encryptCtx);
  254. break;
  255. }
  256. Marshal.FreeHGlobal(_encryptCtx);
  257. _encryptCtx = IntPtr.Zero;
  258. }
  259. if (_decryptCtx != IntPtr.Zero)
  260. {
  261. switch (_cipher)
  262. {
  263. case CIPHER_AES:
  264. PolarSSL.aes_free(_decryptCtx);
  265. break;
  266. case CIPHER_RC4:
  267. PolarSSL.arc4_free(_decryptCtx);
  268. break;
  269. }
  270. Marshal.FreeHGlobal(_decryptCtx);
  271. _decryptCtx = IntPtr.Zero;
  272. }
  273. }
  274. }
  275. #endregion
  276. }
  277. }