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 5.7 kB

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