为什么Windows CryptVerifySignature在PHP创建的签名上失败?

如何解决为什么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 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 &lt;select id=&quot;xxx&quot;&gt; SELECT di.id, di.name, di.work_type, di.updated... &lt;where&gt; &lt;if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 &lt;property name=&quot;dynamic.classpath&quot; value=&quot;tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-