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.

MbedTLSEncryptor.cs 6.2 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Runtime.InteropServices;
  4. namespace Shadowsocks.Encryption
  5. {
  6. public class MbedTLSEncryptor
  7. : IVEncryptor, IDisposable
  8. {
  9. const int CIPHER_RC4 = 1;
  10. const int CIPHER_AES = 2;
  11. const int CIPHER_BLOWFISH = 3;
  12. const int CIPHER_CAMELLIA = 4;
  13. private IntPtr _encryptCtx = IntPtr.Zero;
  14. private IntPtr _decryptCtx = IntPtr.Zero;
  15. public MbedTLSEncryptor(string method, string password, bool onetimeauth, bool isudp)
  16. : base(method, password, onetimeauth, isudp)
  17. {
  18. InitKey(method, password);
  19. }
  20. private static Dictionary<string, Dictionary<string, int[]>> _ciphers = new Dictionary<string, Dictionary<string, int[]>> {
  21. { "aes-128-cfb", new Dictionary<string, int[]> { { "AES-128-CFB128", new int[] { 16, 16, CIPHER_AES } } } },
  22. { "aes-192-cfb", new Dictionary<string, int[]> { { "AES-192-CFB128", new int[] { 24, 16, CIPHER_AES } } } },
  23. { "aes-256-cfb", new Dictionary<string, int[]> { { "AES-256-CFB128", new int[] { 32, 16, CIPHER_AES } } } },
  24. { "aes-128-ctr", new Dictionary<string, int[]> { { "AES-128-CTR", new int[] { 16, 16, CIPHER_AES } } } },
  25. { "aes-192-ctr", new Dictionary<string, int[]> { { "AES-192-CTR", new int[] { 24, 16, CIPHER_AES } } } },
  26. { "aes-256-ctr", new Dictionary<string, int[]> { { "AES-256-CTR", new int[] { 32, 16, CIPHER_AES } } } },
  27. { "bf-cfb", new Dictionary<string, int[]> { { "BLOWFISH-CFB64", new int[] { 16, 8, CIPHER_BLOWFISH } } } },
  28. { "camellia-128-cfb", new Dictionary<string, int[]> { { "CAMELLIA-128-CFB128", new int[] { 16, 16, CIPHER_CAMELLIA } } } },
  29. { "camellia-192-cfb", new Dictionary<string, int[]> { { "CAMELLIA-192-CFB128", new int[] { 24, 16, CIPHER_CAMELLIA } } } },
  30. { "camellia-256-cfb", new Dictionary<string, int[]> { { "CAMELLIA-256-CFB128", new int[] { 32, 16, CIPHER_CAMELLIA } } } },
  31. { "rc4-md5", new Dictionary<string, int[]> { { "ARC4-128", new int[] { 16, 16, CIPHER_RC4 } } } }
  32. };
  33. public static List<string> SupportedCiphers()
  34. {
  35. return new List<string>(_ciphers.Keys);
  36. }
  37. protected override Dictionary<string, Dictionary<string, int[]>> getCiphers()
  38. {
  39. return _ciphers;
  40. }
  41. protected override void initCipher(byte[] iv, bool isCipher)
  42. {
  43. base.initCipher(iv, isCipher);
  44. IntPtr ctx = Marshal.AllocHGlobal(MbedTLS.cipher_get_size_ex());
  45. if (isCipher)
  46. {
  47. _encryptCtx = ctx;
  48. }
  49. else
  50. {
  51. _decryptCtx = ctx;
  52. }
  53. byte[] realkey;
  54. if (_method == "rc4-md5")
  55. {
  56. byte[] temp = new byte[keyLen + ivLen];
  57. realkey = new byte[keyLen];
  58. Array.Copy(_key, 0, temp, 0, keyLen);
  59. Array.Copy(iv, 0, temp, keyLen, ivLen);
  60. realkey = MbedTLS.MD5(temp);
  61. }
  62. else
  63. {
  64. realkey = _key;
  65. }
  66. MbedTLS.cipher_init(ctx);
  67. if (MbedTLS.cipher_setup( ctx, MbedTLS.cipher_info_from_string( _cipherMbedName ) ) != 0 )
  68. throw new Exception("Cannot initialize mbed TLS cipher context");
  69. /*
  70. * MbedTLS takes key length by bit
  71. * cipher_setkey() will set the correct key schedule
  72. * and operation
  73. *
  74. * MBEDTLS_AES_{EN,DE}CRYPT
  75. * == MBEDTLS_BLOWFISH_{EN,DE}CRYPT
  76. * == MBEDTLS_CAMELLIA_{EN,DE}CRYPT
  77. * == MBEDTLS_{EN,DE}CRYPT
  78. *
  79. */
  80. if (MbedTLS.cipher_setkey(ctx, realkey, keyLen * 8, isCipher ? MbedTLS.MBEDTLS_ENCRYPT : MbedTLS.MBEDTLS_DECRYPT) != 0 )
  81. throw new Exception("Cannot set mbed TLS cipher key");
  82. if (MbedTLS.cipher_set_iv(ctx, iv, ivLen) != 0)
  83. throw new Exception("Cannot set mbed TLS cipher IV");
  84. if (MbedTLS.cipher_reset(ctx) != 0)
  85. throw new Exception("Cannot finalize mbed TLS cipher context");
  86. }
  87. protected override void cipherUpdate(bool isCipher, int length, byte[] buf, byte[] outbuf)
  88. {
  89. // C# could be multi-threaded
  90. if (_disposed)
  91. {
  92. throw new ObjectDisposedException(this.ToString());
  93. }
  94. IntPtr ctx;
  95. if (isCipher)
  96. {
  97. ctx = _encryptCtx;
  98. }
  99. else
  100. {
  101. ctx = _decryptCtx;
  102. }
  103. if (MbedTLS.cipher_update(ctx, buf, length, outbuf, ref length) != 0 )
  104. throw new Exception("Cannot update mbed TLS cipher context");
  105. }
  106. #region IDisposable
  107. private bool _disposed;
  108. public override void Dispose()
  109. {
  110. Dispose(true);
  111. GC.SuppressFinalize(this);
  112. }
  113. ~MbedTLSEncryptor()
  114. {
  115. Dispose(false);
  116. }
  117. protected virtual void Dispose(bool disposing)
  118. {
  119. lock (this)
  120. {
  121. if (_disposed)
  122. {
  123. return;
  124. }
  125. _disposed = true;
  126. }
  127. if (disposing)
  128. {
  129. if (_encryptCtx != IntPtr.Zero)
  130. {
  131. MbedTLS.cipher_free(_encryptCtx);
  132. Marshal.FreeHGlobal(_encryptCtx);
  133. _encryptCtx = IntPtr.Zero;
  134. }
  135. if (_decryptCtx != IntPtr.Zero)
  136. {
  137. MbedTLS.cipher_free(_decryptCtx);
  138. Marshal.FreeHGlobal(_decryptCtx);
  139. _decryptCtx = IntPtr.Zero;
  140. }
  141. }
  142. }
  143. #endregion
  144. }
  145. }