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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  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. 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( _innerLibName ) ) != 0 )
  68. throw new System.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,
  81. isEncrypt ? MbedTLS.MBEDTLS_ENCRYPT : MbedTLS.MBEDTLS_DECRYPT) != 0 )
  82. throw new System.Exception("Cannot set mbed TLS cipher key");
  83. if (MbedTLS.cipher_set_iv(ctx, iv, ivLen) != 0)
  84. throw new System.Exception("Cannot set mbed TLS cipher IV");
  85. if (MbedTLS.cipher_reset(ctx) != 0)
  86. throw new System.Exception("Cannot finalize mbed TLS cipher context");
  87. }
  88. protected override void cipherUpdate(bool isEncrypt, int length, byte[] buf, byte[] outbuf)
  89. {
  90. // C# could be multi-threaded
  91. if (_disposed)
  92. {
  93. throw new ObjectDisposedException(this.ToString());
  94. }
  95. if (MbedTLS.cipher_update(isEncrypt ? _encryptCtx : _decryptCtx,
  96. buf, length, outbuf, ref length) != 0 )
  97. throw new CryptoErrorException();
  98. }
  99. #region IDisposable
  100. private bool _disposed;
  101. // instance based lock
  102. private readonly object _lock = new object();
  103. public override void Dispose()
  104. {
  105. Dispose(true);
  106. GC.SuppressFinalize(this);
  107. }
  108. ~StreamMbedTLSEncryptor()
  109. {
  110. Dispose(false);
  111. }
  112. protected virtual void Dispose(bool disposing)
  113. {
  114. lock (_lock)
  115. {
  116. if (_disposed) return;
  117. _disposed = true;
  118. }
  119. if (disposing)
  120. {
  121. // free managed objects
  122. }
  123. // free unmanaged objects
  124. if (_encryptCtx != IntPtr.Zero)
  125. {
  126. MbedTLS.cipher_free(_encryptCtx);
  127. Marshal.FreeHGlobal(_encryptCtx);
  128. _encryptCtx = IntPtr.Zero;
  129. }
  130. if (_decryptCtx != IntPtr.Zero)
  131. {
  132. MbedTLS.cipher_free(_decryptCtx);
  133. Marshal.FreeHGlobal(_decryptCtx);
  134. _decryptCtx = IntPtr.Zero;
  135. }
  136. }
  137. #endregion
  138. }
  139. }