Why does Windows CryptVerifySignature Fail on Signature created by PHP?

前端 未结 1 501
轻奢々
轻奢々 2021-01-27 12:29

I want to create a hash in PHP and sign it on a Linux server (using XAMPP on Windows for the testing) and then verify the hash on Windows using the public key. I have the follo

相关标签:
1条回答
  • 2021-01-27 12:44

    you have logic error in php - openssl_sign function take string of data you wish to sign but not it hash.

    instead

    openssl_sign($hashvalue, $signature, $privatekey, OPENSSL_ALGO_SHA256)
    

    you need

    openssl_sign($datatohash, $signature, $privatekey, OPENSSL_ALGO_SHA256)
    

    as result you calculate hash and it signature not from "TestData" but from "814d78962b0f8ac2bd63daf9f013ed0c07fe67fbfbfbc152b30a476304a0535d" which is sha256 hash of "TestData"

    but in c++ code you calculate hash and signature from "TestData". i not check deep c++ code, probably it ok. but i be anyway use new Next Generation (CNG) Cryptography API instead old. old exist sense use only if you want support xp. anyway new api internal call new now. i be implement sign anf verify in next way:

    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, 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, 0, 0, 0, 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, pbHash, HashBlockLength, 
                        const_cast<PUCHAR>(pbSignature), cbSignature, BCRYPT_PAD_PKCS1);
                }
            }
        }
    
        return status;
    }
    
    inline NTSTATUS openssl_verify(_In_ BCRYPT_KEY_HANDLE hKey,
                                   _In_ PCSTR szToBeSigned,
                                   _In_ PCUCHAR pbSignature, 
                                   _In_ ULONG cbSignature,
                                   _In_ PCWSTR pszAlgId)
    {
        return openssl_verify(hKey, (PCUCHAR)szToBeSigned, (ULONG)strlen(szToBeSigned), pbSignature, cbSignature, pszAlgId);
    }
    
    NTSTATUS openssl_sign(_In_ BCRYPT_KEY_HANDLE hKey,
                          _In_ PCUCHAR pbToBeSigned, 
                          _In_ ULONG cbToBeSigned,
                          _Out_ PUCHAR pbSignature, 
                          _Inout_ PULONG pcbSignature,
                          _In_ PCWSTR pszAlgId)
    {
        BCRYPT_ALG_HANDLE hAlgorithm;
    
        NTSTATUS status = BCryptOpenAlgorithmProvider(&hAlgorithm, pszAlgId, 0, 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, 0, 0, 0, 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 = BCryptSignHash(hKey, &pi, pbHash, HashBlockLength, 
                        pbSignature, *pcbSignature, pcbSignature, BCRYPT_PAD_PKCS1);
                }
            }
        }
    
        return status;
    }
    
    inline NTSTATUS openssl_sign(_In_ BCRYPT_KEY_HANDLE hKey,
                                 _In_ PCSTR szToBeSigned,
                                 _Out_ PUCHAR pbSignature, 
                                 _Inout_ PULONG pcbSignature,
                                 _In_ PCWSTR pszAlgId)
    {
        return openssl_sign(hKey, (PCUCHAR)szToBeSigned, (ULONG)strlen(szToBeSigned), pbSignature, pcbSignature, 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, 0);
    
        if (0 <= status)
        {
            status = BCryptImportKeyPair(hAlgorithm, 0, 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, 0, (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, 0, (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, CRYPT_DECODE_ALLOC_FLAG|CRYPT_DECODE_NOCOPY_FLAG, 0, &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, 
                CRYPT_DECODE_ALLOC_FLAG, 0, (void**)&prkb, &cb));
    
            LocalFree(pv);
    
            if (dwError == NOERROR)
            {
                NTSTATUS status = BCryptImportKey(phKey, BCRYPT_RSAPUBLIC_BLOB, prkb, 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, pbKey, &cbKey, 0, 0))
        {
            if (pbKey)
            {
                switch (bt)
                {
                case bt_priv:
                    hr = BCryptImportPrivateKey(phKey, pbKey, cbKey);
                    break;
                case bt_pub:
                    hr = BCryptImportPublicKey(phKey, pbKey, cbKey, false);
                    break;
                case bt_cert:
                    hr = BCryptImportPublicKey(phKey, pbKey, cbKey, 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_ PCUCHAR pbSignature, 
                             _In_ ULONG cbSignature,
                             _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, pbSignature, cbSignature, pszAlgId));
    
            BCryptDestroyKey(hKey);
        }
    
        return hr;
    }
    
    HRESULT Create_Signature(_In_ PCSTR szToBeSigned, 
                             _In_ PCSTR szPrivateKey, 
                             _In_ ULONG cchPrivateKey,
                             _Out_ UCHAR** ppbSignature,
                             _Out_ ULONG* pcbSignature,
                             _In_ PCWSTR pszAlgId = BCRYPT_SHA256_ALGORITHM)
    {
        HRESULT hr;
        BCRYPT_KEY_HANDLE hKey;
    
        if (0 <= (hr = BCryptImportKey(&hKey, bt_priv, szPrivateKey, cchPrivateKey)))
        {
            ULONG cbSignature, cb;
    
            if (0 <= (hr = BCryptGetProperty(hKey, BCRYPT_SIGNATURE_LENGTH, (PUCHAR)&cbSignature, sizeof(ULONG), &cb, 0)))
            {
                if (PUCHAR pbSignature = new UCHAR[cbSignature])
                {
                    if (0 <= (hr = HRESULT_FROM_NT(openssl_sign(hKey, szToBeSigned, pbSignature, &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, pbSignature, cbSignature, 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;
        }
    }
    

    with "814d78962b0f8ac2bd63daf9f013ed0c07fe67fbfbfbc152b30a476304a0535d" string i got correct result and exactly

    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, 
        0x29, 0x84, 0x6f, 0x1c, 0xc3, 0x09, 0xcf, 0x26, 
        0x04, 0x8d, 0x2c, 0xe0, 0x3f, 0xe6, 0x73, 0xc6, 
        0x7e, 0x94, 0xee, 0x5b, 0x5e, 0x20, 0x4f, 0x50, 
        0x0f, 0x38, 0x9c, 0x63, 0x78, 0x89, 0x7c, 0x80, 
        0x73, 0xfb, 0xf4, 0x93, 0x51, 0x44, 0xc6, 0x02, 
        0xd9, 0x39, 0xae, 0xc2, 0xb0, 0xa4, 0x19, 0x95, 
        0xe6, 0x09, 0x89, 0x37, 0x77, 0x25, 0x3a, 0x0d, 
        0xe5, 0xfe, 0xc7, 0x15, 0x1d, 0xab, 0xd5, 0xba, 
        0x84, 0xc8, 0xa1, 0xe2, 0x97, 0x5f, 0x87, 0x73, 
        0xcd, 0xbb, 0x50, 0x1c, 0x4d, 0x20, 0x96, 0x19, 
        0x5f, 0x1d, 0xfe, 0xc3, 0xa7, 0x58, 0x1f, 0x07, 
        0xb9, 0x2f, 0xac, 0x42, 0x02, 0x93, 0x7a, 0x68, 
        0xb4, 0x9f, 0x5b, 0xb2, 0x9b, 0x9c, 0xcb, 0x63, 
        0xf3, 0x4f, 0xd0, 0x20, 0xc3, 0x43, 0x37, 0x1c, 
        0xb6, 0x24, 0x63, 0x8b, 0xe4, 0xf7, 0xf9, 0x82, 
        0x80, 0x09, 0xec, 0x61, 0xbf, 0x5a, 0xcc, 0x3d, 
        0xdf, 0x7e, 0x7b, 0x88, 0x18, 0x7d, 0x29, 0x9c, 
        0x7f, 0x75, 0xfb, 0x11, 0xdd, 0x60, 0xd3, 0xfb, 
        0x2a, 0xc5, 0xa4, 0x5a, 0xcd, 0x26, 0x0e, 0x13, 
        0xa9, 0x08, 0x24, 0x46, 0xa9, 0xdd, 0xf4, 0x00, 
        0x34, 0x76, 0xac, 0x71, 0x9f, 0xc1, 0x12, 0x88, 
        0x64, 0x43, 0xb7, 0xe3, 0x39, 0xa1, 0xe1, 0x50, 
        0x7e, 0x6c, 0x6c, 0xde, 0x70, 0xe1, 0xd3, 0x30, 
        0xdf, 0x3a, 0x11, 0x04, 0x4a, 0x24, 0x32, 0x0d, 
        0x67, 0x56, 0x8d, 0x25, 0x39, 0x6c, 0x40, 0xf2, 
        0x8a, 0x85, 0x67, 0x41, 0x29, 0xa2, 0xa1, 0x2f, 
        0x61, 0xaa, 0x59, 0x18, 0x60, 0xbd, 0x39, 0x39, 
        0xc2, 0x9e, 0xad, 0x74, 0xf7, 0xee, 0xcc, 0xc0, 
        0xd6, 0x9c, 0xc5, 0x5c, 0x80, 0x47, 0xe9, 0xae, 
    };
    
    0 讨论(0)
提交回复
热议问题