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.

OpenSSLEncryptor.cs 5.6 kB

10 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Runtime.InteropServices;
  4. using System.Text;
  5. namespace Shadowsocks.Encrypt
  6. {
  7. public class OpenSSLEncryptor
  8. : EncryptorBase, IDisposable
  9. {
  10. static Dictionary<string, int[]> ciphers = new Dictionary<string, int[]> {
  11. {"aes-128-cfb", new int[]{16, 16}},
  12. {"aes-192-cfb", new int[]{24, 16}},
  13. {"aes-256-cfb", new int[]{32, 16}},
  14. {"bf-cfb", new int[]{16, 8}},
  15. {"rc4", new int[]{16, 0}},
  16. {"rc4-md5", new int[]{16, 16}},
  17. };
  18. static OpenSSLEncryptor()
  19. {
  20. OpenSSL.OpenSSL_add_all_ciphers();
  21. }
  22. public OpenSSLEncryptor(string method, string password)
  23. : base(method, password)
  24. {
  25. InitKey(method, password);
  26. }
  27. static byte[] tempbuf = new byte[32768];
  28. public override void Encrypt(byte[] buf, int length, byte[] outbuf, out int outlength)
  29. {
  30. if (_encryptCtx == IntPtr.Zero)
  31. {
  32. OpenSSL.RAND_bytes(outbuf, ivLen);
  33. InitCipher(ref _encryptCtx, outbuf, true);
  34. outlength = length + ivLen;
  35. OpenSSL.EVP_CipherUpdate(_encryptCtx, tempbuf, out outlength, buf, length);
  36. outlength = length + ivLen;
  37. Buffer.BlockCopy(tempbuf, 0, outbuf, ivLen, outlength);
  38. }
  39. else
  40. {
  41. outlength = length;
  42. OpenSSL.EVP_CipherUpdate(_encryptCtx, outbuf, out outlength, buf, length);
  43. }
  44. }
  45. public override void Decrypt(byte[] buf, int length, byte[] outbuf, out int outlength)
  46. {
  47. if (_decryptCtx == IntPtr.Zero)
  48. {
  49. InitCipher(ref _decryptCtx, buf, false);
  50. outlength = length - ivLen;
  51. Buffer.BlockCopy(buf, ivLen, tempbuf, 0, length - ivLen);
  52. OpenSSL.EVP_CipherUpdate(_decryptCtx, outbuf, out outlength, tempbuf, length - ivLen);
  53. }
  54. else
  55. {
  56. outlength = length;
  57. OpenSSL.EVP_CipherUpdate(_decryptCtx, outbuf, out outlength, buf, length);
  58. }
  59. }
  60. private static readonly Dictionary<string, byte[]> CachedKeys = new Dictionary<string, byte[]>();
  61. private byte[] _key;
  62. private IntPtr _encryptCtx;
  63. private IntPtr _decryptCtx;
  64. private IntPtr _cipher;
  65. private string _method;
  66. private int keyLen;
  67. private int ivLen;
  68. private void InitKey(string method, string password)
  69. {
  70. method = method.ToLower();
  71. _method = method;
  72. string k = method + ":" + password;
  73. if (method == "rc4-md5")
  74. {
  75. method = "rc4";
  76. }
  77. _cipher = OpenSSL.EVP_get_cipherbyname(System.Text.Encoding.UTF8.GetBytes(method));
  78. if (_cipher == null)
  79. {
  80. throw new Exception("method not found");
  81. }
  82. keyLen = ciphers[_method][0];
  83. ivLen = ciphers[_method][1];
  84. if (CachedKeys.ContainsKey(k))
  85. {
  86. _key = CachedKeys[k];
  87. }
  88. else
  89. {
  90. byte[] passbuf = Encoding.UTF8.GetBytes(password);
  91. _key = new byte[32];
  92. byte[] iv = new byte[16];
  93. OpenSSL.EVP_BytesToKey(_cipher, OpenSSL.EVP_md5(), IntPtr.Zero, passbuf, passbuf.Length, 1, _key, iv);
  94. CachedKeys[k] = _key;
  95. }
  96. }
  97. private void InitCipher(ref IntPtr ctx, byte[] iv, bool isCipher)
  98. {
  99. ctx = OpenSSL.EVP_CIPHER_CTX_new();
  100. int enc = isCipher ? 1 : 0;
  101. byte[] realkey;
  102. IntPtr r = IntPtr.Zero;
  103. if (_method == "rc4-md5")
  104. {
  105. byte[] temp = new byte[keyLen + ivLen];
  106. realkey = new byte[keyLen];
  107. Array.Copy(_key, 0, temp, 0, keyLen);
  108. Array.Copy(iv, 0, temp, keyLen, ivLen);
  109. r = OpenSSL.MD5(temp, keyLen + ivLen, null);
  110. Marshal.Copy(r, realkey, 0, keyLen);
  111. }
  112. else
  113. {
  114. realkey = _key;
  115. }
  116. OpenSSL.EVP_CipherInit_ex(ctx, _cipher, IntPtr.Zero, realkey, iv, enc);
  117. }
  118. #region IDisposable
  119. private bool _disposed;
  120. public override void Dispose()
  121. {
  122. Dispose(true);
  123. GC.SuppressFinalize(this);
  124. }
  125. ~OpenSSLEncryptor()
  126. {
  127. Dispose(false);
  128. }
  129. protected virtual void Dispose(bool disposing)
  130. {
  131. if (!_disposed)
  132. {
  133. if (disposing)
  134. {
  135. }
  136. if (_encryptCtx.ToInt64() != 0)
  137. {
  138. OpenSSL.EVP_CIPHER_CTX_cleanup(_encryptCtx);
  139. OpenSSL.EVP_CIPHER_CTX_free(_encryptCtx);
  140. _encryptCtx = IntPtr.Zero;
  141. }
  142. if (_decryptCtx.ToInt64() != 0)
  143. {
  144. OpenSSL.EVP_CIPHER_CTX_cleanup(_decryptCtx);
  145. OpenSSL.EVP_CIPHER_CTX_free(_decryptCtx);
  146. _decryptCtx = IntPtr.Zero;
  147. }
  148. _disposed = true;
  149. }
  150. }
  151. #endregion
  152. }
  153. }