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