I'm working with an older API that requires XMLs to be signed. There is no proper documentation and the only code example was given in C#. I need to port this example to PHP. However, the code I've written in PHP gets a different output even when provided with the same input, causing the API call to fail.
I've narrowed it to this function in C#:
public byte[] CreateSignature(byte[] hash)
{
RSAPKCS1SignatureFormatter signatureFormatter = new RSAPKCS1SignatureFormatter(pfxCert.PrivateKey);
signatureFormatter.SetHashAlgorithm("SHA1");
return signatureFormatter.CreateSignature(hash);
}
Here's the same operation in PHP:
public function createSignature($hashByteArray, $certArray) {
$hash = implode(array_map("chr", $hashByteArray));
$hashEncoded = base64_encode($hash);
openssl_sign($hashEncoded,$signature, $certArray);
return unpack("C*", $signature);
}
Note, the input in openssl_sign can't take a byte array, so this is a possible point of difference. I've tried all algorithms provided by openssl_get_md_methods() and also phpseclib, neither have matched the output.
I've created a GitHub gist of the same example input and certificate in both C# and PHP to better illustrate the issue.
How can I get the same signing output in PHP as C#, given the same input?
There's a fundamental difference between them.
The RSAPKCS1SignatureFormatter.CreateSignature method expects a data hash. openssl_sign
on the other hand expects the data itself.
From PHP: openssl_sign - Manual
openssl_sign() computes a signature for the specified data by generating a cryptographic digital signature using the private key associated with priv_key_id. Note that the data itself is not encrypted.
Apparently you generate a hash of some data to use with the API written in C#. Do not do it with openssl_sign
, instead call with the original data. openssl_sign
will hash it before signing, this is by design.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With