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?
Advertisement
Answer
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.