Splitting base64 signature value in a xml signed file

2.9k views Asked by At

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://stackoverflow.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

There are 2 answers

0
Jose On BEST ANSWER

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);
6
Zerratar On

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.