CryptoSys Home > FirmaSAT > Using Sat.SignXmlToBytes

Signing a document in memory: Using Sat.SignXmlToBytes


With FirmaSAT, you can do all operations necessary to sign an XML document in memory without using files at all.

With .NET code you must be careful to distinguish between byte[] array and string types, especially if you need to save your work eventually as a file. If you have non-ASCII characters (like, say, "ñ") in your XML it can get messy handing UTF-8 encoded data in a normal string type. It is safer use a byte[] array.

Example code

Here is some code in C# that demonstrates some techniques.

 1 using System;
 2 using System.Text;
 3 using System.IO;
 4 using System.Diagnostics;
 5 using FirmaSAT; 
 6 
 7 /*! SignXmlToBytes.cs v1.0.0 | (c) 2017 DI Management Services Pty Ltd <http://cryptosys.net/> | MIT */
 8 
 9 namespace SignXmlToBytes
10 {
11     class SignXmlToBytes
12     {
13         static void Main(string[] args)
14         {
15             Console.WriteLine("Version={0}", General.Version());
16             byte[] xmlData;
17             byte[] signedData;
18             string baseFile = "cfdv33a-base.xml";
19             string newFile = "signed-frombytes.xml";
20             string xmlStr;
21             int r;
22             // We can pass the certificate and private key directly as strings
23             string certFileData =
24                 "-----BEGIN CERTIFICATE-----" +
25                 "MIIF+TCCA+GgAwIBAgIUMzAwMDEwMDAwMDAzMDAwMjM3MDgwDQYJKoZIhvcNAQELBQAwggFmMSAwHgY" +
26                 "DVQQDDBdBLkMuIDIgZGUgcHJ1ZWJhcyg0MDk2KTEvMC0GA1UECgwmU2VydmljaW8gZGUgQWRtaW5pc3" +
27                 "RyYWNpw7NuIFRyaWJ1dGFyaWExODA2BgNVBAsML0FkbWluaXN0cmFjacOzbiBkZSBTZWd1cmlkYWQgZ" +
28                 "GUgbGEgSW5mb3JtYWNpw7NuMSkwJwYJKoZIhvcNAQkBFhphc2lzbmV0QHBydWViYXMuc2F0LmdvYi5t" +
29                 "eDEmMCQGA1UECQwdQXYuIEhpZGFsZ28gNzcsIENvbC4gR3VlcnJlcm8xDjAMBgNVBBEMBTA2MzAwMQs" +
30                 "wCQYDVQQGEwJNWDEZMBcGA1UECAwQRGlzdHJpdG8gRmVkZXJhbDESMBAGA1UEBwwJQ295b2Fjw6FuMR" +
31                 "UwEwYDVQQtEwxTQVQ5NzA3MDFOTjMxITAfBgkqhkiG9w0BCQIMElJlc3BvbnNhYmxlOiBBQ0RNQTAeF" +
32                 "w0xNzA1MTgwMzU0NTZaFw0yMTA1MTgwMzU0NTZaMIHlMSkwJwYDVQQDEyBBQ0NFTSBTRVJWSUNJT1Mg" +
33                 "RU1QUkVTQVJJQUxFUyBTQzEpMCcGA1UEKRMgQUNDRU0gU0VSVklDSU9TIEVNUFJFU0FSSUFMRVMgU0M" +
34                 "xKTAnBgNVBAoTIEFDQ0VNIFNFUlZJQ0lPUyBFTVBSRVNBUklBTEVTIFNDMSUwIwYDVQQtExxBQUEwMT" +
35                 "AxMDFBQUEgLyBIRUdUNzYxMDAzNFMyMR4wHAYDVQQFExUgLyBIRUdUNzYxMDAzTURGUk5OMDkxGzAZB" +
36                 "gNVBAsUEkNTRDAxX0FBQTAxMDEwMUFBQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJdU" +
37                 "csHIEIgwivvAantGnYVIO3+7yTdD1tkKopbL+tKSjRFo1ErPdGJxP3gxT5O+ACIDQXN+HS9uMWDYnaU" +
38                 "RalSIF9COFCdh/OH2Pn+UmkN4culr2DanKztVIO8idXM6c9aHn5hOo7hDxXMC3uOuGV3FS4ObkxTV+9" +
39                 "NsvOAV2lMe27SHrSB0DhuLurUbZwXm+/r4dtz3b2uLgBc+Diy95PG+MIu7oNKM89aBNGcjTJw+9k+Wz" +
40                 "JiPd3ZpQgIedYBD+8QWxlYCgxhnta3k9ylgXKYXCYk0k0qauvBJ1jSRVf5BjjIUbOstaQp59nkgHh45" +
41                 "c9gnwJRV618NW0fMeDzuKR0CAwEAAaMdMBswDAYDVR0TAQH/BAIwADALBgNVHQ8EBAMCBsAwDQYJKoZ" +
42                 "IhvcNAQELBQADggIBABKj0DCNL1lh44y+OcWFrT2icnKF7WySOVihx0oR+HPrWKBMXxo9KtrodnB1tg" +
43                 "Ix8f+Xjqyphhbw+juDSeDrb99PhC4+E6JeXOkdQcJt50Kyodl9URpCVWNWjUb3F/ypa8oTcff/eMftQ" +
44                 "ZT7MQ1Lqht+xm3QhVoxTIASce0jjsnBTGD2JQ4uT3oCem8bmoMXV/fk9aJ3v0+ZIL42MpY4POGUa/iT" +
45                 "aawklKRAL1Xj9IdIR06RK68RS6xrGk6jwbDTEKxJpmZ3SPLtlsmPUTO1kraTPIo9FCmU/zZkWGpd8ZE" +
46                 "AAFw+ZfI+bdXBfvdDwaM2iMGTQZTTEgU5KKTIvkAnHo9O45SqSJwqV9NLfPAxCo5eRR2OGibd9jhHe8" +
47                 "1zUsp5GdE1mZiSqJU82H3cu6BiE+D3YbZeZnjrNSxBgKTIf8w+KNYPM4aWnuUMl0mLgtOxTUXi9MKnU" +
48                 "ccq3GZLA7bx7Zn211yPRqEjSAqybUMVIOho6aqzkfc3WLZ6LnGU+hyHuZUfPwbnClb7oFFz1PlvGOpN" +
49                 "DsUb0qP42QCGBiTUseGugAzqOP6EYpVPC73gFourmdBQgfayaEvi3xjNanFkPlW1XEYNrYJB4yNjphF" +
50                 "rvWwTY86vL2o8gZN0Utmc5fnoBTfM9r2zVKmEi6FUeJ1iaDaVNv47te9iS1ai4V4vBY8r" +
51                 "-----END CERTIFICATE-----";
52             string keyFileData =
53                 "-----BEGIN ENCRYPTED PRIVATE KEY-----" +
54                 "MIIFDjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQI5qDMtGWYa2wCAggA" +
55                 "MBQGCCqGSIb3DQMHBAhFAqj+c0f8JASCBMhNUpNUp57vMu8L3LHBKRBTFl0VE3oq" +
56                 "BIEKBHFYYz063iiS0Y3tPW3cplLTSqG25MdbIQcHCxwmPVYNdetHUjqjeR+TklWg" +
57                 "tnMbLqvdMmmRxAFuHXznHFIa4U+YNedhFm7sdR2DsGFijm3vIpUbvpILtpTrhog/" +
58                 "EHAvZXV6+F86cYc9+LUg3d0DRwJc+sWmk+2xOoXvOvvpnnQqfhQxkSknfITmc+HA" +
59                 "WgHbKLK2q6e2RixjpWn0sA9LslYD0ZDn5uhrce+QEfK97asraFfiteqXf2Ll8B54" +
60                 "Ku/er+O2JEu62vVDFumwMtZOuHKH4NbjOmMzKIwRTKp/1jp6OTGYSKIRiTDXnTET" +
61                 "JwgItHahf7UAoM/qnkJa17Ood4hiCYopMyCXdhyMDJoFhWRanQODaiocb7XpMm1S" +
62                 "EpTtHZeKgEVWSc/obYgSgs4iY497UR2MUVZQSCBdRXCgs5g1c31cCwAZ6r41KMoL" +
63                 "OBVLtRXoT0mc0D6ovlwYuJhqYvuwjdNkWJS7qwXuy8b2ux4t027NGUXmgtb9XQDm" +
64                 "8yJrdTtm0CktWPKe7i2tQtBC2tAjduGAlBrzY+whySRN8KUJQbYKhOBaLXgEPI93" +
65                 "wi/SKHJO13WvfqqjKqrqJwB3tvhjz5E1uDKmDFoivdS76uq+k/xpmF5OWBmypWNV" +
66                 "iw7kgvmH1OeTBKYkUHIL85skL6pdycGnTk3g0AmG9xtPYu6pdSqUv+N8QmTdmmdu" +
67                 "85fDEN0fk2t2BRPANsbIqxopVfj5qIwm+8TbZDdNj8OssxrC5sRy5yDBjV4J+x25" +
68                 "3yaILn7wgUR6Yj6GaHUUF4GISmFZ/PTbnVPDd424w6hGV8NKtUHXq5ms2kJXo6XG" +
69                 "iGqjbdePM53QhdSrxTM5Dt76RcAInky6w5s/7gvT/w7tdbVA/SPhp4xgaT8Crmjb" +
70                 "k3upcSqNI0HuROBxOs0gRRAWXScUZJ0Vd1V0F+C5cG2R1CtGTYeRmIAwLwcWf6Dj" +
71                 "Y1Q+TOe/W3eTatOo+gIozjYDCk5ZNfeQzq4p1ApN6+gzS8kNxtvKOYJogjV74RK/" +
72                 "Xl7u7oLv4SZT7Nl1YRpScW1ouIcNNTP0AC+j2OFZ3YueN8CcmvXbgSW8pYRooTxn" +
73                 "Ffo9sdOL624uwRyb2DwwLO0Vo3aBIEIf8sm9sqocXmwh9sxFPEbTXPCuMSao8Qjy" +
74                 "BOlsCem2589NVZs0h0ipGwdbatcjkgf+hzRoYBdlvHtKHJ8gL/A/Ap8z0+TK5NaV" +
75                 "WUA+zXOZRZ66NYfs18DEbJKjwOcnnsLcfAMYoSn697148sL4JBv8IOmM6QXfxCl/" +
76                 "0yU0d5/876L5jOL56lfH0eBk8s2nioAl3yRBl2wlihWi39sA0bsdHFKYEX+LqPBB" +
77                 "CAdxZAvXCCJcdEdxOXSgEiFAmW9+IXFT/WJeGcZ4OmCd3Qf0fxGqFXA/9hIUumWd" +
78                 "e6s0wN8LjXuFZQaMDaaVIGXKguP3OijsfBF0PYzI+L6CfUi2BLaYNJTlbQxbncmW" +
79                 "2PKeDiypgt3ZY1PKV66o5OAJEAkV3vf9cRwXE5T8GwZHA+wx2rWC98hkH15xfI9q" +
80                 "EsYulVdcXWzCF58HFQjUoDon0e/QMukS0eNgq9ipmoKAWKyy7+TQw7Xx3MmqkGlL" +
81                 "HGM=" +
82                 "-----END ENCRYPTED PRIVATE KEY-----";
83             string password = "12345678a";
84 
85             // Show cert number in X.509 certificate
86             Console.WriteLine("NumberCert={0}", Sat.GetCertNumber(certFileData));
87 
88             // Read in XML data as a byte array
89             xmlData = ReadABinaryFile(baseFile);
90 
91             // Sign it
92             signedData = Sat.SignXmlToBytes(xmlData, keyFileData, password, certFileData, 0);
93             Console.WriteLine("signedData has {0} bytes", signedData.Length);
94             Debug.Assert(signedData.Length > 0);
95 
96             // Check the output is valid XML, 
97             // but first put into a string because other functions require a string, not bytes.
98             // Use Sat.Asciify to avoid problems with UTF-8-encoded characters in a string.
99             xmlStr = Sat.Asciify(signedData);   // signedData is type `byte[]`; xmlStr is type `string`
100             r = Sat.ValidateXml(xmlStr);
101             Console.WriteLine("Sat.ValidateXml(string) returns {0}", r);
102             Debug.Assert(0 == r);
103             r = Sat.VerifySignature(xmlStr);
104             Console.WriteLine("Sat.VerifySignature(string) returns {0}", r);
105             Debug.Assert(0 == r);
106 
107             // Check cert number in XML
108             Console.WriteLine("NoCertificado={0}", Sat.GetXmlAttribute(xmlStr, "NoCertificado", "Comprobante"));
109 
110             // Save bytes directly into a binary file
111             MakeABinaryFile(newFile, signedData);
112 
113             // Now check the new file
114             r = Sat.ValidateXml(newFile);
115             Console.WriteLine("Sat.ValidateXml(file) returns {0}", r);
116             Debug.Assert(0 == r);
117             r = Sat.VerifySignature(newFile);
118             Console.WriteLine("Sat.VerifySignature(file) returns {0}", r);
119             Debug.Assert(0 == r);
120 
121         }
122 
123         /* UTILITIES FOR BINARY FILES */
124         static byte[] ReadABinaryFile(string fileName)
125         {
126             byte[] b = new byte[0];
127             FileInfo finfo = new FileInfo(fileName);
128             if (finfo.Exists) {
129                 FileStream fsi = finfo.OpenRead();
130                 BinaryReader br = new BinaryReader(fsi);
131                 int count = (int)fsi.Length;
132                 b = br.ReadBytes(count);
133                 br.Close();
134                 fsi.Close();
135             }
136             Debug.Assert(finfo.Exists, "File '" + fileName + "' does not exist.");
137             return b;
138         }
139         static bool MakeABinaryFile(string fileName, byte[] data)
140         {
141             FileStream fs;
142             BinaryWriter bw;
143             fs = new FileStream(fileName, FileMode.Create, FileAccess.Write);
144             bw = new BinaryWriter(fs);
145             bw.Write(data);
146             bw.Close();
147             fs.Close();
148             return true;
149         }
150 
151     }
152 }

Remarks

Output:

Version=80200
NumberCert=30001000000300023708
signedData has 6491 bytes
Sat.ValidateXml(string) returns 0
Sat.VerifySignature(string) returns 0
NoCertificado=30001000000300023708
Sat.ValidateXml(file) returns 0
Sat.VerifySignature(file) returns 0

Download source code and xml (11.9 kB).

Contact us

To contact us or comment on this page, please send us a message.

This page last updated 10 September 2025