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.

StreamMbedTLSEncryptor.cs 5.6 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Runtime.InteropServices;
  4. using Shadowsocks.Encryption.Exception;
  5. namespace Shadowsocks.Encryption.Stream
  6. {
  7. public class StreamMbedTLSEncryptor
  8. : StreamEncryptor, IDisposable
  9. {
  10. const int CIPHER_RC4 = 1;
  11. const int CIPHER_AES = 2;
  12. const int CIPHER_BLOWFISH = 3;
  13. const int CIPHER_CAMELLIA = 4;
  14. private IntPtr _encryptCtx = IntPtr.Zero;
  15. private IntPtr _decryptCtx = IntPtr.Zero;
  16. public StreamMbedTLSEncryptor(string method, string password)
  17. : base(method, password)
  18. {
  19. }
  20. private static Dictionary<string, EncryptorInfo> _ciphers = new Dictionary<string, EncryptorInfo> {
  21. { "aes-128-cfb", new EncryptorInfo("AES-128-CFB128", 16, 16, CIPHER_AES) },
  22. { "aes-192-cfb", new EncryptorInfo("AES-192-CFB128", 24, 16, CIPHER_AES) },
  23. { "aes-256-cfb", new EncryptorInfo("AES-256-CFB128", 32, 16, CIPHER_AES) },
  24. { "aes-128-ctr", new EncryptorInfo("AES-128-CTR", 16, 16, CIPHER_AES) },
  25. { "aes-192-ctr", new EncryptorInfo("AES-192-CTR", 24, 16, CIPHER_AES) },
  26. { "aes-256-ctr", new EncryptorInfo("AES-256-CTR", 32, 16, CIPHER_AES) },
  27. { "bf-cfb", new EncryptorInfo("BLOWFISH-CFB64", 16, 8, CIPHER_BLOWFISH) },
  28. { "camellia-128-cfb", new EncryptorInfo("CAMELLIA-128-CFB128", 16, 16, CIPHER_CAMELLIA) },
  29. { "camellia-192-cfb", new EncryptorInfo("CAMELLIA-192-CFB128", 24, 16, CIPHER_CAMELLIA) },
  30. { "camellia-256-cfb", new EncryptorInfo("CAMELLIA-256-CFB128", 32, 16, CIPHER_CAMELLIA) },
  31. { "rc4-md5", new EncryptorInfo("ARC4-128", 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, EncryptorInfo> getCiphers()
  38. {
  39. return _ciphers;
  40. }
  41. protected override void initCipher(byte[] iv, bool isEncrypt)
  42. {
  43. base.initCipher(iv, isEncrypt);
  44. IntPtr ctx = Marshal.AllocHGlobal(MbedTLS.cipher_get_size_ex());
  45. if (isEncrypt)
  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. 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 System.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. isEncrypt ? MbedTLS.MBEDTLS_ENCRYPT : MbedTLS.MBEDTLS_DECRYPT) != 0 )
  81. throw new System.Exception("Cannot set mbed TLS cipher key");
  82. if (MbedTLS.cipher_set_iv(ctx, iv, ivLen) != 0)
  83. throw new System.Exception("Cannot set mbed TLS cipher IV");
  84. if (MbedTLS.cipher_reset(ctx) != 0)
  85. throw new System.Exception("Cannot finalize mbed TLS cipher context");
  86. }
  87. protected override void cipherUpdate(bool isEncrypt, 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(isEncrypt ? _encryptCtx : _decryptCtx,
  95. buf, length, outbuf, ref length) != 0 )
  96. throw new CryptoErrorException();
  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. ~StreamMbedTLSEncryptor()
  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. }