mirror of
https://github.com/bolucat/Archive.git
synced 2025-10-06 08:39:35 +08:00
164 lines
5.8 KiB
C#
164 lines
5.8 KiB
C#
using System;
|
|
using System.IO;
|
|
using System.Runtime.InteropServices;
|
|
using System.Security;
|
|
using System.Text;
|
|
using NLog;
|
|
using Shadowsocks.Controller;
|
|
using Shadowsocks.Encryption.Exception;
|
|
using Shadowsocks.Properties;
|
|
using Shadowsocks.Util;
|
|
|
|
namespace Shadowsocks.Encryption
|
|
{
|
|
// XXX: only for OpenSSL 1.1.0 and higher
|
|
public static class OpenSSL
|
|
{
|
|
private static Logger logger = LogManager.GetCurrentClassLogger();
|
|
|
|
private const string DLLNAME = "libsscrypto.dll";
|
|
|
|
public const int OPENSSL_ENCRYPT = 1;
|
|
public const int OPENSSL_DECRYPT = 0;
|
|
|
|
public const int EVP_CTRL_AEAD_SET_IVLEN = 0x9;
|
|
public const int EVP_CTRL_AEAD_GET_TAG = 0x10;
|
|
public const int EVP_CTRL_AEAD_SET_TAG = 0x11;
|
|
|
|
static OpenSSL()
|
|
{
|
|
string dllPath = Utils.GetTempPath(DLLNAME);
|
|
try
|
|
{
|
|
FileManager.UncompressFile(dllPath, Resources.libsscrypto_dll);
|
|
}
|
|
catch (IOException)
|
|
{
|
|
}
|
|
catch (System.Exception e)
|
|
{
|
|
logger.LogUsefulException(e);
|
|
}
|
|
LoadLibrary(dllPath);
|
|
}
|
|
|
|
public static IntPtr GetCipherInfo(string cipherName)
|
|
{
|
|
var name = Encoding.ASCII.GetBytes(cipherName);
|
|
Array.Resize(ref name, name.Length + 1);
|
|
return EVP_get_cipherbyname(name);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Need init cipher context after EVP_CipherFinal_ex to reuse context
|
|
/// </summary>
|
|
/// <param name="ctx"></param>
|
|
/// <param name="cipherType"></param>
|
|
/// <param name="nonce"></param>
|
|
public static void SetCtxNonce(IntPtr ctx, byte[] nonce, bool isEncrypt)
|
|
{
|
|
var ret = EVP_CipherInit_ex(ctx, IntPtr.Zero,
|
|
IntPtr.Zero, null,
|
|
nonce,
|
|
isEncrypt ? OPENSSL_ENCRYPT : OPENSSL_DECRYPT);
|
|
if (ret != 1) throw new System.Exception("openssl: fail to set AEAD nonce");
|
|
}
|
|
|
|
public static void AEADGetTag(IntPtr ctx, byte[] tagbuf, int taglen)
|
|
{
|
|
IntPtr tagBufIntPtr = IntPtr.Zero;
|
|
try
|
|
{
|
|
tagBufIntPtr = Marshal.AllocHGlobal(taglen);
|
|
var ret = EVP_CIPHER_CTX_ctrl(ctx,
|
|
EVP_CTRL_AEAD_GET_TAG, taglen, tagBufIntPtr);
|
|
if (ret != 1) throw new CryptoErrorException("openssl: fail to get AEAD tag");
|
|
// take tag from unmanaged memory
|
|
Marshal.Copy(tagBufIntPtr, tagbuf, 0, taglen);
|
|
}
|
|
finally
|
|
{
|
|
if (tagBufIntPtr != IntPtr.Zero)
|
|
{
|
|
Marshal.FreeHGlobal(tagBufIntPtr);
|
|
}
|
|
}
|
|
}
|
|
|
|
public static void AEADSetTag(IntPtr ctx, byte[] tagbuf, int taglen)
|
|
{
|
|
IntPtr tagBufIntPtr = IntPtr.Zero;
|
|
try
|
|
{
|
|
// allocate unmanaged memory for tag
|
|
tagBufIntPtr = Marshal.AllocHGlobal(taglen);
|
|
|
|
// copy tag to unmanaged memory
|
|
Marshal.Copy(tagbuf, 0, tagBufIntPtr, taglen);
|
|
|
|
var ret = EVP_CIPHER_CTX_ctrl(ctx,
|
|
EVP_CTRL_AEAD_SET_TAG, taglen, tagBufIntPtr);
|
|
|
|
if (ret != 1) throw new CryptoErrorException("openssl: fail to set AEAD tag");
|
|
|
|
}
|
|
finally
|
|
{
|
|
if (tagBufIntPtr != IntPtr.Zero)
|
|
{
|
|
Marshal.FreeHGlobal(tagBufIntPtr);
|
|
}
|
|
}
|
|
}
|
|
|
|
[DllImport("Kernel32.dll")]
|
|
private static extern IntPtr LoadLibrary(string path);
|
|
|
|
[SuppressUnmanagedCodeSecurity]
|
|
[DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]
|
|
public static extern IntPtr EVP_CIPHER_CTX_new();
|
|
|
|
[SuppressUnmanagedCodeSecurity]
|
|
[DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]
|
|
public static extern void EVP_CIPHER_CTX_free(IntPtr ctx);
|
|
|
|
[SuppressUnmanagedCodeSecurity]
|
|
[DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]
|
|
public static extern int EVP_CIPHER_CTX_reset(IntPtr ctx);
|
|
|
|
[SuppressUnmanagedCodeSecurity]
|
|
[DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]
|
|
public static extern int EVP_CipherInit_ex(IntPtr ctx, IntPtr type,
|
|
IntPtr impl, byte[] key, byte[] iv, int enc);
|
|
|
|
[SuppressUnmanagedCodeSecurity]
|
|
[DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]
|
|
public static extern int EVP_CipherUpdate(IntPtr ctx, byte[] outb,
|
|
out int outl, byte[] inb, int inl);
|
|
|
|
[SuppressUnmanagedCodeSecurity]
|
|
[DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]
|
|
public static extern int EVP_CipherFinal_ex(IntPtr ctx, byte[] outm, ref int outl);
|
|
|
|
[SuppressUnmanagedCodeSecurity]
|
|
[DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]
|
|
public static extern int EVP_CIPHER_CTX_set_padding(IntPtr x, int padding);
|
|
|
|
[SuppressUnmanagedCodeSecurity]
|
|
[DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]
|
|
public static extern int EVP_CIPHER_CTX_set_key_length(IntPtr x, int keylen);
|
|
|
|
[SuppressUnmanagedCodeSecurity]
|
|
[DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]
|
|
public static extern int EVP_CIPHER_CTX_ctrl(IntPtr ctx, int type, int arg, IntPtr ptr);
|
|
|
|
/// <summary>
|
|
/// simulate NUL-terminated string
|
|
/// </summary>
|
|
/// <param name="name"></param>
|
|
/// <returns></returns>
|
|
[SuppressUnmanagedCodeSecurity]
|
|
[DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]
|
|
public static extern IntPtr EVP_get_cipherbyname(byte[] name);
|
|
}
|
|
} |