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