Trying to code a PHP equivalent of this C# code. Hashing and Signing of a text value

beautifulcan

New member
Joined
Jun 24, 2025
Messages
3
Programming Experience
Beginner
I have this code block in C# that I am trying to convert to PHP and Java. But already got stuck on PHP

C#:
// code sample given to me as to how the Token is created
var text = "Text to Hash and then Sign";

var store = new X509Store(StoreName.My);
store.Open(OpenFlags.ReadOnly);
var certificate = store.Certificates.Single(c => c.Thumbprint == "Whatever-Your-Thumbprint-Is"); // or grab the certificate however you please
var certp = certificate.GetRSAPrivateKey();
    
// Hash the data
var sha1 = new SHA1Managed();
var data = Encoding.Unicode.GetBytes(text);
var hash = sha1.ComputeHash(data);

// Sign the hash
var signedBytes = certp.SignHash(hash, CryptoConfig.MapNameToOID("SHA1"));
var token = Convert.ToBase64String(signedBytes);

It is for an API that I am calling. But when I code it in PHP, it looks to be getting the wrong result in my tests.

I am not too familiar with C#. But the above code, from what I can tell, opens and gets the Private Key, SHA1 hashes the text, then signs it with the private key.

I do the same with PHP, but when I get to pass the token, the API call fails (cuz of the token). I open the Certificate, sha1 hash it, then certificate sign it using SHA1.

PHP:
$certFile = "/location/of/certificate.pfx"; 
$certPassword = "password";

// Load the certificate
$cert = file_get_contents($certFile);
if (!$cert) {
    throw new Exception("Unable to load the certificate");
}

// Load the certificate from file using the passphrase
$pkeyid = openssl_pkcs12_read($cert, $certData, $certPassword);
if (!$pkeyid) {
    throw new Exception("Unable to read the certificate or incorrect password");
}

//validated that the fingerprint of this certificate is the correct and matches
//$fingerprint = openssl_x509_fingerprint($certData['cert'], 'sha1', false);
//if ($fingerprint !== 'Whatever-Your-Thumbprint-Is') throw new Exception("Wrong certificate");

$datatohash = 'Text to Hash and then Sign';
$data = mb_convert_encoding($datatohash, 'UTF-16LE', 'UTF-8'); 

$hash = sha1($data);

$signedBytes = '';
if (!openssl_sign($hash, $signedBytes, $certData['pkey'], OPENSSL_ALGO_SHA1)) {
    throw new Exception("Error signing the hash");
}

$signed_token = base64_encode($signedBytes);

// Extra check to verify the sign
if (openssl_verify($hash, base64_decode($signed_token), $certData['cert'], OPENSSL_ALGO_SHA1)) {
   // signature is correct
} else {
    throw new Exception("Validation Error signing the hash");
}

I am not sure if I misinterpreted the C# code, or if I am failing in the conversion to PHP (probably both? heh).

Any help would GREATLY be appreciated.
 
I don't know PHP APIs that well. Are you absolutely sure that accessing $certData['pkey'] will give you the private key from the certificate?
 
I don't know PHP APIs that well. Are you absolutely sure that accessing $certData['pkey'] will give you the private key from the certificate?

I am absolutely sure that $certData['pkey'] is the valid private key from the certificate. Also the last validation check in PHP I am doing is verifying the signature using the public key and it validates.

Also, maybe I should post this in a php forum? I initially posted here because the source code is C# and I am not too familiar with the language.
 
Also the last validation check in PHP I am doing is verifying the signature using the public key and it validates.

Perhaps it's the way you are sending the token to the API that is issue, and not necessarily the creation of the token.

A quick way to verify if the generated token is correct is to sign the same string both using the C# code and using the PHP code. If the results are different, then it's the token. If the tokens are the same, then it's something about the transmission.
 
What happens when you use these instead: openssl_pkey_get_private() and openssl_pkey_get_public() ?
 
What happens when you use these instead: openssl_pkey_get_private() and openssl_pkey_get_public() ?

I have a .pfx PKCS, but those functions require a PEM format, thus I use the openssl_pkcs12_read() function to open the PKCS cert.

Perhaps it's the way you are sending the token to the API that is issue, and not necessarily the creation of the token.

A quick way to verify if the generated token is correct is to sign the same string both using the C# code and using the PHP code. If the results are different, then it's the token. If the tokens are the same, then it's something about the transmission.

My computer doesn't have the IDE for me to try the C# code to see the output.

I did try an online compiler to do a quick test to at least do the initial SHA1 hash. Don't think I will try to do the signing online. I tested grabbing the SHA1 hash before I signed it with a cert:

C#:
Using System;
using System.Text;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;

public class HelloWorld
{
    public static void Main(string[] args)
    {
        var txt = "Text to Hash";
        
        var sha1 = new SHA1Managed();
        var data = Encoding.Unicode.GetBytes(txt);
        var hash = sha1.ComputeHash(data);
        
        var sb = new StringBuilder();
        var sb1 = new StringBuilder();
        foreach (var hashByte in hash)
        {
            sb.AppendFormat("{0:x2}", hashByte);
            sb1.Append(hashByte);
        }
        var hashString = sb.ToString();
        var hashString1 = sb1.ToString();
        Console.WriteLine (hash);
        Console.WriteLine (hashString);
        Console.WriteLine (hashString1);
    }
}

Console Output:
System.Byte[]
e24f0badfebdcb668aca658d28fa2813d012dced
226791117325418920310213820210114140250401920818220237

So it looks like in C# it gets a byte[] array, and uses that to sign. In my original PHP code, I grab the string hash.

My php String hash is the same as the hashString (converting the byte[] to string) (e24f0badfebdcb668aca658d28fa2813d012dced == e24f0badfebdcb668aca658d28fa2813d012dced) so I know it is partially hashing it correct, but looks like the data I am signing with is different.

in C#, it is signing the Byte[] array. in PHP, I am signing the string representation of the hash

but in PHP, I can do sha1($data, true) which will return the binary hash. but I try signing with that, and still no dice. Might be something with the hash itself that is causing issues. hmm, guess I will play around some more
 
Back
Top Bottom