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.7 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
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Runtime.InteropServices;
  4. using System.Text;
  5. namespace shadowsocks_csharp.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. }