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.

AEADMbedTLSEncryptor.cs 6.2 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Diagnostics;
  4. using System.Runtime.InteropServices;
  5. using Shadowsocks.Encryption.Exception;
  6. namespace Shadowsocks.Encryption.AEAD
  7. {
  8. public class AEADMbedTLSEncryptor
  9. : AEADEncryptor, IDisposable
  10. {
  11. const int CIPHER_AES = 1;
  12. private IntPtr _encryptCtx = IntPtr.Zero;
  13. private IntPtr _decryptCtx = IntPtr.Zero;
  14. public AEADMbedTLSEncryptor(string method, string password)
  15. : base(method, password)
  16. {
  17. }
  18. private static readonly Dictionary<string, EncryptorInfo> _ciphers = new Dictionary<string, EncryptorInfo>
  19. {
  20. {"aes-128-gcm", new EncryptorInfo("AES-128-GCM", 16, 16, 12, 16, CIPHER_AES)},
  21. {"aes-192-gcm", new EncryptorInfo("AES-192-GCM", 24, 24, 12, 16, CIPHER_AES)},
  22. {"aes-256-gcm", new EncryptorInfo("AES-256-GCM", 32, 32, 12, 16, CIPHER_AES)},
  23. };
  24. public static List<string> SupportedCiphers()
  25. {
  26. return new List<string>(_ciphers.Keys);
  27. }
  28. protected override Dictionary<string, EncryptorInfo> getCiphers()
  29. {
  30. return _ciphers;
  31. }
  32. public override void InitCipher(byte[] salt, bool isEncrypt, bool isUdp)
  33. {
  34. base.InitCipher(salt, isEncrypt, isUdp);
  35. IntPtr ctx = Marshal.AllocHGlobal(MbedTLS.cipher_get_size_ex());
  36. if (isEncrypt)
  37. {
  38. _encryptCtx = ctx;
  39. }
  40. else
  41. {
  42. _decryptCtx = ctx;
  43. }
  44. MbedTLS.cipher_init(ctx);
  45. if (MbedTLS.cipher_setup(ctx, MbedTLS.cipher_info_from_string(_innerLibName)) != 0)
  46. throw new System.Exception("Cannot initialize mbed TLS cipher context");
  47. DeriveSessionKey(isEncrypt ? _encryptSalt : _decryptSalt,
  48. _Masterkey, _sessionKey);
  49. CipherSetKey(isEncrypt, _sessionKey);
  50. }
  51. private void CipherSetKey(bool isEncrypt, byte[] key)
  52. {
  53. IntPtr ctx = isEncrypt ? _encryptCtx : _decryptCtx;
  54. int ret = MbedTLS.cipher_setkey(ctx, key, keyLen * 8,
  55. isEncrypt ? MbedTLS.MBEDTLS_ENCRYPT : MbedTLS.MBEDTLS_DECRYPT);
  56. if (ret != 0) throw new System.Exception("failed to set key");
  57. ret = MbedTLS.cipher_reset(ctx);
  58. if (ret != 0) throw new System.Exception("failed to finish preparation");
  59. }
  60. public override void cipherEncrypt(byte[] plaintext, uint plen, byte[] ciphertext, ref uint clen)
  61. {
  62. // buf: all plaintext
  63. // outbuf: ciphertext + tag
  64. int ret;
  65. byte[] tagbuf = new byte[tagLen];
  66. uint olen = 0;
  67. switch (_cipher)
  68. {
  69. case CIPHER_AES:
  70. ret = MbedTLS.cipher_auth_encrypt(_encryptCtx,
  71. /* nonce */
  72. _encNonce, (uint) nonceLen,
  73. /* AD */
  74. IntPtr.Zero, 0,
  75. /* plain */
  76. plaintext, plen,
  77. /* cipher */
  78. ciphertext, ref olen,
  79. tagbuf, (uint) tagLen);
  80. if (ret != 0) throw new CryptoErrorException(String.Format("ret is {0}", ret));
  81. Debug.Assert(olen == plen);
  82. // attach tag to ciphertext
  83. Array.Copy(tagbuf, 0, ciphertext, (int) plen, tagLen);
  84. clen = olen + (uint) tagLen;
  85. break;
  86. default:
  87. throw new System.Exception("not implemented");
  88. }
  89. }
  90. public override void cipherDecrypt(byte[] ciphertext, uint clen, byte[] plaintext, ref uint plen)
  91. {
  92. // buf: ciphertext + tag
  93. // outbuf: plaintext
  94. int ret;
  95. uint olen = 0;
  96. // split tag
  97. byte[] tagbuf = new byte[tagLen];
  98. Array.Copy(ciphertext, (int) (clen - tagLen), tagbuf, 0, tagLen);
  99. switch (_cipher)
  100. {
  101. case CIPHER_AES:
  102. ret = MbedTLS.cipher_auth_decrypt(_decryptCtx,
  103. _decNonce, (uint) nonceLen,
  104. IntPtr.Zero, 0,
  105. ciphertext, (uint) (clen - tagLen),
  106. plaintext, ref olen,
  107. tagbuf, (uint) tagLen);
  108. if (ret != 0) throw new CryptoErrorException(String.Format("ret is {0}", ret));
  109. Debug.Assert(olen == clen - tagLen);
  110. plen = olen;
  111. break;
  112. default:
  113. throw new System.Exception("not implemented");
  114. }
  115. }
  116. #region IDisposable
  117. private bool _disposed;
  118. // instance based lock
  119. private readonly object _lock = new object();
  120. public override void Dispose()
  121. {
  122. Dispose(true);
  123. GC.SuppressFinalize(this);
  124. }
  125. ~AEADMbedTLSEncryptor()
  126. {
  127. Dispose(false);
  128. }
  129. protected virtual void Dispose(bool disposing)
  130. {
  131. lock (_lock)
  132. {
  133. if (_disposed) return;
  134. _disposed = true;
  135. }
  136. if (disposing)
  137. {
  138. // free managed objects
  139. }
  140. // free unmanaged objects
  141. if (_encryptCtx != IntPtr.Zero)
  142. {
  143. MbedTLS.cipher_free(_encryptCtx);
  144. Marshal.FreeHGlobal(_encryptCtx);
  145. _encryptCtx = IntPtr.Zero;
  146. }
  147. if (_decryptCtx != IntPtr.Zero)
  148. {
  149. MbedTLS.cipher_free(_decryptCtx);
  150. Marshal.FreeHGlobal(_decryptCtx);
  151. _decryptCtx = IntPtr.Zero;
  152. }
  153. }
  154. #endregion
  155. }
  156. }