简体   繁体   English

C++ & C# 调用 CryptEncrypt 和 CryptDecrypt

[英]C++ & C# Call CryptEncrypt and CryptDecrypt

Hello i am trying to Encrypt and Decrypt between C++ and C# have made a dll project using CryptEncrypt wincrypt here code i used C++您好,我正在尝试在 C++ 和 C# 之间进行加密和解密,已经使用 CryptEncrypt wincrypt 制作了一个 dll 项目,这里的代码我使用了 C++

#include <Windows.h>
#include <stdio.h>
extern "C" __declspec(dllexport)

BOOL EncryptData(char* szData, char* szPassword, char* szErroror, BYTE* pData, BYTE* pDataLen, BOOL Encrypt)
{
    HANDLE hSourceFile = INVALID_HANDLE_VALUE;
    HANDLE hDestinationFile = INVALID_HANDLE_VALUE;

    HCRYPTPROV hProv = NULL;
    HCRYPTKEY hKey = NULL;
    HCRYPTKEY hXchgKey = NULL;
    HCRYPTHASH hHash = NULL;

    PBYTE pbKeyBlob = NULL;
    DWORD dwKeyBlobLen;

    PBYTE pbBuffer = NULL;
    DWORD dwBlockLen = 0;
    DWORD dwBufferLen = 0;
    DWORD dwCount = 0;
    bool bRet = true;

    int len = strlen(szData);

    if (!CryptAcquireContext(&hProv, NULL, MS_ENHANCED_PROV, PROV_RSA_FULL, 0))
    {
        if (!CryptAcquireContext(&hProv, NULL, MS_ENHANCED_PROV, PROV_RSA_FULL, CRYPT_NEWKEYSET))
            return false;
    }

    // Create a hash object.
    if (!CryptCreateHash(hProv, CALG_MD5, 0, 0, &hHash))
        return false;

    // Hash in the password data.
    if (!CryptHashData(hHash, (BYTE*)szPassword, strlen(szPassword), 0))
        return false;

    // Derive a session key from the hash object.
    if (!CryptDeriveKey(hProv, CALG_RC4, hHash, 0x00800000, &hKey))
        return false;

    dwBlockLen = 1000 - 1000 % 8;

    // Allocate memory.
    if ((pbBuffer = (BYTE*)malloc(dwBufferLen)) == NULL)
        return false;

    if (Encrypt)
    {
        if (!CryptEncrypt(hKey, 0, false, 0, pbBuffer, &dwCount, dwBufferLen))
        {
            DWORD  dwError = GetLastError();
            strcpy(szErroror, "CryptEncrypt Failed Error ");
            char szError[10];
            memset(szError, 0, 10);
            sprintf(szError, "%d", dwError);
            strcat(szErroror, szError);
            bRet = false;
        }
    }
    else
    {
        if (!CryptDecrypt(hKey, 0, false, 0, pbBuffer, &dwCount))
        {
            DWORD  dwError = GetLastError();
            strcpy(szErroror, "CryptDecrypt Failed Error ");
            char szError[10];
            memset(szError, 0, 10);
            sprintf(szError, "%d", dwError);
            strcat(szErroror, szError);
            bRet = false;
        }
    }

    char szDataLen[16];
    memset(szDataLen, 0, 16);
    sprintf(szDataLen, "%d", dwCount);
    memcpy(pDataLen, szDataLen, 16);

    BYTE* pMyData = (BYTE*)malloc(len);

    memset(pMyData, 0, len);
    memcpy(pData, pbBuffer, len);

    // Free memory.
    if (pbKeyBlob) free(pbKeyBlob);
    if (pbBuffer) free(pbBuffer);
    if (pMyData) free(pMyData);

    // Destroy session key.
    if (hKey) CryptDestroyKey(hKey);

    // Release key exchange key handle.
    if (hXchgKey) CryptDestroyKey(hXchgKey);

    // Destroy hash object.
    if (hHash) CryptDestroyHash(hHash);

    // Release provider handle.
    if (hProv) CryptReleaseContext(hProv, 0);

    return bRet;
}

And C# Project Calling the dll and the funcation和C#项目调用dll和函数

namespace ConsoleApp1
{
    class Program
    {
        [DllImport("Project3.dll", CallingConvention = CallingConvention.Cdecl)]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool EncryptData(byte[] szData, char[] szPassword, StringBuilder sbError, byte[] pData, byte[] pDataLen, bool Encrypt);

        static void Main(string[] args)
        {

            StringBuilder sbError = new StringBuilder(255);
            byte[] szData = Encoding.ASCII.GetBytes("datatest");
            char[] szPassword = ("test").ToCharArray();
            byte[] pData = new byte[1008];
            byte[] pDataLen = new byte[16];
            Console.WriteLine("Encrypt");
            bool bRet = EncryptData(szData, szPassword, sbError, pData, pDataLen, true);

            Console.WriteLine(Encoding.ASCII.GetString(pData));

            Console.WriteLine("Decrypt");
            bool bRet2 = EncryptData(szData, szPassword, sbError, pData, pDataLen, false);
            Console.WriteLine(Encoding.ASCII.GetString(pData));

            Console.ReadKey();

        }
    }
}

but i have a problem with Decrypt但我有解密问题

out出去

Encrypt ??rc?加密??rc?
Decrypt datatestx?解密datatestx?

Encrypt 1?8V?6N5l???加密1?8V?6N5l???
Decrypt d ??解密 ?? - ——

as you can see the Decrypt is wrong what could be wrong正如你所看到的 Decrypt 是错的 什么可能是错的

First of all your C/C++ code uses deprecated Windows functions, secondly, there are a lot of "unsecure" C runtime functions used like: "strcpy", "strcat", "sprintf" etc. etc., thirdly not all code is guarding against buffer coding errors.首先,您的 C/C++ 代码使用不推荐使用的 Windows 函数,其次,使用了许多“不安全”的 C 运行时函数,例如:“strcpy”、“strcat”、“sprintf”等,第三并非所有代码都是防止缓冲区编码错误。 The C code as is does not compile in any recent Visual Studio compiler without significant corrections.如果没有重大修正,C 代码在任何最近的 Visual Studio 编译器中都不会编译。

Pls try fixing all errors, simplify code and post it again.请尝试修复所有错误,简化代码并再次发布。

On the C# side, data buffers that are passed to C code are not pinned and can be moved by GC at any time.在 C# 端,传递给 C 代码的数据缓冲区没有固定,可以随时由 GC 移动。 Due to its small size, they could be eagerly promoted from Gen 0 to Gen 1 by GC what will cause memory move operation and invalidation of the pointer to buffer.由于其体积小,它们可以通过 GC 急切地从 Gen 0 提升到 Gen 1,这将导致内存移动操作和指向缓冲区的指针无效。 To put it simply pointers to all buffers may be invalid at the moment they are read by C code.简单地说,指向所有缓冲区的指针在它们被 C 代码读取时可能是无效的。

On the C# side you could do the following:在 C# 方面,您可以执行以下操作:

    [DllImport("Project3.dll", CallingConvention = CallingConvention.Cdecl)]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static unsafe extern bool EncryptData(
        byte* szData, char* szPassword, StringBuilder sbError, byte* pData, byte* pDataLen, bool Encrypt);

    static unsafe void Main(string[] args)
    {
        StringBuilder sbError = new StringBuilder(255);
        byte[] szDataBuff = Encoding.ASCII.GetBytes("datatest");
        char[] szPasswordBuff = ("test").ToCharArray();
        byte[] pDataBuff = new byte[1008];
        byte[] pDataLenBuff = new byte[16];

        fixed (byte* szData = szDataBuff)
        fixed (char* szPassword = szPasswordBuff)
        fixed (byte* pData = pDataBuff)
        fixed (byte* pDataLen = pDataLenBuff)
        {
            Console.WriteLine("Encrypt");
            bool bRet = EncryptData(szData, szPassword, sbError, pData, pDataLen, true);

            Console.WriteLine("Encrypted: {0}", bRet);
            Console.WriteLine(Marshal.PtrToStringAnsi((IntPtr)pData));

            Console.WriteLine("Decrypt");
            bool bRet2 = EncryptData(szData, szPassword, sbError, pData, pDataLen, false);
            Console.WriteLine("Derypted: {0}", bRet2);
            Console.WriteLine(Marshal.PtrToStringAnsi((IntPtr)pData));
        }

        Console.ReadKey();
    }

There are other approaches possible but this one seems to be most straightforward and simple.还有其他可能的方法,但这种方法似乎是最直接和最简单的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM