首页 > 解决方案 > 将 advapi32.dll 加密功能移植到 Linux 容器 C#

问题描述

我们有使用 PublicKey 加密的遗留功能。我们希望将此代码路径迁移到 Linux 容器中。

advapi32.dll在 Linux 中无效。我们需要使用在 Linux 容器中工作的相应 .net 核心跨平台代码。

CryptAcquireContext,CryptExportKey,CryptExportKey,CryptImportKey,CryptEncrypt,CryptGenKey,CryptDestroyKey,CryptReleaseContext在 Linux 容器上支持的 C# ( ) 中编写相应 DllImport 方法的任何指针或指导?

这是我们的代码。

        internal static string Encrypt(string textToEncrypt, string publicKey)
        {
            publicKey = publicKey.StartsWith("0x", StringComparison.OrdinalIgnoreCase) ?
                publicKey.Remove(0, 2) : publicKey;

            // delete version string
            string publicKeyMaterial = publicKey.Remove(0, 44);

            byte[] publicKeyBytes = HexToByteArray(publicKeyMaterial);

            IntPtr hProv = IntPtr.Zero;

            if (CryptAcquireContext(ref hProv, IntPtr.Zero, null, PROV_RSA_AES, CRYPT_VERIFYCONTEXT) == 0)
            {
                throw new Exception(String.Format(CultureInfo.InvariantCulture, "Error aquiring key container context. ErrorId: {0}",
                    Marshal.GetLastWin32Error()));
            }

            IntPtr hPublicKey = IntPtr.Zero;

            // import public key to key container
            if (CryptImportKey(hProv, publicKeyBytes, publicKeyBytes.Length, IntPtr.Zero, CRYPT_EXPORTABLE,
                    ref hPublicKey) == 0)
            {
                throw new Exception(String.Format(CultureInfo.InvariantCulture, "Error importing key. ErrorId: {0}",
                    Marshal.GetLastWin32Error()));
            }

            IntPtr hSessionHandle = IntPtr.Zero;

            if (CryptGenKey(hProv, new IntPtr(CALG_AES_192), CRYPT_EXPORTABLE,
                    ref hSessionHandle) == 0)
            {
                throw new Exception(String.Format(CultureInfo.InvariantCulture, "Error generating session key. ErrorId: {0}",
                    Marshal.GetLastWin32Error()));
            }

            int sessionBlobLength = 0;

            // exports length of wrapped session key 
            if (CryptExportKey(hSessionHandle, hPublicKey, SIMPLEBLOB, 0, IntPtr.Zero,
                    ref sessionBlobLength) == 0)
            {
                throw new Exception(String.Format(CultureInfo.InvariantCulture, "Error exporting session key length. ErrorId: {0}, key: {1}, hSessionHandle: {2}, hPublicKey: {3}",
                    Marshal.GetLastWin32Error(), publicKey, hSessionHandle, hPublicKey));
            }

            byte[] exportedSessionKey = new byte[sessionBlobLength];

            // exports session key wrapped with public key
            if (CryptExportKey(hSessionHandle, hPublicKey, SIMPLEBLOB, 0, exportedSessionKey,
                    ref sessionBlobLength) == 0)
            {
                throw new Exception(String.Format(CultureInfo.InvariantCulture, "Error exporting session key. ErrorId: {0}",
                    Marshal.GetLastWin32Error()));
            }

            byte[] bytesToEncrypt = Encoding.Unicode.GetBytes(textToEncrypt);

            int dataLength = bytesToEncrypt.Length;
            int bufferLen = bytesToEncrypt.Length;

            // get the length of the cipher text
            if (CryptEncrypt(hSessionHandle, 0, true, 0, null, ref dataLength, bufferLen) == 0)
            {
                throw new Exception(String.Format(CultureInfo.InvariantCulture, "Error while getting cipher text length. ErrorId: {0}",
                    Marshal.GetLastWin32Error()));
            }

            byte[] buffer = new byte[dataLength];
            Buffer.BlockCopy(bytesToEncrypt, 0, buffer, 0, bytesToEncrypt.Length);

            dataLength = bytesToEncrypt.Length;
            bufferLen = buffer.Length;

            if (CryptEncrypt(hSessionHandle, 0, true, 0, buffer, ref dataLength, bufferLen) == 0)
            {
                throw new Exception(String.Format(CultureInfo.InvariantCulture, "Error while encrypting data. ErrorId: {0}",
                    Marshal.GetLastWin32Error()));
            }

            // key/container clean up
            CryptDestroyKey(hSessionHandle);
            CryptDestroyKey(hPublicKey);
            CryptReleaseContext(hProv, 0);

            EncryptedData encryptedData = new EncryptedData();
            encryptedData.CipherText = buffer;
            encryptedData.ExportedSessionKey = exportedSessionKey;
            encryptedData.PublicKeyHeader = EncryptedData.ExtractPublicKeyHeader(publicKey);
            encryptedData.SessionKeyType = KeyType.SESSION_KEY_AES_192;

            return encryptedData.ToString();
        }

        private static byte[] HexToByteArray(String hexString)
        {
            int OutputByteCount = hexString.Length / 2;

            byte[] bytes = new byte[OutputByteCount];

            for (int i = 0; i < hexString.Length; i += 2)
            {
                bytes[i / 2] = Convert.ToByte(hexString.Substring(i, 2), 16);
            }

            return bytes;
        }

        #region CryptoAPI Constants
        private const int CRYPT_VERIFYCONTEXT = -268435456;
        private const int PROV_RSA_FULL = 1;
        private const int PROV_RSA_AES = 24;
        private const int CRYPT_EXPORTABLE = 1;
        private const int SIMPLEBLOB = 1;
        private const int CALG_3DES = 26115; // (3 << 13) | (3 << 9) | 3;
        private const int CALG_AES_192 = 26126; // (3 << 13) | (3 << 9) | 14;
        #endregion CryptoAPI Constants

        [DllImport(@"advapi32.dll", SetLastError = true)] // do not remove SetLastError
        private static extern int CryptAcquireContext(ref IntPtr phProv, IntPtr pszContainer,
            string pszProvider, int dwProvType, int dwFlags);

        [DllImport(@"advapi32.dll", SetLastError = true)]
        private static extern int CryptExportKey(IntPtr hKey, IntPtr hExpKey, int dwBlobType,
            int dwFlags, IntPtr pbData, ref int pdwDataLen);

        [DllImport(@"advapi32.dll", SetLastError = true)]
        private static extern int CryptExportKey(IntPtr hKey, IntPtr hExpKey, int dwBlobType,
            int dwFlags, byte[] pbData, ref int pdwDataLen);

        [DllImport(@"advapi32.dll", SetLastError = true)]
        private static extern int CryptImportKey(IntPtr hProv, byte[] pbData, int dwDataLen,
            IntPtr hPubKey, int dwFlags, ref IntPtr phKey);

        [DllImport(@"advapi32.dll")]
        private static extern int CryptEncrypt(IntPtr hKey, int hHash, bool Final, int dwFlags,
            byte[] pbData, ref int pdwDataLen, int dwBufLen);

        [DllImport(@"advapi32.dll", SetLastError = true)]
        private static extern int CryptGenKey(IntPtr hProv, IntPtr Algid, int dwFlags,
            ref IntPtr phKey);

        [DllImport(@"advapi32.dll", SetLastError = true)]
        private static extern int CryptDestroyKey(IntPtr hKey);

        [DllImport(@"advapi32.dll", SetLastError = true)]
        private static extern int CryptReleaseContext(IntPtr hProv, int dwFlags);

        private enum KeyType : short
        {
            SESSION_KEY_3DES = 1,
            SESSION_KEY_AES_192 = 2
        }

        private struct EncryptedData { ... }

标签: c#cryptographycontainersinteropcryptoapi

解决方案


推荐阅读