Я подписываю некоторый текст, используя 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"; } ?>
Код 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 (это большой эндиан).
Вы можете сделать это следующим образом
for(i=0, j=dwSigLen-1; i<j; ++i, --j) { char t = pbSignature[i]; pbSignature[i] = pbSignature[j]; pbSignature[j] = t; }
После этого проверьте подпись.
Этот вопрос может помочь вам, поскольку он сталкивается с аналогичной проблемой (подписанной из CryptoAPI и проверяет с помощью OpenSSL).