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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  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. }
  19. private static Dictionary<string, EncryptorInfo> _ciphers = new Dictionary<string, EncryptorInfo> {
  20. { "aes-128-cfb", new EncryptorInfo("AES-128-CFB128", 16, 16, CIPHER_AES) },
  21. { "aes-192-cfb", new EncryptorInfo("AES-192-CFB128", 24, 16, CIPHER_AES) },
  22. { "aes-256-cfb", new EncryptorInfo("AES-256-CFB128", 32, 16, CIPHER_AES) },
  23. { "aes-128-ctr", new EncryptorInfo("AES-128-CTR", 16, 16, CIPHER_AES) },
  24. { "aes-192-ctr", new EncryptorInfo("AES-192-CTR", 24, 16, CIPHER_AES) },
  25. { "aes-256-ctr", new EncryptorInfo("AES-256-CTR", 32, 16, CIPHER_AES) },
  26. { "bf-cfb", new EncryptorInfo("BLOWFISH-CFB64", 16, 8, CIPHER_BLOWFISH) },
  27. { "camellia-128-cfb", new EncryptorInfo("CAMELLIA-128-CFB128", 16, 16, CIPHER_CAMELLIA) },
  28. { "camellia-192-cfb", new EncryptorInfo("CAMELLIA-192-CFB128", 24, 16, CIPHER_CAMELLIA) },
  29. { "camellia-256-cfb", new EncryptorInfo("CAMELLIA-256-CFB128", 32, 16, CIPHER_CAMELLIA) },
  30. { "rc4-md5", new EncryptorInfo("ARC4-128", 16, 16, CIPHER_RC4) }
  31. };
  32. public static List<string> SupportedCiphers()
  33. {
  34. return new List<string>(_ciphers.Keys);
  35. }
  36. protected override Dictionary<string, EncryptorInfo> getCiphers()
  37. {
  38. return _ciphers;
  39. }
  40. protected override void initCipher(byte[] iv, bool isCipher)
  41. {
  42. base.initCipher(iv, isCipher);
  43. IntPtr ctx = Marshal.AllocHGlobal(MbedTLS.cipher_get_size_ex());
  44. if (isCipher)
  45. {
  46. _encryptCtx = ctx;
  47. }
  48. else
  49. {
  50. _decryptCtx = ctx;
  51. }
  52. byte[] realkey;
  53. if (_method == "rc4-md5")
  54. {
  55. byte[] temp = new byte[keyLen + ivLen];
  56. realkey = new byte[keyLen];
  57. Array.Copy(_key, 0, temp, 0, keyLen);
  58. Array.Copy(iv, 0, temp, keyLen, ivLen);
  59. realkey = MbedTLS.MD5(temp);
  60. }
  61. else
  62. {
  63. realkey = _key;
  64. }
  65. MbedTLS.cipher_init(ctx);
  66. if (MbedTLS.cipher_setup( ctx, MbedTLS.cipher_info_from_string( _innerLibName ) ) != 0 )
  67. throw new Exception("Cannot initialize mbed TLS cipher context");
  68. /*
  69. * MbedTLS takes key length by bit
  70. * cipher_setkey() will set the correct key schedule
  71. * and operation
  72. *
  73. * MBEDTLS_AES_{EN,DE}CRYPT
  74. * == MBEDTLS_BLOWFISH_{EN,DE}CRYPT
  75. * == MBEDTLS_CAMELLIA_{EN,DE}CRYPT
  76. * == MBEDTLS_{EN,DE}CRYPT
  77. *
  78. */
  79. if (MbedTLS.cipher_setkey(ctx, realkey, keyLen * 8,
  80. 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. if (MbedTLS.cipher_update(isCipher ? _encryptCtx : _decryptCtx,
  95. buf, length, outbuf, ref length) != 0 )
  96. throw new Exception("Cannot update mbed TLS cipher context");
  97. }
  98. #region IDisposable
  99. private bool _disposed;
  100. // instance based lock
  101. private readonly object _lock = new object();
  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) return;
  116. _disposed = true;
  117. }
  118. if (disposing)
  119. {
  120. // free managed objects
  121. }
  122. // free unmanaged objects
  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. #endregion
  137. }
  138. }