OpenSSL和MS CryptoAPI兼容性问题

时间:2016-07-22 13:50:42

标签: openssl cryptoapi

我面临Microsoft CrypoAPI和OpenSSL之间的不兼容问题,我无法解决。

我希望RSA使用带有公钥的CAPI对邮件进行加密,然后使用OpenSSL(使用私钥)对其进行解密,但没有运气。

我正在做的步骤如下:

  • 使用pem格式的OpenSSL生成公钥/私钥对。

openssl genrsa -out private.pem 2048

openssl rsa -in private.pem -outform PEM -pubout -out public.pem

  • 然后在CAPI中,我导入生成的密钥,如下所示: dsadsa
      const char* szPemPrivKey = 
"-----BEGIN RSA PRIVATE KEY-----"
"MIIEpAIBAAKCAQEAvUT7PaQzzhSmyQKrnroWCk2tdy9O1BR6bINObhGXoDfK4tnU"
"qgpr0MbM8VjCvpgNjJT8m5RZkvSxcmaWZZQnXxr/SESnrmwk6CcRAvEk45M3LTix"
"N0TTUZzQdBbG9z0bgx1a1P866S87MOf6wbb9yUfV79N7J+xZRQC8mnRtvmzjRZ3W"
"MOcBZ8n1C106gOq//SwvB28mGWTpJ+opASv3mkxTydiDd5v7/yq2Lx4NrvJN+1E4"
"nOX6PLiTECFcvNYzZe9KDuJ5CJv45ifRUo9m5ebo759lKpL1X69ptG7RpHEYULYY"
"urwEGExC1jp/Nbft0zOehsF4wwFqwQVQ34m5LQIDAQABAoIBAD6dQISu+th1aovb"
"T01ugHYeJoHka66rq6iUc/Dj7wZ5DqynpbwvQGXMLua1F5AYG3tjmoIZvNxqCP4w"
"xBaMwc2rz8JnvBVu/3Kx4eXYQvzqqflS5QXExigcubV+B4qpc52Xq4IFgca88lcG"
"l6VYVXMuSa9Shk652PqD+OEcHWY+aygXETLGEAlO88iWe2LbzrD9I1faW8Mrj+wi"
"b9mVhZbjbrI+w9O7cfde4d9Lo4wzGrrunRa0THKUyfwJGtTJ3eP2jCWlE1ij3Xmy"
"c/Mf8U8RlMU8N/Ys77WtCXUA3DK0ge8HSITqvD1NHSyuPM0XqinTkRSg0Ri/tWo+"
"1C6gKJ0CgYEA9K9snRlfuQshwfyR40npJ8r5X9YApjfK8PrxsmdpOi8tpDyi5I66"
"fmnUsbV0ikM+9U898myUAF3SxZIZfw+LYI3ofdstnv6wc9+c9jP9wbGxSryiBurW"
"d3uPuemee7+CxTVEwI0PEAVerRSP+m6MZ/F+SRkQjyLmBXu7soxaspMCgYEAxgWL"
"/wkz6WCf37+9TUHO0MG7vOQ2sI7Bc+82dAa9fsxLwpncmkNxEv+hK3k7Jlr2J4pZ"
"SveRhcq3Ohm2aDRi5CfgQaZO4bGDop7ZYWZuW/MakZdCf8olWCifXEPWcxBo8FGW"
"9/3XEbXkW481HDrX4wyn2b3ptdSqMcdDMKmifT8CgYEA6vtVWYG2teSE5OED0b13"
"VinNV0YTlY1bLhYw6134ZlJMiL9ayBhx7VkBVDCo3Oc7nSYenaO8dqWj9u0Z4zYw"
"aeeecM9+foSlPIJxINhJSCy30Mha6j24/UICg05iTwFaOr2vayOMZZxikeF/a8ei"
"u2fmGZkil/Ox524ukYfMylUCgYAiFTJTYzIcKRVbXZUnhvwh0jaN/HmtSeTiH3ov"
"3jkfaepgRDtEEfeUXYtQAD2+DEnx5E4aKSJS9OE0jthmdx3OR07B/e31yqfthYnE"
"yeyUxvL7vB0mAZUL53IGX2a5x0lIk8J4TKiH09bKK4von/gojDUXtShUs5XXm4Rl"
"C8174QKBgQDbRGyg3VCwo3p0sdqm5UlCL0pc36T5bBUfkVGpJdBZxbIx283CvY35"
"OGqcYdiANMn+alg9IDXfuaFYgg1QTQSkF74CMi+gY7Z8n2OKsjF0cR8VkIYoI9BL"
"iDXvlWs2QVsv+1CIYmZdI8nkExirzRvBD75ZqNdGSWkrfuYnr/bpHg=="
"-----END RSA PRIVATE KEY-----";


const char* szPemPubKey = 
"-----BEGIN PUBLIC KEY-----"
"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvUT7PaQzzhSmyQKrnroW"
"Ck2tdy9O1BR6bINObhGXoDfK4tnUqgpr0MbM8VjCvpgNjJT8m5RZkvSxcmaWZZQn"
"Xxr/SESnrmwk6CcRAvEk45M3LTixN0TTUZzQdBbG9z0bgx1a1P866S87MOf6wbb9"
"yUfV79N7J+xZRQC8mnRtvmzjRZ3WMOcBZ8n1C106gOq//SwvB28mGWTpJ+opASv3"
"mkxTydiDd5v7/yq2Lx4NrvJN+1E4nOX6PLiTECFcvNYzZe9KDuJ5CJv45ifRUo9m"
"5ebo759lKpL1X69ptG7RpHEYULYYurwEGExC1jp/Nbft0zOehsF4wwFqwQVQ34m5"
"LQIDAQAB"
"-----END PUBLIC KEY-----";



/* 
..... some unrelated code here */
char           derPubKey[2048];
size_t         derPubKeyLen = 2048;
CERT_PUBLIC_KEY_INFO *publicKeyInfo;
int            publicKeyInfoLen;
HCRYPTPROV hProv = NULL;
HCRYPTKEY hKey = NULL;
/*
* Convert from PEM format to DER format - removes header and footer and decodes from base64
*/
if ( !CryptStringToBinaryA( szPemPubKey, 0, CRYPT_STRING_BASE64HEADER, (BYTE*)derPubKey, (DWORD*)&derPubKeyLen, NULL, NULL ) )
{
    fprintf( stderr, "CryptStringToBinary failed. Err: %d\n", GetLastError() );
}

/*
 * 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, (DWORD*)&publicKeyInfoLen ) )
{
    fprintf( stderr, "CryptDecodeObjectEx 1 failed. Err: %p\n", GetLastError() );
    return -1;
}

// Create a temporary and volatile CSP context in order to import
// the key and use for signing
if (!CryptAcquireContext(&hProv, NULL, MS_ENHANCED_PROV, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
{
    printf("CryptAcquireContext failed with error 0x%.8X\n", GetLastError());
    goto main_exit;
}

/*
 * Import the public key using the context
 */
if ( !CryptImportPublicKeyInfo( hProv, X509_ASN_ENCODING, publicKeyInfo, &hKey ) )
{
    fprintf( stderr, "CryptImportPublicKeyInfo failed. error: %d\n", GetLastError() );
    return -1;
}

似乎正确导入了密钥并填充了hKey

  • 到目前为止,这么好。然后我要加密明文
    char* plaintext = "123456";
LPBYTE pEncryptedData = NULL;
DWORD EncryptedDataLen = 0;

LPBYTE pEncryptedDataRev = NULL; /* I'll explain this later (: */
DWORD EncryptedDataRevLen = 0;

pEncryptedData = (LPBYTE) LocalAlloc(0, 500);
EncryptedDataLen = 6;


pEncryptedDataRev = (LPBYTE) LocalAlloc(0, 500);
EncryptedDataLen = 6;


CopyMemory(pEncryptedData, plaintext, 6);


if ( CryptEncrypt( hKey, NULL, TRUE, 0, pEncryptedData, &EncryptedDataLen, 500) ) {
    DWORD dwBytesWritten = 0;

    hFile = CreateFile(L"poc_enc",              // name of the write
                       GENERIC_WRITE,          // open for writing
                       0,                      // do not share
                       NULL,                   // default security
                       CREATE_NEW,             // create new file only
                       FILE_ATTRIBUTE_NORMAL,  // normal file
                       NULL);                  // no attr. template

    ReverseStream(pEncryptedData, pEncryptedDataRev, EncryptedDataLen);

    WriteFile( 
                    hFile,           // open file handle
                    pEncryptedData,      // start of data to write
                    EncryptedDataLen,  // number of bytes to write
                    &dwBytesWritten, // number of bytes that were written
                    NULL);            // no overlapped structure

      CloseHandle(hFile); 
} 

您可以看到,我正在使用ReverseStrem()来反转加密数据,这是因为我已经读到CAPI和OpenSSL使用的endiannes不同。 (little-endian CAPI和big-endian OpenSSL)

void ReverseStream(LPBYTE Source, LPBYTE Destination, DWORD Size)
{
    DWORD cnt = Size;
    while(0<cnt)
    {
        Destination[Size-cnt] = Source[cnt];
        cnt--;
    }
}
  • 好的,现在麻烦来了。加密明文(123456)写入名为poc_enc的文件,当我尝试使用OpenSSL解密时

openssl rsautl -decrypt -in poc_enc -out plaintext -inkey private.pem

我收到以下错误:

    RSA operation error
16968:error:0407109F:rsa routines:RSA_padding_check_PKCS1_type_2:pkcs decoding error:.\crypto\rsa\rsa_pk1.c:273:
16968:error:04065072:rsa routines:RSA_EAY_PRIVATE_DECRYPT:padding check failed:.\crypto\rsa\rsa_eay.c:602:

任何想法如何解决此问题?谢谢:))

1 个答案:

答案 0 :(得分:1)

反向函数错误,这样你错过了最后一个字节,它应该是这样的:

void ReverseStream(LPBYTE Source, LPBYTE Destination, DWORD Size)
{
    int SourceCnt = Size;
    int DestCnt = 0;

    for (SourceCnt = Size - 1, DestCnt = 0; SourceCnt >= 0; SourceCnt--, DestCnt++)
        Destination[DestCnt] = Source[SourceCnt];
}