c++ - 生成 RSA-2048 key (公钥和私钥)

标签 c++ winapi rsa wincrypt

我正在简单地实现 RSA-2048。我在另一个论坛上找到了一些代码。

#include <string>
#include <iostream>
#include <windows.h>
#include <Wincrypt.h>

using namespace std;

#pragma comment (lib, "Crypt32.lib")

BYTE* Crypt(const string& _str, DWORD* _outLength);

BYTE* Decrypt(BYTE* _encryptedData, DWORD* _length);

const char* szPemPrivKey =
"-----BEGIN RSA PRIVATE KEY-----"
"MIICWwIBAAKBgQCn7fL/1qsWkJkUtXKZIJNqYfnVByVhK/LzQecPhVR7r+4ng1nZ"
"Bxg44SexS63iYlnodqDWkH/Hi82Uc0UmugY/Ow39uEGeoiYqWl5BLM8pfRAGqzxb"
"h600Qd/Oc5kYdg8hP0D/gAHXwutL74fygpB6xb8EZl2BHKvpDR80GYFlrQIDAQAB"
"AoGAZ4ZHsfTTEFwgIyYg+cmdV44DCJMZNihz5AcSvPzDMmUo+m79as/23MnhQGmZ"
"TuC28JqBWQVH4OqM2CGf1doEkuLZ/rcgxDipRqbLkEW3T/q+kJ2m9A652ePbHUKX"
"ayozDQrWtL4wkvAQQ9Il6vx+AJUzT41hv1PKZ5KWxONiJDkCQQDRsObUVVc6exb+"
"YUWVgN0pivHudKIwGUN3js09MjHoen9LbUcvupO3seAUhnNQ17t+1XxsrnPKabQQ"
"OimcPK3XAkEAzQQEI++NdoLYJv1oKYADzOUbDAmfoZ/szN6z//53h8zt5ni+6Q0n"
"k7nyrVXWuLeP0rEvD0hMOzI0mfUMwbtwGwJAMUYId8y1+qAB/zSMTV1CmwhzYT02"
"/2ZwXB/KSp8I60AduXOsTqLhI0FBDpGpd026WUuBOWik/ONp1IZWUMhRcQJAHI+U"
"rBTxVjNAPZ5L5owo+2BndjPZA0EuUhQsa1td95M7CUKFBh6JBvF+t1sgALfB145L"
"igt+YzjJTzFuR4b/RQJATgZuFyBiuLHrMES2vAtmLRlF6uTzsrNZLLUko2Rfzkzh"
"qR4inQOWWZLFzjqp3ha9rzCSVY+nBw+xD+B9hBlsNw=="
"-----END RSA PRIVATE KEY-----";

const char* szPemPublicKey =
"-----BEGIN PUBLIC KEY-----"
"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCn7fL/1qsWkJkUtXKZIJNqYfnV"
"ByVhK/LzQecPhVR7r+4ng1nZBxg44SexS63iYlnodqDWkH/Hi82Uc0UmugY/Ow39"
"uEGeoiYqWl5BLM8pfRAGqzxbh600Qd/Oc5kYdg8hP0D/gAHXwutL74fygpB6xb8E"
"Zl2BHKvpDR80GYFlrQIDAQAB"
"-----END PUBLIC KEY-----";


int main()
{
    string str_data = "test RSA implementation";

    DWORD encryptedDataLen;
    BYTE* encrytedData = Crypt(str_data, &encryptedDataLen);
    cout << encrytedData << endl;

    cout << endl;

    BYTE* decryptedData = Decrypt(encrytedData, &encryptedDataLen);
    cout << decryptedData << endl;

    delete(encrytedData);
    delete(decryptedData);

    return 0;
}

BYTE* Crypt(const string& _str, DWORD* _outLength)
{
    char            pemPubKey[2048];
    memcpy((void*)pemPubKey, szPemPublicKey, strlen(szPemPublicKey));
    char            derPubKey[2048];
    DWORD           derPubKeyLen = 2048;
    CERT_PUBLIC_KEY_INFO* publicKeyInfo;
    DWORD           publicKeyInfoLen;
    HANDLE          hFile;
    HCRYPTPROV      hProv = 0;
    HCRYPTKEY       hKey = 0;


    // Convert from PEM format to DER format - removes header and footer and decodes from base64
    if (!CryptStringToBinaryA(pemPubKey, 0, CRYPT_STRING_BASE64HEADER, (BYTE*)derPubKey, &derPubKeyLen, NULL, NULL))
    {
        fprintf(stderr, "CryptStringToBinary failed. Err: %d\n", GetLastError());
        return NULL;
    }

    // Decode from DER format to CERT_PUBLIC_KEY_INFO    
    if (!CryptDecodeObjectEx(X509_ASN_ENCODING, X509_PUBLIC_KEY_INFO, (BYTE*)derPubKey, derPubKeyLen,
        CRYPT_ENCODE_ALLOC_FLAG, NULL, &publicKeyInfo, &publicKeyInfoLen))
    {
        fprintf(stderr, "CryptDecodeObjectEx 1 failed. Err: %p\n", GetLastError());
        return NULL;
    }

    if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
    {
        {
            printf("CryptAcquireContext failed - err=0x%x.\n", GetLastError());
            return NULL;
        }
    }

    if (!CryptImportPublicKeyInfo(hProv, X509_ASN_ENCODING, publicKeyInfo, &hKey))
    {
        fprintf(stderr, "CryptImportPublicKeyInfo failed. error: %d\n", GetLastError());
        return NULL;
    }
    // LocalFree( publicKeyInfo );


    // get size of buffer
    DWORD strLen = _str.length() * sizeof(char);
    DWORD bufLen = strLen;
    if (!CryptEncrypt(hKey, 0, true, 0, 0, &bufLen, strLen))
    {
        cout << "CryptEncrypt() failed with error " << GetLastError() << endl;
        return NULL;
    }
    // Crypt string data
    BYTE* cipherBlock = new BYTE[bufLen];
    memset((void*)cipherBlock, 0, bufLen);
    memcpy((void*)cipherBlock, _str.c_str(), strLen);
    if (!CryptEncrypt(hKey, 0, TRUE, 0, cipherBlock, &strLen, bufLen))
    {
        cout << "CryptEncrypt() failed with error " << GetLastError() << endl;
        return NULL;
    }

    *_outLength = bufLen;
    return cipherBlock;
}

BYTE* Decrypt(BYTE* _encryptedData, DWORD* _length)
{
    DWORD dwBufferLen = 0, cbKeyBlob = 0, cbSignature = 0/*,i*/;
    LPBYTE pbBuffer = NULL, pbKeyBlob = NULL, pbSignature = NULL;
    HCRYPTPROV hProv = NULL;
    HCRYPTKEY hKey = NULL;
    HCRYPTHASH hHash = NULL;

    if (!CryptStringToBinaryA(szPemPrivKey, 0, CRYPT_STRING_BASE64HEADER, NULL, &dwBufferLen, NULL, NULL))
    {
        cout << "Failed to convert BASE64 private key. Error " << GetLastError() << endl;
        return NULL;
    }

    pbBuffer = (LPBYTE)LocalAlloc(0, dwBufferLen);
    if (!CryptStringToBinaryA(szPemPrivKey, 0, CRYPT_STRING_BASE64HEADER, pbBuffer, &dwBufferLen, NULL, NULL))
    {
        cout << "Failed to convert BASE64 private key. Error " << GetLastError() << endl;
        return NULL;
    }

    if (!CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, PKCS_RSA_PRIVATE_KEY, pbBuffer, dwBufferLen, 0, NULL, NULL, &cbKeyBlob))
    {
        cout << "Failed to parse private key. Error " << GetLastError() << endl;
        return NULL;
    }

    pbKeyBlob = (LPBYTE)LocalAlloc(0, cbKeyBlob);
    if (!CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, PKCS_RSA_PRIVATE_KEY, pbBuffer, dwBufferLen, 0, NULL, pbKeyBlob, &cbKeyBlob))
    {
        cout << "Failed to parse private key. Error " << GetLastError() << endl;
        return NULL;
    }

    if (!CryptAcquireContext(&hProv, NULL, MS_DEF_PROV, PROV_RSA_FULL, 0))
    {
        if (GetLastError() == NTE_BAD_KEYSET)
        {
            if (!CryptAcquireContext(&hProv, NULL, MS_DEF_PROV, PROV_RSA_FULL, CRYPT_NEWKEYSET))
            {
                cout << "CryptAcquireContext() failed with error " << GetLastError() << endl;
                return NULL;
            }
        }
        else
        {
            cout << "CryptAcquireContext() failed with error " << GetLastError() << endl;
            return NULL;
        }
    }

    if (!CryptImportKey(hProv, pbKeyBlob, cbKeyBlob, NULL, 0, &hKey))
    {
        cout << "CryptImportKey() failed with error " << GetLastError() << endl;
        return NULL;
    }


    // Decrypt
    DWORD bufLen = *_length + 1;
    BYTE* cipherBlock = new BYTE[bufLen];
    memset((void*)cipherBlock, 0, bufLen);
    memcpy((void*)cipherBlock, _encryptedData, *_length);
    if (!CryptDecrypt(hKey, 0, TRUE, 0, cipherBlock, _length))
    {
        cout << "CryptDecrypt() failed with error " << GetLastError() << endl;
        return NULL;
    }

    // Decrypted data
    BYTE* decryptedData = new BYTE[*_length + 1];
    decryptedData[*_length] = 0;
    memcpy((void*)decryptedData, cipherBlock, *_length);

    delete(cipherBlock);
    if (pbBuffer) LocalFree(pbBuffer);
    if (pbKeyBlob) LocalFree(pbKeyBlob);
    if (pbSignature) LocalFree(pbSignature);
    if (hHash) CryptDestroyHash(hHash);
    if (hKey) CryptDestroyKey(hKey);
    if (hProv) CryptReleaseContext(hProv, 0);

    return decryptedData;
}

因此,加密\解密工作得很好。 我需要换 key 。 如何为此代码生成 key ?

我试过这个在线生成器,但它不起作用。 https://travistidwell.com/jsencrypt/demo/ 和其他在线生成器

最佳答案

NCryptCreatePersistedKey .请放弃旧的 Crypt* 函数,转而使用 NCrypt 和 BCrypt* 变体。如果您坚持使用旧 API,请使用 this .

关于c++ - 生成 RSA-2048 key (公钥和私钥),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56440993/

相关文章:

c++ - 如何指示 CMake 仅使用特定目录中的库

C++ 运行时错误 : free(): invalid next size (fast)

c++ - 容器特征 - is_multi、is_ordered、is_associative

c - 在不使用第 3 方库的情况下基于 C 中的 char* 的多平台 Unicode 处理?

java - RSA Ruby 和 Android 填充问题

c++ - "Non-standard syntax"函数参数中的 vector 错误

c++ - 如何在我的 TreeView 中显示 +/- 图标?

c++ - 如何更改左上角 : taskbar, 的图标,按下 Alt-Tab 时的图标,我的 .exe

asp.net-core - “CspKeyContainerInfo”需要 Windows Cryptographic API (CAPI),此平台上不可用

javascript - Web Crypto API 无法导入 openssl key