如何解决为什么Windows CryptVerifySignature在PHP创建的签名上失败?
我想在PHP中创建一个哈希并在Linux服务器上对其进行签名(使用Windows上的XAMPP进行测试),然后使用公钥在Windows上验证该哈希。我有以下PHP脚本来生成它(然后单击鼠标右键,查看源代码,将签名创建复制/粘贴到C / C ++ Windows应用程序)。当我运行Windows应用程序时,SHA256哈希与PHP中创建的哈希匹配,但验证失败。我试过不字节交换Windows中的签名,但同样的问题。我在做什么错了?
这是PHP代码:
#include <iostream>
using namespace std;
struct Node
{
int data;
Node *link;
};
int main()
{
cout << "Starting main program \n";
Node head;
head.data = 0;
head.link = NULL;
cout << "After declaring head and initializing values \n";
//Declaring a pointer variable which points to an entity of type struct.
Node *previous;
*previous=head;
cout << "After declaring previous pointer \n";
bool done = false;
int i = 1;
cout << "First while loop\n";
while(!done)
{
cout << i << ": Iteration";
Node temp;
temp.data=i;
temp.link=NULL;
if(i > 2)
{
done = true;
continue;
}
*previous->link=temp;
++i;
*previous = temp;
}
done = false;
cout << "Declaring temp pointer before printing \n";
Node *temp;
*temp = head;
cout << "Second while loop\n";
while (!done)
{
cout << i << ": Iteration";
if(temp == NULL)
{
done = true;
continue;
}
cout << temp->data << "->";
*temp = *temp->link;
}
cout << "NULL";
}
这是Windows C / C ++代码:
<?php
$privatekey=<<<EOD
-----BEGIN PRIVATE KEY-----
MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQC27fzjIIr/V3ds
1hLNyuyrpw5yAtTPG/deWyaU1kLHk028ohfkm9nbGFCloJNiIf51fSlpyPDiBjnC
pTCr/ac6TPGcXiJcxNvpzK9uFS2iQDgWHlJzvPT5dJacvg8RWXklVg3wseHMnp1t
mvCZrMDCiay4dAL0GWRyxUe12kX05XA4J0oSJbi11zwIq3SlhtzWaCn7njOLV0dh
BLidBhEY1Y47rjikCFaJrfac324NNvNuIJPI0gfhtqZFjjSC9vhUw0zE9SWl8iLb
3+qJ6HJ/Et+iPMGCmuvR4YB/UrdoN/pKQazfIfYoaRnoz0rT55uj42TL/mdhgWkO
3ftuocJtAgMBAAECggEBAKqq7z2YpxYDrNBGCdUmdhjQC5IjQhjYprnJoP1LyZIZ
xHUxZclL/r2CuftNDTSJMra6x2CCsPqvhEQtinNsfBDQqLqSuMyEfghrh2DVMXYn
JCy+rX591LDILZyfVb+CEpza5Lajv18AvS/9VmyJ2G2ntRWCZx8GcckCdh0cQBhy
QPKGmad2iBs0vcsP+2JTqxy1jMIPTydCVYwyXpTqqfUFvFWkeTQ8ZZT7mopOUqTL
wJBUTNwEbTCaoVMP/Ya57KjT0/3iD9r3n2IIOUsE1fIDJqFaoE0cXtERjTnkevTa
xJeuiqvVEd9+i2coTrpywLX6Ri9ATnYECg8XMW568gECgYEA8wqzxOM9TjV2yxyE
O3d6Fo6nVBpdFoj1S9Ies7SLwHEwIyF3/FmQB75jJs8uMhFNHbKpOiscOeKmtkEd
iSrN4qyQboNvBsHbL7nS0yF5zo9zRWH6RfAjV2Z+8cRNhN1rQqYrLZjDilo26B4c
VMmCoOGOKaPnYVMqAc9cPTmVZd0CgYEAwK7PRznksy19k8qRPZdtnlHMhNucNr0+
UvxK5MGV0aTvM5ZoJb75fT7YD5YN05FoMB4N4xO05S/l9ewM62zUOnTIRJM5wyDA
MEmTl5yxFv7CKpglAByc+hYsRQ+wES0GJ5p+yjFNP3kNANUIjIVQVWSJB6s6XsHL
qcFk3k4M7dECgYEA09AT9BeHKk32BfYIWDs8L8SLmASR9D3Qag/pqfxDf6glp7hX
dZooqFcI2p3dSM1DRAqc6ZEAvIIHgPcm4pBndpGmHmp1rJHukJ2GW3LlUVw7vdAx
6hnq8xTktZe7Z3wBKsjfAJIOeNk+2PTFBC/KpKNu3mN2F5//ECzD2qgAyBECgYEA
qKIVnMOpSbuddRRLSvlVocL7WKePL0Uu35gYv95BDcro4mBXY/mhBqFSnUl5blmL
MtmK09rybcce3r0pjX2gvExq3cFwQztNmLU8K+uh/XsXWgnwEAn6xNFVC1gwgsfB
5DVNlA3UCqIZ5EmOAtXGOgYT+5c7LaU0ZqxwaDMtE5ECgYB5j2uYxS75QgziesFs
ibIhmXYNhfZydpce5fhsIVZADOBTrj1Pkb9qoXAJgGgbuI17E+Mb5Adgs3W5YWHy
MJG9Ih8xQRM6Xau4EGF+I73JWcQHDxeoEYFi8nvTtb//hUMsME/gADyXgthTBPXS
fYx1VsZzfLe9U3YxOmrgM6fXIA==
-----END PRIVATE KEY-----
EOD;
$publickey=<<<EOD
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtu384yCK/1d3bNYSzcrs
q6cOcgLUzxv3XlsmlNZCx5NNvKIX5JvZ2xhQpaCTYiH+dX0pacjw4gY5wqUwq/2n
OkzxnF4iXMTb6cyvbhUtokA4Fh5Sc7z0+XSWnL4PEVl5JVYN8LHhzJ6dbZrwmazA
womsuHQC9BlkcsVHtdpF9OVwOCdKEiW4tdc8CKt0pYbc1mgp+54zi1dHYQS4nQYR
GNWOO644pAhWia32nN9uDTbzbiCTyNIH4bamRY40gvb4VMNMxPUlpfIi29/qiehy
fxLfojzBgprr0eGAf1K3aDf6SkGs3yH2KGkZ6M9K0+ebo+Nky/5nYYFpDt37bqHC
bQIDAQAB
-----END PUBLIC KEY-----
EOD;
// $datatohash=$_POST["var1"].$_POST["var2"].$_POST["var3"];
$datatohash="TestData";
$hashvalue=hash("sha256",$datatohash);
if (openssl_sign($hashvalue,$signature,$privatekey,OPENSSL_ALGO_SHA256)) {
echo "Success: ",$hashvalue,"\n",base64_encode($signature),"\n\n";
echo "BYTE Signature[]={ ";
for ($i = 0; $i < strlen($signature); $i++) {
echo "0x",dechex(ord($signature[$i])),",";
}/*
for ($i = strlen($signature)-1; $i >=0 ; $i--) {
echo "0x",";
}*/
echo "};\n";
if (openssl_verify($hashvalue,$publickey,OPENSSL_ALGO_SHA256)) {
echo "Verified\n";
}
else {
echo "Verification Failed\n";
}
}
else {
echo "Failure:";
}
?>
解决方法
您在php中遇到逻辑错误-openssl_sign
函数接受您希望签名的数据字符串,但不进行哈希处理。
代替
openssl_sign($hashvalue,$signature,$privatekey,OPENSSL_ALGO_SHA256)
您需要
openssl_sign($datatohash,OPENSSL_ALGO_SHA256)
结果是,您不是从"TestData"
而是从"814d78962b0f8ac2bd63daf9f013ed0c07fe67fbfbfbc152b30a476304a0535d"
计算哈希及其签名,而"TestData"
是"TestData"
的sha256哈希
,但是在 c ++ 代码中,您从inline ULONG BOOL_TO_ERROR(BOOL f)
{
return f ? NOERROR : GetLastError();
}
NTSTATUS openssl_verify(_In_ BCRYPT_KEY_HANDLE hKey,_In_ PCUCHAR pbToBeSigned,_In_ ULONG cbToBeSigned,_In_ PCUCHAR pbSignature,_In_ ULONG cbSignature,_In_ PCWSTR pszAlgId)
{
BCRYPT_ALG_HANDLE hAlgorithm;
NTSTATUS status = BCryptOpenAlgorithmProvider(&hAlgorithm,pszAlgId,0);
if (0 <= status)
{
BCRYPT_HASH_HANDLE hHash = 0;
ULONG HashBlockLength,cb;
0 <= (status = BCryptGetProperty(hAlgorithm,BCRYPT_HASH_LENGTH,(PUCHAR)&HashBlockLength,sizeof(ULONG),&cb,0)) &&
0 <= (status = BCryptCreateHash(hAlgorithm,&hHash,0));
BCryptCloseAlgorithmProvider(hAlgorithm,0);
if (0 <= status)
{
PUCHAR pbHash = (PUCHAR)alloca(HashBlockLength);
0 <= (status = BCryptHashData(hHash,const_cast<PUCHAR>(pbToBeSigned),cbToBeSigned,0)) &&
0 <= (status = BCryptFinishHash(hHash,pbHash,HashBlockLength,0));
BCryptDestroyHash(hHash);
if (0 <= status)
{
BCRYPT_PKCS1_PADDING_INFO pi = { pszAlgId };
status = BCryptVerifySignature(hKey,&pi,const_cast<PUCHAR>(pbSignature),cbSignature,BCRYPT_PAD_PKCS1);
}
}
}
return status;
}
inline NTSTATUS openssl_verify(_In_ BCRYPT_KEY_HANDLE hKey,_In_ PCSTR szToBeSigned,_In_ PCWSTR pszAlgId)
{
return openssl_verify(hKey,(PCUCHAR)szToBeSigned,(ULONG)strlen(szToBeSigned),pbSignature,pszAlgId);
}
NTSTATUS openssl_sign(_In_ BCRYPT_KEY_HANDLE hKey,_Out_ PUCHAR pbSignature,_Inout_ PULONG pcbSignature,0));
BCryptDestroyHash(hHash);
if (0 <= status)
{
BCRYPT_PKCS1_PADDING_INFO pi = { pszAlgId };
status = BCryptSignHash(hKey,*pcbSignature,pcbSignature,BCRYPT_PAD_PKCS1);
}
}
}
return status;
}
inline NTSTATUS openssl_sign(_In_ BCRYPT_KEY_HANDLE hKey,_In_ PCWSTR pszAlgId)
{
return openssl_sign(hKey,pszAlgId);
}
NTSTATUS BCryptImportKey(_Out_ BCRYPT_KEY_HANDLE *phKey,_In_ PCWSTR pszBlobType,_In_ BCRYPT_RSAKEY_BLOB* prkb,_In_ ULONG cb)
{
BCRYPT_ALG_HANDLE hAlgorithm;
NTSTATUS status = BCryptOpenAlgorithmProvider(&hAlgorithm,BCRYPT_RSA_ALGORITHM,0);
if (0 <= status)
{
status = BCryptImportKeyPair(hAlgorithm,pszBlobType,phKey,(PUCHAR)prkb,cb,0);
BCryptCloseAlgorithmProvider(hAlgorithm,0);
}
return status;
}
HRESULT BCryptImportPrivateKey(_Out_ BCRYPT_KEY_HANDLE *phKey,_In_ PCUCHAR pbKey,_In_ ULONG cbKey)
{
ULONG cb;
PCRYPT_PRIVATE_KEY_INFO PrivateKeyInfo;
ULONG dwError = BOOL_TO_ERROR(CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,PKCS_PRIVATE_KEY_INFO,pbKey,cbKey,CRYPT_DECODE_ALLOC_FLAG|CRYPT_DECODE_NOCOPY_FLAG,(void**)&PrivateKeyInfo,&cb));
if (dwError == NOERROR)
{
BCRYPT_RSAKEY_BLOB* prkb;
dwError = BOOL_TO_ERROR(CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,CNG_RSA_PRIVATE_KEY_BLOB,PrivateKeyInfo->PrivateKey.pbData,PrivateKeyInfo->PrivateKey.cbData,CRYPT_DECODE_ALLOC_FLAG,(void**)&prkb,&cb));
LocalFree(PrivateKeyInfo);
if (dwError == NOERROR)
{
NTSTATUS status = BCryptImportKey(phKey,BCRYPT_RSAPRIVATE_BLOB,prkb,cb);
LocalFree(prkb);
return HRESULT_FROM_NT(status);
}
}
return HRESULT_FROM_WIN32(dwError);
}
HRESULT BCryptImportPublicKey(_Out_ BCRYPT_KEY_HANDLE *phKey,_In_ PCUCHAR pbKeyOrCert,_In_ ULONG cbKeyOrCert,bool bCert)
{
ULONG cb;
union {
PVOID pvStructInfo;
PCERT_INFO pCertInfo;
PCERT_PUBLIC_KEY_INFO PublicKeyInfo;
};
ULONG dwError = BOOL_TO_ERROR(CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,bCert ? X509_CERT_TO_BE_SIGNED : X509_PUBLIC_KEY_INFO,pbKeyOrCert,cbKeyOrCert,&pvStructInfo,&cb));
if (dwError == NOERROR)
{
BCRYPT_RSAKEY_BLOB* prkb;
PVOID pv = pvStructInfo;
if (bCert)
{
PublicKeyInfo = &pCertInfo->SubjectPublicKeyInfo;
}
dwError = BOOL_TO_ERROR(CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,CNG_RSA_PUBLIC_KEY_BLOB,PublicKeyInfo->PublicKey.pbData,PublicKeyInfo->PublicKey.cbData,&cb));
LocalFree(pv);
if (dwError == NOERROR)
{
NTSTATUS status = BCryptImportKey(phKey,BCRYPT_RSAPUBLIC_BLOB,cb);
LocalFree(prkb);
return HRESULT_FROM_NT(status);
}
}
return HRESULT_FROM_WIN32(dwError);
}
enum BLOB_TYPE { bt_priv,bt_pub,bt_cert };
HRESULT BCryptImportKey(_Out_ BCRYPT_KEY_HANDLE *phKey,_In_ BLOB_TYPE bt,_In_ PCSTR szKey,_In_ ULONG cchKey)
{
PUCHAR pbKey = 0;
ULONG cbKey = 0;
HRESULT hr;
while (CryptStringToBinaryA(szKey,cchKey,CRYPT_STRING_BASE64HEADER,&cbKey,0))
{
if (pbKey)
{
switch (bt)
{
case bt_priv:
hr = BCryptImportPrivateKey(phKey,cbKey);
break;
case bt_pub:
hr = BCryptImportPublicKey(phKey,false);
break;
case bt_cert:
hr = BCryptImportPublicKey(phKey,true);
break;
default: hr = E_INVALIDARG;
}
_freea(pbKey);
return hr;
}
if (!(pbKey = (PUCHAR)_malloca(cbKey)))
{
break;
}
}
hr = HRESULT_FROM_WIN32(GetLastError());
if (pbKey) _freea(pbKey);
return hr;
}
HRESULT Verify_Signature(_In_ PCSTR szToBeSigned,_In_ PCSTR szPublicKeyOrCert,_In_ ULONG cchPublicKeyOrCert,_In_ bool bCert,_In_ PCWSTR pszAlgId = BCRYPT_SHA256_ALGORITHM)
{
HRESULT hr;
BCRYPT_KEY_HANDLE hKey;
if (0 <= (hr = BCryptImportKey(&hKey,bCert ? bt_cert : bt_pub,szPublicKeyOrCert,cchPublicKeyOrCert)))
{
hr = HRESULT_FROM_NT(openssl_verify(hKey,szToBeSigned,pszAlgId));
BCryptDestroyKey(hKey);
}
return hr;
}
HRESULT Create_Signature(_In_ PCSTR szToBeSigned,_In_ PCSTR szPrivateKey,_In_ ULONG cchPrivateKey,_Out_ UCHAR** ppbSignature,_Out_ ULONG* pcbSignature,bt_priv,szPrivateKey,cchPrivateKey)))
{
ULONG cbSignature,cb;
if (0 <= (hr = BCryptGetProperty(hKey,BCRYPT_SIGNATURE_LENGTH,(PUCHAR)&cbSignature,0)))
{
if (PUCHAR pbSignature = new UCHAR[cbSignature])
{
if (0 <= (hr = HRESULT_FROM_NT(openssl_sign(hKey,&cbSignature,pszAlgId))))
{
*pcbSignature = cbSignature,*ppbSignature = pbSignature;
}
else
{
delete [] pbSignature;
}
}
}
BCryptDestroyKey(hKey);
}
return hr;
}
void SignTest()
{
char TestToBeSigned[] = "814d78962b0f8ac2bd63daf9f013ed0c07fe67fbfbfbc152b30a476304a0535d";
PUCHAR pbSignature;
ULONG cbSignature;
if (0 <= Create_Signature(TestToBeSigned,PrivateKey,_countof(PrivateKey) - 1,&pbSignature,&cbSignature))
{
if (0 > Verify_Signature(TestToBeSigned,PublicKey,_countof(PublicKey) - 1,false))
{
__debugbreak();
}
ULONG i = 0;
DbgPrint("const UCHAR Signature[] = {");
do
{
if (!(i++ & 7)) DbgPrint("\n\t");
DbgPrint("0x%02x,",pbSignature[i]);
} while (--cbSignature);
DbgPrint("\n};\n");
delete [] pbSignature;
}
}
计算哈希和签名。我没有检查深的 c ++ 代码,可能还可以。但无论如何,我还是要使用新的下一代(CNG)密码API。仅当您想支持XP时,才可以使用旧的存在感。无论如何,新的api内部调用现在是新的。我将以以下方式实施签名和验证:
"814d78962b0f8ac2bd63daf9f013ed0c07fe67fbfbfbc152b30a476304a0535d"
使用const UCHAR Signature[] = {
0x48,0x7d,0xeb,0x0c,0x3c,0x6b,0x2e,0xd7,0x17,0x8d,0x9b,0x43,0xe2,0x29,0x97,0x8c,0x35,0x65,0x5a,0x41,0x89,0x4a,0x18,0x26,0x84,0x6f,0x1c,0xc3,0x09,0xcf,0x04,0x2c,0xe0,0x3f,0xe6,0x73,0xc6,0x7e,0x94,0xee,0x5b,0x5e,0x20,0x4f,0x50,0x0f,0x38,0x9c,0x63,0x78,0x7c,0x80,0xfb,0xf4,0x93,0x51,0x44,0x02,0xd9,0x39,0xae,0xc2,0xb0,0xa4,0x19,0x95,0x37,0x77,0x25,0x3a,0x0d,0xe5,0xfe,0xc7,0x15,0x1d,0xab,0xd5,0xba,0xc8,0xa1,0x5f,0x87,0xcd,0xbb,0x4d,0x96,0xa7,0x58,0x1f,0x07,0xb9,0x2f,0xac,0x42,0x7a,0x68,0xb4,0x9f,0xb2,0xcb,0xf3,0xd0,0xb6,0x24,0x8b,0xe4,0xf7,0xf9,0x82,0xec,0x61,0xbf,0xcc,0x3d,0xdf,0x7b,0x88,0x7f,0x75,0x11,0xdd,0x60,0xd3,0x2a,0xc5,0x0e,0x13,0xa9,0x08,0x46,0x00,0x34,0x76,0x71,0xc1,0x12,0x64,0xb7,0xe3,0xe1,0x6c,0xde,0x70,0x30,0x32,0x67,0x56,0x40,0xf2,0x8a,0x85,0xa2,0xaa,0x59,0xbd,0x9e,0xad,0x74,0xc0,0xd6,0x5c,0x47,0xe9,};
字符串,我得到了正确的结果,并且完全是
simple_salesforce
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。