0
votes

I am trying to sign some XML files, which i managed to do fine, yet i can't find a way to check the signature, the receiver service accepts it fine (the xml), but it finds error on the signature.

I have checked the documentation of the web service and they said, signature values can have UP to 76 characters per line, and i must preserve.whitespace everytime i load or edit the xml file.

This is my xml file once outputted (i edited some values for security) puu.sh/d6lwC/25eb2a0d02.png (notice how the two signature values are a long line without spacing.

This is how i think it should look: puu.sh/d6lCV/48b0cc0cd7.png

This is the xml file as should be as per service documentation: puu.sh/d6ltJ/bd8e25a4b4.png

Here's my signing code

     SignedXml signedXml = new SignedXml(xmldocument);
        signedXml.SigningKey = certificado.PrivateKey;
        Signature XMLSignature = signedXml.Signature;
        Reference reference = new Reference();
        reference.Uri = referenciaUri;
        XMLSignature.SignedInfo.AddReference(reference);
        KeyInfo keyInfo = new KeyInfo();
        keyInfo.AddClause(new RSAKeyValue((RSA)certificado.PrivateKey));
        keyInfo.AddClause(new KeyInfoX509Data(certificado));
        XMLSignature.KeyInfo = keyInfo;
        signedXml.ComputeSignature();
        XmlElement xmlDigitalSignature = signedXml.GetXml();
        xmldocument.DocumentElement.SelectSingleNode(para).AppendChild(xmldocument.ImportNode(xmlDigitalSignature, true));    

My question is:

How can i split the lines of the signature value easily without damaging other core values of the xml itself, so with that change making the webservice being able to read and validate correctly the signature of the xml file?

Thanks in advance, and forgive my crappy english.

Edit: I found this question https://stackguides.com/questions/24916486/how-to-do-enveloped-rsa-sha1-digital-signature-of-xml-data-using-php

he somehow manged to solve my problem via php splitting the base64 value by chunks and 76 length with this code

// Base64 encoding
$SignatureValue = rtrim(chunk_split(base64_encode($SignatureValue_bruto), 76));    

how can i achieve that with c#?

2
I found this code and implemented it but i can't split the total of the base64 string puu.sh/d6mtC/4f7306e9b9.png - Glas
Perhaps start at looking on what those php functions really do and then do it in c# :-) rtrim trims the right side of a string. Chunk_split splits a string every 76th character (defined by the input parameter) and the base64_encode is just a simple base64 encoding. :-) combine it and you will get your answer! - Zerratar
Karl, I am on that, but i am not sure if it will works puu.sh/d6omi/e931d1a79d.png - Glas

2 Answers

1
votes

A little old, but I think is much simpler to let dotNet do the work for you like this:

var bytes = Convert.FromBase64String(str);
return Convert.ToBase64String(bytes, Base64FormattingOptions.InsertLineBreaks);
0
votes

Alright! You can try this :-) Add the following code

    public static string base64_encode(string str)
    {
        return System.Convert.ToBase64String(Encoding.UTF8.GetBytes(str));
    }

    public static string chunk_split(string str, int len)
    {
        var strings = new List<string>();
        var div = str.Length % len;
        var remainder = len - div * len;

        if (div == 1)
        {
            return string.Join("", str.Take(len));
        }

        for (var j = 0; j < div; j++)
        {
            var s = string.Join("", str.Skip(j * len).Take(len));
            if (!string.IsNullOrEmpty(s))
                strings.Add(s);
        }

        if (remainder > 0)
        {
            var s = string.Join("", str.Skip(div * len).Take(remainder));
            if (!string.IsNullOrEmpty(s))
                strings.Add(s);
        }

        return string.Join(Environment.NewLine, strings.ToArray());
    }

    public static string rtrim(string input)
    {
        while (input.EndsWith(Environment.NewLine))
            input = input.Remove(input.Length - Environment.NewLine.Length);

        return input.TrimEnd(' ');
    }

and then just use

chunk_split(base64_encode(strstr), 76);

EDIT You could use this function to fix the signature of the document. I don't know how else I can help you :P

    public static void UpdateXmlSignature(string filename)
    {
        // Load the target xml, the xml file with the certificate
        var doc = XDocument.Load(filename);
        var cert = doc.XPathSelectElement("//X509Data/X509Certificate");
        if (cert != null)
        {
            var updatedValue = rtrim(chunk_split(base64_encode(cert.Value), 76));
            cert.Value = updatedValue;
        }

        // Overwrite the old file
        doc.Save(filename);
    }

this will require that all code is in place.