79293440

Date: 2024-12-19 07:46:48
Score: 1.5
Natty:
Report link

Sorry for any confusion that I've created. Thanks @Rukmini for leading me in the right direction. My goal was to use the data, the public key and the signature that I will receive from a external system as three base64 strings, to verify them in both C# and in OpenSSL. In this scenario, the external system is Azure Key Vault; I have an EC Key stored there, and I am using the Azure Key Vault REST APIs for sign and verify operations.

My issue was that the signature was in raw format, and OpenSSL always failed the verification.

So the first thing I do is run this C# script

using System.Formats.Asn1;
using System.Security.Cryptography;

// Inputs
// Public key and Signature from another system.
string publicKey_FromOtherSystem = "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEcLNwTTk9eixQnaMPBmETJpdip0FBHcRrO1Rm2j6geNmWcl1v1pnoipc7ah09sWayJrlssqGTMX2CHiaU6X5kXQ==";
string signature_FromOtherSystem = "fKsprDKyHNqIP3lCtJBBp+Kt+oEOPgYUpPDtA4/O0J+1A1xAku9PsVe/wMI3DgjUR0LMLkWeY950hLJ/L0dVwQ==";
string input = "SGVsbG8gV29ybGQ="; 

byte[] input_base64_bytes = Convert.FromBase64String(input);
byte[] digest = SHA256.Create().ComputeHash(input_base64_bytes);
string input_hex = BitConverter.ToString(digest).Replace("-", "");
Console.WriteLine("Digest: " + input_hex); // Check this value with the one you get in openssl

byte[] publicKeyBytes = Convert.FromBase64String(publicKey_FromOtherSystem);
byte[] signatureBytes = Convert.FromBase64String(signature_FromOtherSystem);

// convert the raw signature from the other system to be ASN1.DER Formatted
byte[] rfc3279DerSignature = ConvertIeeeP1363ToRfc3279Der(signatureBytes);
string rfc3279DerSignature_base64 = Convert.ToBase64String(rfc3279DerSignature); // This signature must be validated also with openssl
Console.WriteLine("Signature in RFC3279 DER format: " + rfc3279DerSignature_base64);

using (ECDsa ecdsa = ECDsa.Create())
{
    ecdsa.ImportSubjectPublicKeyInfo(publicKeyBytes, out _);
    bool isValid = false;
    isValid = ecdsa.VerifyHash(digest, signatureBytes, DSASignatureFormat.Rfc3279DerSequence);
    Console.WriteLine($"IEEE Signature verification returned: {isValid}"); // This should FAIL (using the Raw Signature)
    isValid = ecdsa.VerifyHash(digest, rfc3279DerSignature, DSASignatureFormat.Rfc3279DerSequence);
    Console.WriteLine($"RFC Signature verification returned: {isValid}"); // This should be valid // This will be true even without the Leading Zeros, but it will fail in OpenSSL
}

static byte[] ConvertIeeeP1363ToRfc3279Der(byte[] ieeeSignature)
{
    if (ieeeSignature.Length % 2 != 0)
    {
        throw new ArgumentException("Invalid IEEE P1363 signature length");
    }

    int halfLength = ieeeSignature.Length / 2;
    byte[] r = new byte[halfLength];
    byte[] s = new byte[halfLength];

    Array.Copy(ieeeSignature, 0, r, 0, halfLength);
    Array.Copy(ieeeSignature, halfLength, s, 0, halfLength);

    var writer = new AsnWriter(AsnEncodingRules.DER);
    writer.PushSequence();
    writer.WriteInteger(AddLeadingZeroIfNeeded(r));
    writer.WriteInteger(AddLeadingZeroIfNeeded(s));
    writer.PopSequence();

    return writer.Encode();
}

static byte[] AddLeadingZeroIfNeeded(byte[] value)
{
    if (value[0] >= 0x80)
    {
        byte[] extendedValue = new byte[value.Length + 1];
        Array.Copy(value, 0, extendedValue, 1, value.Length);
        return extendedValue;
    }
    return value;
}

Now, using both signatures, the one that I got from the external system and the one converted by the C# script above, I've tried to validate the signature using OpenSSL

$ data="SGVsbG8gV29ybGQ="
$ pubkey="MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEcLNwTTk9eixQnaMPBmETJpdip0FBHcRrO1Rm2j6geNmWcl1v1pnoipc7ah09sWayJrlssqGTMX
2CHiaU6X5kXQ=="
$ sigRaw="fKsprDKyHNqIP3lCtJBBp+Kt+oEOPgYUpPDtA4/O0J+1A1xAku9PsVe/wMI3DgjUR0LMLkWeY950hLJ/L0dVwQ=="
$ sigRfc="MEUCIHyrKawyshzaiD95QrSQQafirfqBDj4GFKTw7QOPztCfAiEAtQNcQJLvT7FXv8DCNw4I1EdCzC5FnmPedISyfy9HVcE="

$ echo $data | base64 -d > data.bin
$ echo $pubkey | base64 -d > pubKey.pem
$ echo $sigRfc | base64 -d > sigrfc.bin
$ echo $sigRaw | base64 -d > sigraw.bin

$ openssl dgst -sha256 data.bin
SHA2-256(data.bin)= a591a6d40bf420404a011733cfb7b190d62c65bf0bcda32b57b277d9ad9f146e

$ openssl dgst -sha256 -verify pubkey.pem -signature sigraw.bin data.bin
Error verifying data

$ openssl dgst -sha256 -verify pubkey.pem -signature sigrfc.bin data.bin
Verified OK

Conclusion: My issue was when I tried to convert the raw signature to RFC3279. I was missing the leading zeros and after adding those leading zeros, the signature was validated also in OpenSSL

Reasons:
  • Blacklisted phrase (0.5): Thanks
  • Long answer (-1):
  • Has code block (-0.5):
  • User mentioned (1): @Rukmini
  • Self-answer (0.5):
  • Low reputation (1):
Posted by: Brãnicã