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