I am getting error with ECDSA SHA-512 algorithm when converting from c# to php

  • Hello everyone!
  • I’m having trouble converting code from C# to PHP.
  • I want the code in php to use the same algorithm as my code in c#.
  • The signature in the C# code I created was verified correctly, but the signature created from the php code (I used the same private key) was verified failed.
    *I know that the encryption algorithm in the C# source code IS: ECDSA SHA-512
    I have tried using many different libraries in php but still the signature cannot be verified
private void btn_Create_Signature_Click(object sender, EventArgs e)
{
    if (string.IsNullOrWhiteSpace(txt_CRB_3_3_x.Text))
    {
        MessageBox.Show("ID is not entered.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
    }
    else
    {
        string crbKeyFilePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "crb.xml");
        string crbxml = File.ReadAllText(crbKeyFilePath);
        string textBoxData = txt_CRB_3_3_x.Text; // Data from textbox1

        string idTagStart = "<Id>";
        string idTagEnd = "</Id>";

        int startIndex = crbxml.IndexOf(idTagStart) + idTagStart.Length;
        int endIndex = crbxml.IndexOf(idTagEnd);

        if (startIndex >= 0 && endIndex >= 0)
        {
            string updatedCrbxml = crbxml.Substring(0, startIndex) + textBoxData + crbxml.Substring(endIndex);
            File.WriteAllText(crbKeyFilePath, updatedCrbxml);
        }
        else
        {
            MessageBox.Show("ID tags <Id></Id> not found in the file.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
        }

        // Path to the file to store the signature
        string signedFilePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "crb.key");

        // Read XML content from the file
        XElement xelement = XElement.Load(crbKeyFilePath);

        // Display XML content in a message box
        MessageBox.Show(xelement.ToString(), "XML Content");

        // String containing the encrypted private key and password
        string privateKey = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "privateKey.pem");
        string fileContent = File.ReadAllText(privateKey);
        string string_2 = "999999999";

        // Remove header and footer from the PEM string
        string base64PrivateKey = ExtractBase64FromPem(fileContent);

        // Create or get the Signature element
        XElement signatureElement = xelement.Element("Signature") ?? new XElement("Signature");

        try
        {
            if (signatureElement.Parent != null)
            {
                signatureElement.Remove();
            }

            // Decrypt the private key
            AsymmetricKeyParameter asymmetricKeyParameter = smethod_1(base64PrivateKey, string_2);

            // Prepare data for signing
            byte[] bytes = Encoding.UTF8.GetBytes(xelement.ToString(SaveOptions.DisableFormatting));

            // Initialize the signer with the signature algorithm
            string string_0 = "1.2.840.10045.4.3.4"; // Change the algorithm if needed
            ISigner signer = SignerUtilities.GetSigner(string_0);
            signer.Init(true, asymmetricKeyParameter);
            signer.BlockUpdate(bytes, 0, bytes.Length);

            // Create the signature
            byte[] signature = signer.GenerateSignature();
            signatureElement.Value = Convert.ToBase64String(signature);

            // Save the signature to a file
            string signatureBase64 = Convert.ToBase64String(signature);
            File.WriteAllText("signatureCSharp.txt", signatureBase64);
        }
        catch (Exception ex)
        {
            MessageBox.Show("An error occurred while creating the signature: " + ex.Message);
            return;
        }
        finally
        {
            // Add the Signature element to the XML
            xelement.Add(signatureElement);

            // Convert the XML content to a byte array
            byte[] xmlBytes = Encoding.UTF8.GetBytes(xelement.ToString());

            // Encode the byte array to Base64 string
            string base64EncodedXML = Convert.ToBase64String(xmlBytes);

            // Save the Base64 string to a file
            File.WriteAllText(signedFilePath, base64EncodedXML);

            MessageBox.Show("Signature created and saved to file: " + signedFilePath, "Notification", MessageBoxButtons.OK, MessageBoxIcon.Information);
        }
    }
}
  • PHP CODE SOURCE :
<?php
session_start();

require 'vendor/autoload.php';
use phpseclib3\Crypt\EC;
use phpseclib3\Crypt\PublicKeyLoader;
use phpseclib3\Crypt\EC\Curves\nistp521;
use phpseclib3\Crypt\Hash;

// Đường dẫn đến tệp crb.xml
$crbFilePath = 'crb.xml';

// Nội dung khóa riêng tư đã mã hóa dưới dạng base64
$encryptedPrivateKeyContent = "MIHBMCQGCiqGSIb3DQEMAQMwFgQQhF07E7HT9E2UWQHhcRpLwgICCAAEgZjGWAViMrjZBoiRvW7oP7FuvQFFKJMqk80kHP94clyome8AUHbEzuwoIyfGrvgApj5g6TEZUoDaIiZylxeM+cfIix5znQRl0hj+HkPDxa6XpR+wXaurQvbRFAypUv6L75ZccJdO8KCDwsDB6O9+yqUlKdfTU5JpQsOx0OT+3q5yk8JrmlBzKCg5R+VWPsHUxTgwHJRcr3kd0w==";
$password = '999999999';

// Giải mã base64
$decodedPrivateKeyContent = base64_decode($encryptedPrivateKeyContent);

// Tạo chuỗi PEM bằng cách thêm header và footer
$privateKeyPem = "-----BEGIN ENCRYPTED PRIVATE KEY-----\n";
$privateKeyPem .= chunk_split(base64_encode($decodedPrivateKeyContent), 64, "\n");
$privateKeyPem .= "-----END ENCRYPTED PRIVATE KEY-----\n";

// Giải mã khóa riêng tư
$privateKey = PublicKeyLoader::load($privateKeyPem, $password);

// Đọc nội dung XML từ file
$dom = new DOMDocument();
$dom->preserveWhiteSpace = false;
$dom->load($crbFilePath);
$dom->formatOutput = true;

// Loại bỏ phần tử "Signature" nếu có
while ($dom->getElementsByTagName('Signature')->length > 0) {
    $signatureNode = $dom->getElementsByTagName('Signature')->item(0);
    $signatureNode->parentNode->removeChild($signatureNode);
}

// Chuyển đổi DOMDocument thành chuỗi XML với khai báo
$xmlProlog = '<?xml version="1.0" encoding="utf-8"?>';
$dataToSign = $xmlProlog . $dom->saveXML($dom->documentElement);

// Tạo chữ ký
$hash = new Hash('sha512');
$hashData = $hash->hash($dataToSign);
$signature = $privateKey->sign($hashData);

// Chuyển chữ ký thành dạng base64 và thêm vào XML
$signatureBase64 = base64_encode($signature);
$signatureElement = $dom->createElement('Signature', $signatureBase64);
$dom->documentElement->appendChild($signatureElement);

// Lưu nội dung XML đã có chữ ký vào tệp crb.xml
file_put_contents($crbFilePath, $dom->saveXML());

// Mã hóa toàn bộ nội dung của tệp crb.xml thành base64 và lưu vào tệp crb.key
$base64Content = base64_encode(file_get_contents($crbFilePath));
$keyFilePath = 'crb.key';
if (file_put_contents($keyFilePath, $base64Content) === false) {
    echo "Lỗi: không thể tạo tệp crb.key";
    exit;
}

echo "Chữ ký đã được tạo và lưu vào file: " . $keyFilePath;
?>
  • This is the content of the xml file that needs to be signed:
<License>
  <Id></Id>
  <Type>Standard</Type>
  <Customer>
    <Name>Alessandro Maciell</Name>
    <Email>sandrobota@gmail.co</Email>
  </Customer>
  
<Signature>MEUCIQDPSHurS8VlCXGKKvQrMlKOlvRbg0t5+J3O64XYNawqJQIgXrvJjIk0e7ZFt4Kqhosz4tTBQOJ3H3Z+0xatZ0P7ir4=</Signature>
</License>
  • C# source code validates signature :
private void btn_Verify_Signature_Click(object sender, EventArgs e)
{
    // Determine the path to the crb.key file in the application's root directory
    string filePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "crb.key");

    // Check if the file exists
    if (!File.Exists(filePath))
    {
        Console.WriteLine("File crb.key does not exist.");
        return;
    }

    string string_1 = "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEnO2SV+sdiMX9OzjcWrsDDlWR7AGfh9fNQgnE2AB/QdEYP0AmAjVPGTORSRlSNF9R6V4rPqSJDZRuEcNqOYmBmA==";

    // Read XML content from the crb.key file
    XElement xelement = XElement.Load(filePath);
    XElement signatureElement = xelement.Element("Signature");
    bool flag = false;

    if (signatureElement != null)
    {
        try
        {
            signatureElement.Remove(); // Temporarily remove the "Signature" element
            AsymmetricKeyParameter asymmetricKeyParameter = smethod_3(string_1);
            byte[] bytes = Encoding.UTF8.GetBytes(xelement.ToString(SaveOptions.DisableFormatting));
            ISigner signer = SignerUtilities.GetSigner(this.string_0);
            signer.Init(false, asymmetricKeyParameter);
            signer.BlockUpdate(bytes, 0, bytes.Length);
            flag = signer.VerifySignature(Convert.FromBase64String(signatureElement.Value));
        }
        finally
        {
            xelement.Add(signatureElement); // Add the "Signature" element back
        }
    }

    // Use the flag variable to perform necessary actions after verifying the signature
    if (flag)
    {
        // Valid signature
        MessageBox.Show("Valid signature.");
    }
    else
    {
        // Invalid signature
        MessageBox.Show("Invalid signature.");
    }
}

private string ExtractBase64FromPem(string pemContent)
{
    var start = "-----BEGIN EC PRIVATE KEY-----";
    var end = "-----END EC PRIVATE KEY-----";
    var base64 = pemContent
        .Replace(start, "")
        .Replace(end, "")
        .Replace("\r", "")
        .Replace("\n", "")
        .Trim();
    return base64;
}