php openssl签名字符串未通过Win CryptoAPI验证

php openssl签名字符串未通过Win CryptoAPI验证,php,c++,windows,openssl,rsa,Php,C++,Windows,Openssl,Rsa,我正在使用php openssl对一些文本进行签名,并尝试在windows应用程序中使用CryptoApi进行验证,但验证总是失败。请帮帮我 PHP代码: <?php $data = "data that is to be hashed and signed."; $private_key = <<<EOD -----BEGIN RSA PRIVATE KEY----- MIIBOgIBAAJBANDiE2+Xi/WnO+s120NiiJhNyIButVu6zxql

我正在使用php openssl对一些文本进行签名,并尝试在windows应用程序中使用CryptoApi进行验证,但验证总是失败。请帮帮我

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";
}

?>
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(即big-endian)

你可以用下面的方法来做

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

for(i=0,j=dwSigLen-1;iI)反转了签名,但验证仍然失败。请尝试同时反转签名和公钥([参见此类似问题][1])[1]是的,但是这只是Base64数据——你必须先把它解码成字节串。你有没有得到他的结果?我在同一个问题上尝试过字节交换(参见评论)。@ USS3161924我在这段时间里工作了很久,但是在Windows中使用C++。问题是数据的迂回性。它正在工作。