本文介绍了php openssl签名字符串未获得Win CryptoAPI验证的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用php openssl签署一些文本,并试图在Windows应用程序中使用CryptoApi验证,但验证总是失败。请帮助我。

I am signing some text using php openssl and trying to verify it in the windows app using CryptoApi but validation always fails. Please help me out.

PHP代码:

<?php

$data = "data that is to be hashed and signed.";


$private_key = <<<EOD
-----BEGIN RSA PRIVATE KEY-----
MIIBOgIBAAJBANDiE2+Xi/WnO+s120NiiJhNyIButVu6zxqlVzz0wy2j4kQVUC4Z
RZD80IY+4wIiX2YxKBZKGnd2TtPkcJ/ljkUCAwEAAQJAL151ZeMKHEU2c1qdRKS9
sTxCcc2pVwoAGVzRccNX16tfmCf8FjxuM3WmLdsPxYoHrwb1LFNxiNk1MXrxjH3R
6QIhAPB7edmcjH4bhMaJBztcbNE1VRCEi/bisAwiPPMq9/2nAiEA3lyc5+f6DEIJ
h1y6BWkdVULDSM+jpi1XiV/DevxuijMCIQCAEPGqHsF+4v7Jj+3HAgh9PU6otj2n
Y79nJtCYmvhoHwIgNDePaS4inApN7omp7WdXyhPZhBmulnGDYvEoGJN66d0CIHra
I2SvDkQ5CmrzkW5qPaE2oO7BSqAhRZxiYpZFb5CI
-----END RSA PRIVATE KEY-----
EOD;
$public_key = <<<EOD
-----BEGIN PUBLIC KEY-----
MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBANDiE2+Xi/WnO+s120NiiJhNyIButVu6
zxqlVzz0wy2j4kQVUC4ZRZD80IY+4wIiX2YxKBZKGnd2TtPkcJ/ljkUCAwEAAQ==
-----END PUBLIC KEY-----
EOD;

$binary_signature = "";

// At least with PHP 5.2.2 / OpenSSL 0.9.8b (Fedora 7)
// there seems to be no need to call openssl_get_privatekey or similar.
// Just pass the key as defined above
openssl_sign($data, $binary_signature, $private_key, OPENSSL_ALGO_SHA1);

// Check signature
$ok = openssl_verify($data, $binary_signature, $public_key, OPENSSL_ALGO_SHA1);
echo $binary_signature;
echo "\n";
echo strlen($binary_signature);
echo "\n";
echo strlen($public_key);

$binary_signature="ÅâŸoÀÞü¸IOT6ê¿›¹ý"´Šæ¸Ûà$,&†-X÷bË`‡0¥u«CAÚNgϼ‡Êû`Sî";
echo "check #1: ";
echo sha1($data);
if ($ok == 1) {
    echo "signature ok (as it should be)\n";
} elseif ($ok == 0) {
    echo "bad (there's something wrong)\n";
} else {
    echo "ugly, error checking signature\n";
}

$ok = openssl_verify('tampered'.$data, $binary_signature, $public_key, OPENSSL_ALGO_SHA1);
echo "check #2: ";
if ($ok == 1) {
    echo "ERROR: Data has been tampered, but signature is still valid! Argh!\n";
} elseif ($ok == 0) {
    echo "bad signature (as it should be, since data has beent tampered)\n";
} else {
    echo "ugly, error checking signature\n";
}

?>

C ++代码:

HCRYPTPROV hProv;
    BYTE *pbBuffer= (BYTE *)"data that is to be hashed and signed.";
    DWORD dwBufferLen = strlen((char *)pbBuffer)+1;
    HCRYPTHASH hHash;
    HCRYPTKEY hPubKey;
    BYTE *pbKeyBlob;
    // signature from php script
    BYTE *pbSignature = (BYTE*)"BõŸûëN2¸GõÂÌ_;3µÜåJˆLôMÐh’*¡mø&·À„<ááø‡–e…ÎJ‡B¥tyƒ¥Óþ'N]Ù";

    //-------------------------------------------------------------------


    char           pemPubKey[2048] = "-----BEGIN PUBLIC KEY-----MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBANDiE2+Xi/WnO+s120NiiJhNyIButVu6zxqlVzz0wy2j4kQVUC4ZRZD80IY+4wIiX2YxKBZKGnd2TtPkcJ/ljkUCAwEAAQ==-----END PUBLIC KEY-----";
    //int            readLen;
    unsigned char           derPubKey[2048];
    DWORD         derPubKeyLen = 2048;
    CERT_PUBLIC_KEY_INFO *publicKeyInfo;
    DWORD            publicKeyInfoLen;
    //HANDLE         hFile;


    if ( !CryptStringToBinaryA( pemPubKey, 0, CRYPT_STRING_BASE64HEADER, derPubKey, &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, derPubKey, derPubKeyLen,
                               CRYPT_ENCODE_ALLOC_FLAG, NULL, &publicKeyInfo, &publicKeyInfoLen ) )
    {
        fprintf( stderr, "CryptDecodeObjectEx 1 failed. Err: %p\n", GetLastError() );
        return -1;
    }

    // Acquire a cryptographic provider context handle.

    if(CryptAcquireContext(
        &hProv,
        NULL,
        NULL,
        PROV_RSA_FULL,
        CRYPT_VERIFYCONTEXT))
    {
        printf("CSP context acquired.\n");
    }
    else
    {
        MyHandleError("Error during CryptAcquireContext.");
    }

    if ( CryptImportPublicKeyInfo( hProv, MY_ENCODING_TYPE, publicKeyInfo, &hPubKey ) )
    {
        printf("The key has been imported.\n");

    }
    else
    {
        MyHandleError("Public key import failed.");
    }
    if(publicKeyInfo)
        LocalFree( publicKeyInfo );
    //-------------------------------------------------------------------
    // Create a new hash object.

    if(CryptCreateHash(
        hProv,
        CALG_SHA1,
        0,
        0,
        &hHash))
    {
        printf("The hash object has been recreated. \n");
    }
    else
    {
        MyHandleError("Error during CryptCreateHash.");
    }
    //-------------------------------------------------------------------
    // Compute the cryptographic hash of the buffer.

    if(CryptHashData(
        hHash,
        pbBuffer,
        dwBufferLen,
        0))
    {
        printf("The new hash has been created.\n");
    }
    else
    {
        MyHandleError("Error during CryptHashData.");
    }
    //-------------------------------------------------------------------
    // Validate the digital signature.

    if(CryptVerifySignature(
        hHash,
        pbSignature,
        dwSigLen,
        hPubKey,
        NULL,
        0))
    {
        printf("The signature has been verified.\n");
    }
    else
    {
        printf("Signature not validated!\n");
    }
    //-------------------------------------------------------------------
    // Free memory to be used to store signature.

    /*if(pbSignature)
        free(pbSignature);*/

    //-------------------------------------------------------------------
    // Destroy the hash object.

    if(hHash)
        CryptDestroyHash(hHash);

    //-------------------------------------------------------------------
    // Release the provider handle.

    if(hProv)
        CryptReleaseContext(hProv, 0);
    system("PAUSE");
    return 0;


推荐答案

要使用CryptoAPI进行验证, 。这是因为在Windows上,字节顺序与OpenSSL(即大字节顺序)不同。

To verify using CryptoAPI, reverse the signature and then verify. This is because, on Windows, byte ordering is different from OpenSSL (that is big endian).

您可以通过以下方式完成

You can do it in the following way

for(i=0, j=dwSigLen-1; i<j; ++i, --j) {
     char t = pbSignature[i];
     pbSignature[i] = pbSignature[j];
     pbSignature[j] = t;
}

之后,验证签名。

此可以帮助您,因为它面临类似的问题(从CryptoAPI并使用OpenSSL验证)。

This question can help you as it faces similar problem (signed from CryptoAPI and verify using OpenSSL).

这篇关于php openssl签名字符串未获得Win CryptoAPI验证的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-11 08:51