0

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 Code:

<?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++ Code:

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;
adnan kamili
  • 7,575
  • 5
  • 50
  • 105

1 Answers1

1

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

After that, verify signature.

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

Community
  • 1
  • 1
doptimusprime
  • 8,303
  • 5
  • 41
  • 82