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.

OpenSSL.cs 6.1 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. using System;
  2. using System.IO;
  3. using System.Runtime.InteropServices;
  4. using System.Security;
  5. using System.Text;
  6. using NLog;
  7. using Shadowsocks.Controller;
  8. using Shadowsocks.Encryption.Exception;
  9. using Shadowsocks.Properties;
  10. using Shadowsocks.Util;
  11. namespace Shadowsocks.Encryption
  12. {
  13. // XXX: only for OpenSSL 1.1.0 and higher
  14. public static class OpenSSL
  15. {
  16. private static Logger logger = LogManager.GetCurrentClassLogger();
  17. private const string DLLNAME = "libsscrypto.dll";
  18. public const int OPENSSL_ENCRYPT = 1;
  19. public const int OPENSSL_DECRYPT = 0;
  20. public const int EVP_CTRL_AEAD_SET_IVLEN = 0x9;
  21. public const int EVP_CTRL_AEAD_GET_TAG = 0x10;
  22. public const int EVP_CTRL_AEAD_SET_TAG = 0x11;
  23. static OpenSSL()
  24. {
  25. string dllPath = Utils.GetTempPath(DLLNAME);
  26. try
  27. {
  28. FileManager.UncompressFile(dllPath, Resources.libsscrypto_dll);
  29. }
  30. catch (IOException)
  31. {
  32. }
  33. catch (System.Exception e)
  34. {
  35. logger.LogUsefulException(e);
  36. }
  37. LoadLibrary(dllPath);
  38. }
  39. public static IntPtr GetCipherInfo(string cipherName)
  40. {
  41. var name = Encoding.ASCII.GetBytes(cipherName);
  42. Array.Resize(ref name, name.Length + 1);
  43. return EVP_get_cipherbyname(name);
  44. }
  45. /// <summary>
  46. /// Need init cipher context after EVP_CipherFinal_ex to reuse context
  47. /// </summary>
  48. /// <param name="ctx"></param>
  49. /// <param name="cipherType"></param>
  50. /// <param name="nonce"></param>
  51. public static void SetCtxNonce(IntPtr ctx, byte[] nonce, bool isEncrypt)
  52. {
  53. var ret = EVP_CipherInit_ex(ctx, IntPtr.Zero,
  54. IntPtr.Zero, null,
  55. nonce,
  56. isEncrypt ? OPENSSL_ENCRYPT : OPENSSL_DECRYPT);
  57. if (ret != 1) throw new System.Exception("openssl: fail to set AEAD nonce");
  58. }
  59. public static void AEADGetTag(IntPtr ctx, byte[] tagbuf, int taglen)
  60. {
  61. IntPtr tagBufIntPtr = IntPtr.Zero;
  62. try
  63. {
  64. tagBufIntPtr = Marshal.AllocHGlobal(taglen);
  65. var ret = EVP_CIPHER_CTX_ctrl(ctx,
  66. EVP_CTRL_AEAD_GET_TAG, taglen, tagBufIntPtr);
  67. if (ret != 1) throw new CryptoErrorException("openssl: fail to get AEAD tag");
  68. // take tag from unmanaged memory
  69. Marshal.Copy(tagBufIntPtr, tagbuf, 0, taglen);
  70. }
  71. finally
  72. {
  73. if (tagBufIntPtr != IntPtr.Zero)
  74. {
  75. Marshal.FreeHGlobal(tagBufIntPtr);
  76. }
  77. }
  78. }
  79. public static void AEADSetTag(IntPtr ctx, byte[] tagbuf, int taglen)
  80. {
  81. IntPtr tagBufIntPtr = IntPtr.Zero;
  82. try
  83. {
  84. // allocate unmanaged memory for tag
  85. tagBufIntPtr = Marshal.AllocHGlobal(taglen);
  86. // copy tag to unmanaged memory
  87. Marshal.Copy(tagbuf, 0, tagBufIntPtr, taglen);
  88. var ret = EVP_CIPHER_CTX_ctrl(ctx,
  89. EVP_CTRL_AEAD_SET_TAG, taglen, tagBufIntPtr);
  90. if (ret != 1) throw new CryptoErrorException("openssl: fail to set AEAD tag");
  91. }
  92. finally
  93. {
  94. if (tagBufIntPtr != IntPtr.Zero)
  95. {
  96. Marshal.FreeHGlobal(tagBufIntPtr);
  97. }
  98. }
  99. }
  100. [DllImport("Kernel32.dll")]
  101. private static extern IntPtr LoadLibrary(string path);
  102. [SuppressUnmanagedCodeSecurity]
  103. [DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]
  104. public static extern IntPtr EVP_CIPHER_CTX_new();
  105. [SuppressUnmanagedCodeSecurity]
  106. [DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]
  107. public static extern void EVP_CIPHER_CTX_free(IntPtr ctx);
  108. [SuppressUnmanagedCodeSecurity]
  109. [DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]
  110. public static extern int EVP_CIPHER_CTX_reset(IntPtr ctx);
  111. [SuppressUnmanagedCodeSecurity]
  112. [DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]
  113. public static extern int EVP_CipherInit_ex(IntPtr ctx, IntPtr type,
  114. IntPtr impl, byte[] key, byte[] iv, int enc);
  115. [SuppressUnmanagedCodeSecurity]
  116. [DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]
  117. public static extern int EVP_CipherUpdate(IntPtr ctx, byte[] outb,
  118. out int outl, byte[] inb, int inl);
  119. [SuppressUnmanagedCodeSecurity]
  120. [DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]
  121. public static extern int EVP_CipherFinal_ex(IntPtr ctx, byte[] outm, ref int outl);
  122. [SuppressUnmanagedCodeSecurity]
  123. [DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]
  124. public static extern int EVP_CIPHER_CTX_set_padding(IntPtr x, int padding);
  125. [SuppressUnmanagedCodeSecurity]
  126. [DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]
  127. public static extern int EVP_CIPHER_CTX_set_key_length(IntPtr x, int keylen);
  128. [SuppressUnmanagedCodeSecurity]
  129. [DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]
  130. public static extern int EVP_CIPHER_CTX_ctrl(IntPtr ctx, int type, int arg, IntPtr ptr);
  131. /// <summary>
  132. /// simulate NUL-terminated string
  133. /// </summary>
  134. /// <param name="name"></param>
  135. /// <returns></returns>
  136. [SuppressUnmanagedCodeSecurity]
  137. [DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]
  138. public static extern IntPtr EVP_get_cipherbyname(byte[] name);
  139. }
  140. }