c++ 从 xml 导入 CAPI/CNG 中的 RSA 私钥

c++ Import RSA private key in CAPI/CNG from xml

我在 this question 中读到关于从本机组件导入 public 密钥。 我尝试根据 BLOB 文档对私钥执行相同的操作,但出现 NTE_BAD_DATA 错误。

我的想法可行吗?如果是这样,你能帮忙吗?

我的尝试:

void old_RSA_decrypt(PBYTE blob, DWORD blobSize)
{
    HCRYPTPROV hCryptProv = NULL;
    HCRYPTKEY hKey = NULL;
    DWORD dwDecryptedLen = 0;
    DWORD length;
    std::ifstream f;
    f.open("c:\Programming\encrypted.txt", std::ios::binary);
    if (!f.is_open())
    {
        std::cout << "Error on open file: " << GetLastError() << std::endl;
        return;
    }

    f.seekg(0, f.end);
    length = f.tellg();
    f.seekg(0, f.beg);

    char * buffer = new char[length];
    f.read(buffer, length);

    if (!f)
        std::cout << "error: only " << f.gcount() << " could be read" << std::endl;
    f.close();

    PBYTE bBuffer = (PBYTE)buffer;

    //now to get the decryption thing going

    if (!CryptAcquireContext(
        &hCryptProv,
        NULL,
        MS_STRONG_PROV,
        PROV_RSA_FULL,
        CRYPT_VERIFYCONTEXT))

    {
        std::cout << "Error on CryptAcquireContext " << GetLastError() << std::endl;
        return;
    }
    if (!CryptImportKey(
        hCryptProv,
        blob,
        blobSize,
        NULL,
        0,
        &hKey))
    {
        std::cout << "Error on CryptImportKey " << GetLastError() << std::endl;
        return;
    }
    if (!CryptDecrypt(hKey, NULL, TRUE, 0, NULL, &dwDecryptedLen))
    {
        std::cout << "Error on CryptDecrypt (First Pass) " << GetLastError() << std::endl;
        return;
    }
    PBYTE decBuffer = new BYTE[dwDecryptedLen];
    for(int i = 0; i < length ; ++i)
        decBuffer[i] = bBuffer[i];

    if (!CryptDecrypt(hKey, NULL, TRUE, 0, decBuffer, &length))
    {
        std::cout << "Error on CryptDecrypt (Second Pass) " << GetLastError() << std::endl;
        return;
    }
    std::cout << "Yurika2!" << std::endl;
    std::ofstream of;
    of.open("c:\Programming\decrypted.txt", std::ios::binary);
    if (!of.is_open())
    {
        std::cout << "Error on open write file: " << GetLastError() << std::endl;
        return;
    }
    string sDecMsg = string(reinterpret_cast<char*>(decBuffer), length);
    of << sDecMsg << std::endl;
    of.close();
cleanup:
    delete[] buffer;
    delete[] decBuffer;

}

void do_decrypt()
{
    string modStr = "yVUndgQFuB5Z5FgC0/WgWCg6Y8VuB582avGjQDdeoJDa1+RBKCyXo700sAMSGjM/bVakOlFqvCsVFNBysx1CH731CDb2DR1a0bsmYmDQ9d0ZHX+AOohVDIx9mc7bkDQZoEFpe9NqFsu95Y9yktpl1JKPmKyLOFgufGJYYvQyoOM=";
    string expStr = "AQAB";
    string PStr = "/JydNn89lSWjgWOG1XRJm1qTWDekzzoLfTQU+GK+h8DGQ6gkUbgqGosLGo+eAxbO/ETZV3ibbBuIdvL4UxC5Qw==";
    string QStr = "zAh23Gc8Oqz/Uh2wh+yt8DqUesVLwMn2koc9CbyF9/Z5Qe8OIR4yygJtuYruRC1x/KYj85l6DGzstUZOtYmv4Q==";
    string DPStr ="+1INj1SUPjjOLUKJuQAS4z7/7PqfO5RyLcSNQHltOb5vAozcZXkmWnYPPAO6nzQoBg+xdDcH2kyiPkWJDYtL5Q==";
    string DQStr = "cbYh8HJEufrijTRox0hcJG+xgr7kmjy1BDMFDKEaFPkz2VBPEpwO+FDkMC1C35JoXcOGc+RMhhJK1jip8zkaYQ==";
    string InverseQStr = "3PAXzlAXgvLVrbOEygjA2zhJEYALBEi6VTKqfDKlnv8/D9QUkC39bEDIRLG0wMFFxN8NlLx5zTiiVswxnMy8Mw==";
    string DStr = "KKBSyKkyID+bowyxcWUAuJlRgv19YPNbL0RYTWZ+5UalqmfoT/uDk+pjndrYxcmulFkl5ZC1SYgmBl+zrXoLc/Ei86BtNiuwfcqHlUDp0fdP+fyYN45wh/251HQ3UM1zBpMP8XeYB6zjpCU/s3/wCBE6WpJWN9fKcG0W5PLq8eE=";

    //FROM STRINGS TO BYTE VECTORS!
    vector<BYTE> modBinMSB = base64_decode(modStr);
    vector<BYTE> expBinMSB = base64_decode(expStr);
    vector<BYTE> PBinMSB = base64_decode(PStr);
    vector<BYTE> QBinMSB = base64_decode(QStr);
    vector<BYTE> DPBinMSB = base64_decode(DPStr);
    vector<BYTE> DQBinMSB = base64_decode(DQStr);
    vector<BYTE> InverseQBinMSB = base64_decode(InverseQStr);
    vector<BYTE> DBinMSB = base64_decode(DStr);

    //TURN MSB TO LSB

    DWORD offset = sizeof(BLOBHEADER) + sizeof(RSAPUBKEY); // to keep track of things
    const DWORD modulusLengthInBytes = 128;
    DWORD keyBlobLength = sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) + (modulusLengthInBytes * 4) + (modulusLengthInBytes / 2);
    BYTE* keyBlob = (PBYTE)malloc(keyBlobLength);
    BLOBHEADER* blobheader = (BLOBHEADER*)keyBlob;
    blobheader->bType = PRIVATEKEYBLOB;
    blobheader->bVersion = CUR_BLOB_VERSION;
    blobheader->reserved = 0;
    blobheader->aiKeyAlg = CALG_RSA_KEYX;
    RSAPUBKEY* rsapubkey = (RSAPUBKEY*)(keyBlob + sizeof(BLOBHEADER));
    rsapubkey->magic = 0x31415352;
    rsapubkey->bitlen = modulusLengthInBytes * 8 *4 + modulusLengthInBytes*4;
    rsapubkey->pubexp = MSBByteVectorToDword(expBinMSB);

    BYTE* modulus = keyBlob + offset;
    copyReversed(modBinMSB, modulus);
    offset += modulusLengthInBytes;
    BYTE* prime1 = keyBlob + offset ;
    copyReversed(PBinMSB, prime1);
    offset += modulusLengthInBytes / 2;
    BYTE* prime2 = keyBlob + offset;
    copyReversed(QBinMSB, prime2);
    offset += (modulusLengthInBytes / 2);
    BYTE* exponent1 = keyBlob + offset;
    copyReversed(DPBinMSB, exponent1);
    offset += (modulusLengthInBytes / 2);
    BYTE* exponent2 = keyBlob + offset;
    copyReversed(DQBinMSB, exponent2);
    offset += (modulusLengthInBytes / 2);
    BYTE* coefficient = keyBlob + offset;
    copyReversed(InverseQBinMSB, coefficient);
    offset += modulusLengthInBytes / 2;
    BYTE* privateExponent = keyBlob + offset;
    copyReversed(DBinMSB, privateExponent);

    old_RSA_decrypt(keyBlob, keyBlobLength);
}

当然可以。您提到了两个 Windows 加密堆栈,但存在一些差异:

  • 编码:
    • CAPI:所有变长字段都是小端
    • CNG:所有可变长度字段都是大端。
  • 刚度:
    • CAPI:模数和D的长度必须相同。此外,P、Q、DP、DQ、InverseQ 的长度都相同(必须是模数长度的一半(四舍五入))。
    • CNG:私钥仅要求 n、e、p 和 q...,您分别指定每个字段的长度。

我在您的代码中看到一个明显的错误:

rsapubkey->bitlen = modulusLengthInBytes * 8 *4 + modulusLengthInBytes*4;

根据 the documentation:

bitlen

Number of bits in the modulus. In practice, this must always be a multiple of eight.

就这样

rsapubkey->bitlen = modulusLengthInBytes * 8;

您的 dwMagic 值设置似乎也不正确。

rsapubkey->magic = 0x31415352;

0x31415352 是 RSA_PUB_MAGIC,因此您称自己为 public 密钥。您想要 RSA_PRIV_MAGIC(并使用常量)。

rsapubkey->magic = RSA_PRIV_MAGIC;

http://source.dot.net/#System.Security.Cryptography.Csp/System/Security/Cryptography/CapiHelper.Shared.cs,b7bc764e6deb34f5 比较,后者是 C# 中的工作 blob 编写器。