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

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