在c++端使用BCrypt.lib对数据进行非对称加密,并在c#端使用RSACryptoServiceProvider进行解密。 (参数有误)

问题描述 投票:0回答:1

我有一个用 .NET (C#) 编写的 Windows 服务和一个用 CPP 编写的库。我正在 .NET 端使用 RSACryptoServiceProvider 生成公钥/私钥对,并将公钥信息发送到 CPP 端。 在 C++ 端,导入从 C# 收到的公钥后,我使用 BCrypt.lib 库加密我的数据,并通过将其编码为 base64 将其返回到 .net 服务。 现在在 .Net 端,我正在使用 RSACryptoServiceProvider 解密从 C++ 接收到的编码数据。

在 RSA.Decrypt() 方法调用期间,我遇到以下异常:

CryptographicException: 'The parameter is incorrect'

对我来说这似乎是一些编码问题,但我不是这里的专家。

我尝试过以下解决方案:

  • 使用Convert.FromBase64String()方法将接收到的base64数据转换为字节数组。
  • 我尝试反转从上述转换收到的字节数组。

下面是我正在处理的代码片段。

.网端代码:

var rsa = RSACryptoServiceProvider.Create(1024);
var publicKey = rsa.ToXmlString(false);

var encryptedData = Convert.FromBase64String(GetEncryptedDataFromCPP(publicKey));
//Array.Reverse(encryptedData); 

byte[] decryptedData = rsa.Decrypt(encryptedData, RSAEncryptionPadding.Pkcs1); //CryptographyException: Invalid Parameter
var decryptedDataValue = Encoding.UTF8.GetString(decryptedData);

.C++ 边代码:

VOID GetEncryptedDataFromCPP(publicKey)
{
    BYTE* pbPublicKey = NULL;
    DWORD cbExp = 3;
    DWORD cbModulus = 128;
    DWORD cbKey = cbExp + sizeof(BCRYPT_RSAKEY_BLOB) + cbModulus;
    BCRYPT_RSAKEY_BLOB* pRsaBlob;
    PBYTE pbCurrent;

//**Assuming I have fetched the Modulus and Exponent from the xml string and assigned as below.**
    std::string modulus = "3XCSEveWJ3Mp41g5VxcmmlCYDL5X+VUX1ULOIl8TdsEu6bbS/Ho0ofBgAwglCrbRgAjm7ZW+EivEVLZRx5FVsEYqGX12fFZSn84Ye6D2rUYqvwR0kBE8MBCdirqg3gXAlmuIgxucWcxiT9NDTaC67Awe9yyQv3fJ2uPeOEXw0LU=";
    std::string exponent = "AQAB";

    std::vector<BYTE> PubKeyModulus_bin = base64_decode(PubKeyModulus);
    std::vector<BYTE> PubKeyExp_bin = base64_decode(PubKeyExp);
    
    pbPublicKey = (BYTE*)CoTaskMemAlloc(cbKey);
    ZeroMemory(pbPublicKey, cbKey);
    pRsaBlob = (BCRYPT_RSAKEY_BLOB*)(pbPublicKey);
    // Make the Public Key Blob Header
    pRsaBlob->Magic = BCRYPT_RSAPUBLIC_MAGIC;
    pRsaBlob->BitLength = 128*8;
    pRsaBlob->cbPublicExp = 3;
    pRsaBlob->cbModulus = 128;
    pRsaBlob->cbPrime1 = 0;
    pRsaBlob->cbPrime2 = 0;
    
    BCRYPT_ALG_HANDLE hAlgorithm = NULL;
    BCRYPT_KEY_HANDLE hKey = NULL;
    NTSTATUS status;

    BYTE textData[] = "test";
    DWORD textDataSize = sizeof(textData);
    
    status = BCryptOpenAlgorithmProvider(&hAlgorithm,
        BCRYPT_RSA_ALGORITHM,
        NULL,
        0);
    if (!NT_SUCCESS(status)) {
        printf("Failed to get algorithm provider..status : %08x\n", status);
    }

    status = BCryptImportKeyPair(hAlgorithm,
        NULL,
        BCRYPT_RSAPUBLIC_BLOB,
        &hKey,
        (PUCHAR)pbPublicKey,
        cbKey,//155,
        BCRYPT_NO_KEY_VALIDATION);
    if (!NT_SUCCESS(status)) {
        printf("Failed to import Private key..status : %08x\n", status);
    }  
        
    status = BCryptEncrypt(hKey,
        textData,
        textDataSize,
        NULL,
        NULL,
        0,
        NULL,
        0,
        &encryptedBufferSize,
        BCRYPT_PAD_PKCS1
    );
    if (!NT_SUCCESS(status)) {
        printf("Failed to get required size of buffer..status : %08x\n", status);
    }

    encryptedBuffer = (PUCHAR)HeapAlloc(GetProcessHeap(), 0, encryptedBufferSize);

    if (encryptedBuffer == NULL) {
        printf("failed to allocate memory for blindedFEKBuffer\n");
    }

    status = BCryptEncrypt(hKey,
        textData,
        textDataSize,
        NULL,
        NULL,
        0,
        encryptedBuffer,
        encryptedBufferSize,
        &encryptedBufferSize,
        BCRYPT_PAD_PKCS1
    );

    if (!NT_SUCCESS(status)) {
        printf("Failed encrypt data..status : %08x\n", status);
    }
    printf("Encrypted Data\n");
    printMem(encryptedBuffer, encryptedBufferSize);
    printf("\n\n");

    std::string encryptedDataReturn = base64_encode(&encData[0], encDataSize);

    }
}

ReverseMemCpy(如果是Little Endian,我希望这是正确的方法)

void ReverseMemCopy(BYTE* pbDest, BYTE const* pbSource, DWORD cb)
{
    for (DWORD i = 0; i < cb; i++)
    {
        //pbDest[cb - 1 - i] = pbSource[i];   // in case of Big Endian
        pbDest[i] = pbSource[i];
    }
}

代码所需的输入和输出:

输入数据

test

我的公钥/私钥对:(在.Net端生成)

<RSAKeyValue><Modulus>3XCSEveWJ3Mp41g5VxcmmlCYDL5X+VUX1ULOIl8TdsEu6bbS/Ho0ofBgAwglCrbRgAjm7ZW+EivEVLZRx5FVsEYqGX12fFZSn84Ye6D2rUYqvwR0kBE8MBCdirqg3gXAlmuIgxucWcxiT9NDTaC67Awe9yyQv3fJ2uPeOEXw0LU=</Modulus><Exponent>AQAB</Exponent><P>8uB+2rMMnduKEZ/j9pIkNuHPjqOaeBi0DMkfVTHlrknVdDwCreKVHEx9XIEyYQeYdpCwmj8hwHMEVmHJhVUcjw==</P><Q>6WeNjG2cOZ6y6e+A0k12Bn5UX/HNgeBjdfyy67PG9FMioJ9znAZsJmM5dWaQD9Px3OaHEp5tJhlqrUc6U25oew==</Q><DP>FMpW0Y3GJLUoSn3vW6oC45fM1p72mBU1RGrq/bX5vUOgvARvDkd5ECUUDhkZIOkviea0119UGk8+Lc7NG1a/zQ==</DP><DQ>Sda9vAhNHRlspn9jdKSWyxUaIkQ/7G+NZ50rCVAVh+PpF4F6NIj/m+FWIyLwPmGhqW2wm55ND3mI+wqGlDBgkw==</DQ><InverseQ>Pz8NIq8+1o6PXWdWJUJPyV1Wli9NdK5RlH8yc44QJYzAxcEFnI8CPHkQu0BHrN+mfOX9UN7LfHjI9wmOVStksw==</InverseQ><D>NjayPJyLEXt7fOKDn1PWqp8iqrQLO8ree+LQLtASJtfjEWsmOpP8wMzl5LggwX/CyNLlHrOzhiVa+tZsLSziykG4CzY1qwL6HS+oSoR7GbjkSZXQPbN8RM2tS8fZ0ZyRAtn7ohDRFNMZe6Y+cFQ3H2ijARpVl4VngTqyK/Syyz0=</D></RSAKeyValue>" 

Base64 加密数据:

kycXjy03kP+VjWP4uYFMl4/avSOhJ269BZM/AeEj0RQmSgkfA+m9woENkDVqQuxOuw8/DqpeNreA7p11QOu3i5WNJ2wC2zhCVgXi0z+tjylQidAKiwNFNlvEfAQN3h18F/gLKkuCH7W3a7tqigxZc2jCOflA4ZeGx54ZL+gVDAw=

十六进制/字节形式的加密数据:

93 27 17 8f 2d 37 90 ff 95 8d 63 f8 b9 81 4c 97 8f da bd 23 a1 27 6e bd 05 93 3f 01 e1 23 d1 14 26 4a 09 1f 03 e9 bd c2 81 0d 90 35 6a 42 ec 4e bb 0f 3f 0e aa 5e 36 b7 80 ee 9d 75 40 eb b7 8b 95 8d 27 6c 02 db 38 42 56 05 e2 d3 3f ad 8f 29 50 89 d0 0a 8b 03 45 36 5b c4 7c 04 0d de 1d 7c 17 f8 0b 2a 4b 82 1f b5 b7 6b bb 6a 8a 0c 59 73 68 c2 39 f9 40 e1 97 86 c7 9e 19 2f e8 15 0c 0c

Decrypt() .Net 端出现异常

System.Security.Cryptography.CryptographicException: 'The parameter is incorrect

cryptography rsa cng
1个回答
0
投票

您不考虑

PubKeyModulus_bin
PubKeyExp_bin
,这实际上意味着没有导入密钥。

但是,我不确定这是否真的是问题的原因,因为在我的环境中,代码会导致运行时错误并且不会生成密文,而在您的环境中,加密似乎适用于发布的密文。所以也许这只是一个复制/粘贴错误。

另一方面,当此错误修复后,加密和解密可以在我的环境中与您的代码一起工作:

...
pRsaBlob->cbPrime2 = 0;

pbCurrent = (PBYTE)(pRsaBlob + 1);
memcpy((char*)pbCurrent, (const char*)PubKeyExp_bin.data(), cbExp);
pbCurrent += cbExp;
memcpy((char*)pbCurrent, (const char*)PubKeyModulus_bin.data(), cbModulus);

BCRYPT_ALG_HANDLE hAlgorithm = NULL;
...

通过此修复,代码与您发布的密钥一起创建例如以下密文(当然,每次加密都会改变,因为 RSA 加密是不确定的):

jlLc4CYg+4WiA3GRzLasBe3SvBSaA/x/ujVE8dwqczFsUfxW02QecN9VDwPpGY6s4Jx4OorUoyjXD/g0d56m/L7iRl3wX8eenIWnmSXZfekVjO31PK95kLY+ht/xonVOAd23WvFrVWnyWFJ2Z2hEIQ+0Kcv/x2N99AwB5mqxDsI=

此密文是有效的RSA密文,可以使用在线工具或C#代码解密。


测试:

在线工具通常不支持 XML 密钥格式,因此将您的密钥(例如使用合适的转换器工具)转换为支持的格式是有意义的,例如PKCS#1:

-----BEGIN RSA PRIVATE KEY-----
MIICWwIBAAKBgQDdcJIS95YncynjWDlXFyaaUJgMvlf5VRfVQs4iXxN2wS7pttL8
ejSh8GADCCUKttGACObtlb4SK8RUtlHHkVWwRioZfXZ8VlKfzhh7oPatRiq/BHSQ
ETwwEJ2KuqDeBcCWa4iDG5xZzGJP00NNoLrsDB73LJC/d8na4944RfDQtQIDAQAB
AoGANjayPJyLEXt7fOKDn1PWqp8iqrQLO8ree+LQLtASJtfjEWsmOpP8wMzl5Lgg
wX/CyNLlHrOzhiVa+tZsLSziykG4CzY1qwL6HS+oSoR7GbjkSZXQPbN8RM2tS8fZ
0ZyRAtn7ohDRFNMZe6Y+cFQ3H2ijARpVl4VngTqyK/Syyz0CQQDy4H7aswyd24oR
n+P2kiQ24c+Oo5p4GLQMyR9VMeWuSdV0PAKt4pUcTH1cgTJhB5h2kLCaPyHAcwRW
YcmFVRyPAkEA6WeNjG2cOZ6y6e+A0k12Bn5UX/HNgeBjdfyy67PG9FMioJ9znAZs
JmM5dWaQD9Px3OaHEp5tJhlqrUc6U25oewJAFMpW0Y3GJLUoSn3vW6oC45fM1p72
mBU1RGrq/bX5vUOgvARvDkd5ECUUDhkZIOkviea0119UGk8+Lc7NG1a/zQJASda9
vAhNHRlspn9jdKSWyxUaIkQ/7G+NZ50rCVAVh+PpF4F6NIj/m+FWIyLwPmGhqW2w
m55ND3mI+wqGlDBgkwJAPz8NIq8+1o6PXWdWJUJPyV1Wli9NdK5RlH8yc44QJYzA
xcEFnI8CPHkQu0BHrN+mfOX9UN7LfHjI9wmOVStksw==
-----END RSA PRIVATE KEY-----

如果使用该密钥,生成的密文可以成功解密,例如:与 CyberChef 一起使用,正如以下链接所证明的那样。


注意,当用

sizeof()
中的
DWORD textDataSize = sizeof(textData)
确定明文长度时,会考虑终止0。相反,
strlen()
不考虑终止 0。

© www.soinside.com 2019 - 2024. All rights reserved.