This question already has answers here:
How do I convert a vector of strings to a vector of integers in a functional way?
(3 answers)
Closed 3 years ago.
I'm passing an encrypted message between client/server over TCP using AES-GCM-SIV. The received buffer is converted to String and divided into several Vec<&str> using
let v: Vec<&str> = buffer_string.split("?+").collect();
Example of v:
["POST / HTTP/1.1\\r\\n\\", "Uaxh5NUi098q", "178", "[162, 254, 28, 241, ... ]"]
v[3] should be the ciphertext as Vec<u8>. How can the vector be used as Vec<u8>?
iter().map(|c| *c as u8).collect()
would work with chars, not &str.
Here's a complete example on the Playground:
fn main() {
let buffer_string = r##"POST /chat HTTP/1.1\r\n\?+rRMUG4Lg8Gi6?+178?+[136, 136, 144, 59, 173, 25, 204, 247, 151, 53, 2, 137, 100, 45, 198, 58, 65, 210, 134, 165, 163, 156, 136, 148, 46, 31, 16, 184, 179, 73, 220, 14, 113, 152, 85, 1, 233, 208, 53, 27, 124, 52, 41, 175, 86, 109, 134, 103, 93, 148, 208, 114, 123, 97, 18, 53, 149, 195, 51, 55, 213, 114, 184, 72, 109, 30, 217, 206, 212, 58, 253, 141, 9, 45, 173, 213, 96, 35, 77, 122, 113, 240, 22, 222, 194, 11, 123, 221, 176, 116, 161, 196, 84, 203, 203, 184, 140, 42, 169, 244, 211, 1, 189, 96, 16, 62, 173, 50, 65, 48, 176, 44, 176, 246, 246, 242, 18, 146, 105, 29, 13, 223, 185, 151, 114, 30, 27, 36, 48, 178, 16, 3, 250, 49, 229, 84, 121, 135, 197, 204, 42, 140, 220, 244, 73, 184, 250, 104, 125, 224, 219, 94, 111, 247, 92, 16, 168, 50, 249, 10, 65, 214, 217, 157, 7, 113, 217, 141, 174, 139, 183, 86, 17, 24, 221, 134, 222, 240]"##;
let v: Vec<&str> = buffer_string.split("?+").collect();
println!("Vector: v1 {:?}, v2 {:?}, v3: {:?}", v[1], v[2], v[3]);
//only the v[3] is needed as vec<u8>
//error with iter and &str
//let ciphertext_vec: Vec<_> = v[3].iter().map(|c| c.parse::<u8>().unwrap()).collect();
let ciphertext: Vec<u8> = [
136, 136, 144, 59, 173, 25, 204, 247, 151, 53, 2, 137, 100, 45, 198, 58, 65, 210, 134, 165,
163, 156, 136, 148, 46, 31, 16, 184, 179, 73, 220, 14, 113, 152, 85, 1, 233, 208, 53, 27,
124, 52, 41, 175, 86, 109, 134, 103, 93, 148, 208, 114, 123, 97, 18, 53, 149, 195, 51, 55,
213, 114, 184, 72, 109, 30, 217, 206, 212, 58, 253, 141, 9, 45, 173, 213, 96, 35, 77, 122,
113, 240, 22, 222, 194, 11, 123, 221, 176, 116, 161, 196, 84, 203, 203, 184, 140, 42, 169,
244, 211, 1, 189, 96, 16, 62, 173, 50, 65, 48, 176, 44, 176, 246, 246, 242, 18, 146, 105,
29, 13, 223, 185, 151, 114, 30, 27, 36, 48, 178, 16, 3, 250, 49, 229, 84, 121, 135, 197,
204, 42, 140, 220, 244, 73, 184, 250, 104, 125, 224, 219, 94, 111, 247, 92, 16, 168, 50,
249, 10, 65, 214, 217, 157, 7, 113, 217, 141, 174, 139, 183, 86, 17, 24, 221, 134, 222,
240,
]
.to_vec();
let ciphertext2: Vec<u8> = v[3].iter().map(|c| c.parse::<u8>().unwrap()).collect();
assert_eq!(ciphertext, ciphertext2);
// ciphertext: Vec<u8> =
}
I believe that does it.
fn main() {
let s = "[162, 254, 28, 241]";
let v: Vec<u8> = s
.trim_start_matches('[')
.trim_end_matches(']')
.split(',')
.map(|c| c.trim().parse::<u8>().unwrap())
.collect();
for n in v {
println!("{}", n);
}
}
Try it here.
I have a binary string in Elixir that's composed of compressed bytes that I want to deflate and extract the "real data" from:
iex(93)> data
<<31, 139, 8, 0, 0, 0, 0, 0, 0, 0, 109, 80, 203, 110, 218, 64, 0, 76, 171, 70, 141, 68, 78, 105, 213, 67, 171, 74, 168, 7, 212, 86, 50, 172, 189, 94, 236, 69, 66, 173, 49, 40, 56, 96, 76, 130, 31, 196, 23, 226, 216, 11, 44, 216, 94, 227, 117, 13, 238, 199, 244, 208, 207, 234, 23, 244, 23, 122, 43, 137, 218, 91, 110, 243, 208, 204, 72, 83, 187, 56, 61, 59, 169, 255, 126, 121, 245, 227, 69, 237, 226, 125, 41, 117, 66, 150, 52, 105, 146, 241, 42, 92, 179, 230, 61, 99, 69, 148, 51, 26, 117, 196, 14, 122, 251, 170, 119, 164, 245, 254, 3, 175, 127, 188, 33, 15, 230, 167, 15, 53, 109, 58, 29, 27, 186, 102, 27, 214, 228, 243, 155, 167, 211, 210, 159, 231, 235, 162, 200, 120, 167, 213, 10, 210, 71, 165, 25, 198, 148, 164, 5, 111, 174, 24, 91, 197, 164, 121, 204, 181, 146, 32, 223, 146, 162, 21, 177, 125, 26, 179, 32, 106, 245, 255, 129, 47, 89, 16, 110, 131, 21, 153, 4, 9, 233, 62, 61, 208, 40, 73, 206, 41, 75, 117, 22, 145, 46, 106, 112, 30, 119, 197, 70, 193, 182, 36, 237, 106, 150, 173, 39, 192, 22, 151, 188, 93, 85, 75, 52, 2, 78, 110, 136, 90, 101, 17, 228, 43, 179, 126, 24, 109, 122, 217, 72, 231, 238, 140, 248, 83, 205, 229, 73, 79, 77, 101, 129, 162, 148, 135, 246, 88, 95, 32, 107, 39, 229, 153, 155, 219, 250, 118, 236, 196, 14, 104, 187, 150, 228, 91, 154, 194, 132, 188, 7, 29, 65, 25, 122, 201, 236, 90, 91, 78, 50, 49, 191, 180, 190, 29, 59, 146, 91, 213, 50, 23, 43, 92, 84, 36, 240, 124, 103, 98, 198, 90, 60, 47, 231, 133, 105, 175, 16, 173, 42, 67, 217, 5, 222, 149, 61, 208, 92, 115, 70, 215, 166, 158, 89, 17, 112, 239, 105, 168, 30, 134, 91, 60, 242, 6, 163, 18, 122, 202, 94, 42, 47, 157, 104, 176, 151, 199, 223, 5, 225, 154, 223, 82, 52, 104, 251, 150, 195, 131, 74, 223, 249, 169, 13, 54, 96, 108, 26, 195, 249, 46, 94, 192, 233, 58, 106, 252, 255, 203, 136, 186, 2, 148, 85, 36, 73, 176, 141, 17, 84, 177, 36, 42, 50, 132, 157, 119, 101, 146, 2, 44, 28, 82, 153, 142, 124, 111, 7, 5, 97, 64, 151, 192, 62, 32, 112, 195, 191, 254, 252, 101, 78, 79, 230, 207, 238, 78, 55, 103, 230, 227, 253, 125, 45, 127, 13, 48, 22, 177, 164, 96, 5, 41, 80, 145, 219, 0, 171, 16, 159, 159, 255, 5, 242, 139, 137, 38, 42, 2, 0, 0>>
I'm not sure how to unzip this data. So far, I've:
Looked through Official Elixir Docs
Tried using Erlang's :zip and :zlib modules but had no success. Both of them throw errors:
iex(100)> :zlib.uncompress(data)
** (ErlangError) erlang error: :data_error
:zlib.call/3
:zlib.inflate/2
:zlib.uncompress/1
iex(101)> :zip.unzip data
{:error,
{:EXIT,
{{:badmatch,
<<31, 139, 8, 0, 0, 0, 0, 0, 0, 0, 109, 80, 203, 110, 218, 64, 0, 76, 171, 70, 141, 68, 78, 105, 213, 67, 171, 74, 168, 7, 212, 86, 50, 172, 189, 94, 236, 69, 66, 173, 49, 40, 56, 96, 76, 130, ...>>},
[{:zip, :binary_io, 2, [file: 'zip.erl', line: 1726]},
{:zip, :get_end_of_central_dir, 3, [file: 'zip.erl', line: 1313]},
{:zip, :get_central_dir, 3, [file: 'zip.erl', line: 1269]},
{:zip, :do_unzip, 2, [file: 'zip.erl', line: 380]},
{:zip, :unzip, 2, [file: 'zip.erl', line: 370]},
{:erl_eval, :do_apply, 6, [file: 'erl_eval.erl', line: 670]},
{:elixir, :erl_eval, 3, [file: 'src/elixir.erl', line: 215]},
{:elixir, :eval_forms, 4, [file: 'src/elixir.erl', line: 203]}]}}}
I know for a fact that the data is correct, I was able to extract information from the same bytes in Javascript using JXG.Util.Unzip(). But, how do I unzip this data in Elixir?
Your data was gzip compressed data according to the file command, so I tried :zlib.gunzip and it worked:
iex(1)> data = <<31, 139, 8, 0, 0, 0, 0, 0, 0, 0, 109, 80, 203, 110, 218, 64, 0, 76, 171, 70, 141, 68, 78, 105, 213, 67, 171, 74, 168, 7, 212, 86, 50, 172, 189, 94, 236, 69, 66, 173, 49, 40, 56, 96, 76, 130, 31, 196, 23, 226, 216, 11, 44, 216, 94, 227, 117, 13, 238, 199, 244, 208, 207, 234, 23, 244, 23, 122, 43, 137, 218, 91, 110, 243, 208, 204, 72, 83, 187, 56, 61, 59, 169, 255, 126, 121, 245, 227, 69, 237, 226, 125, 41, 117, 66, 150, 52, 105, 146, 241, 42, 92, 179, 230, 61, 99, 69, 148, 51, 26, 117, 196, 14, 122, 251, 170, 119, 164, 245, 254, 3, 175, 127, 188, 33, 15, 230, 167, 15, 53, 109, 58, 29, 27, 186, 102, 27, 214, 228, 243, 155, 167, 211, 210, 159, 231, 235, 162, 200, 120, 167, 213, 10, 210, 71, 165, 25, 198, 148, 164, 5, 111, 174, 24, 91, 197, 164, 121, 204, 181, 146, 32, 223, 146, 162, 21, 177, 125, 26, 179, 32, 106, 245, 255, 129, 47, 89, 16, 110, 131, 21, 153, 4, 9, 233, 62, 61, 208, 40, 73, 206, 41, 75, 117, 22, 145, 46, 106, 112, 30, 119, 197, 70, 193, 182, 36, 237, 106, 150, 173, 39, 192, 22, 151, 188, 93, 85, 75, 52, 2, 78, 110, 136, 90, 101, 17, 228, 43, 179, 126, 24, 109, 122, 217, 72, 231, 238, 140, 248, 83, 205, 229, 73, 79, 77, 101, 129, 162, 148, 135, 246, 88, 95, 32, 107, 39, 229, 153, 155, 219, 250, 118, 236, 196, 14, 104, 187, 150, 228, 91, 154, 194, 132, 188, 7, 29, 65, 25, 122, 201, 236, 90, 91, 78, 50, 49, 191, 180, 190, 29, 59, 146, 91, 213, 50, 23, 43, 92, 84, 36, 240, 124, 103, 98, 198, 90, 60, 47, 231, 133, 105, 175, 16, 173, 42, 67, 217, 5, 222, 149, 61, 208, 92, 115, 70, 215, 166, 158, 89, 17, 112, 239, 105, 168, 30, 134, 91, 60, 242, 6, 163, 18, 122, 202, 94, 42, 47, 157, 104, 176, 151, 199, 223, 5, 225, 154, 223, 82, 52, 104, 251, 150, 195, 131, 74, 223, 249, 169, 13, 54, 96, 108, 26, 195, 249, 46, 94, 192, 233, 58, 106, 252, 255, 203, 136, 186, 2, 148, 85, 36, 73, 176, 141, 17, 84, 177, 36, 42, 50, 132, 157, 119, 101, 146, 2, 44, 28, 82, 153, 142, 124, 111, 7, 5, 97, 64, 151, 192, 62, 32, 112, 195, 191, 254, 252, 101, 78, 79, 230, 207, 238, 78, 55, 103, 230, 227, 253, 125, 45, 127, 13, 48, 22, 177, 164, 96, 5, 41, 80, 145, 219, 0, 171, 16, 159, 159, 255, 5, 242, 139, 137, 38, 42, 2, 0, 0>>
<<31, 139, 8, 0, 0, 0, 0, 0, 0, 0, 109, 80, 203, 110, 218, 64, 0, 76, 171, 70, 141, 68, 78, 105, 213, 67, 171, 74, 168, 7, 212, 86, 50, 172, 189, 94, 236, 69, 66, 173, 49, 40, 56, 96, 76, 130, 31, 196, 23, 226, ...>>
iex(2)> :zlib.gunzip(data)
<<11, 18, 5, 8, 0, 32, 232, 7, 74, 158, 4, 11, 18, 29, 118, 50, 58, 99, 111, 109, 46, 105, 109, 112, 115, 121, 99, 104, 111, 46, 98, 111, 111, 116, 100, 114, 111, 105, 100, 58, 49, 58, 53, 26, 19, 66, 111, 111, 116, 32, ...>>
From the docs.
gunzip(Data) -> Decompressed
Types:
Data = iodata()
Decompressed = binary()
Uncompress data (with gz headers and checksum).
Good day to all, first of all WALL OF TEXT WARNING! I've done a lot of research and i'll post some code I'm sure will help someone. I've put italic in the Blah blah parts, leaving the "important" parts in normal text.
Short question: Are the SignedInfo node bytes (from [60] to [62]) the one that really get signed (that means "sha1ed", then RSAed, then B64es and the incrusted into the SignatureValue node?"
Long Question:
The problem is simply do a standar XMLDSIG on a XML file created by myself (that means it will always look similar). The software should be able to run on android devices and windows phone 6.1 devices (especifically the CN50 intermec portable computer). The last part is relevant because that means i cant use the simplistic way of XML signing that the .NET framework provides (I'm looking at you, System.Security.Cryptography.Xml library). So, unable to use the mentioned library i tried to sign the document "by hand".
The most obvious proof and noob oriented info i could find is this page: http://www.di-mgt.com.au/xmldsig2.html where they do precisely that: a completely step by step guide on how to sign a XML document with and enveloped signature.
The canonicalization part doesn't worry me since, like I say, the document will be created by be, and such i will take precautions to not introduce elements that could potentially ruin the hashing calculation part. That said, i tried to do the canonicalizacion in Java usinf the XOM library, however the results obtained where.. strange.
Before I go on, a data filled, unsigned document was correctly signed using the XMLSEC library (available here http://www.aleksey.com/xmlsec/) using the following command:
xmlsec --sign --privkey-pem PEMFILE.pem,PEMFILE.pem --node-xpath "(//*[local-name()='Signature' and namespace-uri()='http://www.w3.org/2000/09/xmldsig#'])[last()]" --id-attr:Id "http://www.w3.org/2000/09/xmldsig#:Signature" --id-attr:Id "http://www.w3.org/2000/09/xmldsig#:SignatureValue" UnsignedDocument.xml > SignedDocument.xml
Also, i did the signing using the .NET framework on my computer using the standar .NET 4.0 framework with the following (Note1: its not a real production code, but as an example it could help someone. Note2: Here i used the PFX certificate installed on my computer)
X509Store Certificados = new X509Store(StoreName.My, StoreLocation.CurrentUser);
Certificados.Open(OpenFlags.ReadOnly);
foreach (X509Certificate2 Resultado in Certificados.Certificates)
if (Resultado.Thumbprint == "16182C4CB0440D86DBD567B6A9C1963C02E41B9A")
return Resultado;
throw new Exception("No hay un certificado instalado para el RFC que se indicó.");
And the signing is done with the following
public static void SignXmlFile2(string FileName, string SignedFileName, X509Certificate2 Key)
{
// Create a new XML document.
XmlDocument doc = new XmlDocument();
// Format the document to ignore white spaces.
doc.PreserveWhitespace = true;
// Load the passed XML file using it's name.
doc.Load(new XmlTextReader(FileName));
XmlNode root = doc.DocumentElement;
// Create a SignedXml object.
SignedXml signedXml = new SignedXml(doc);
// Obtenemos el objeto de llave privada del certificado
RSACryptoServiceProvider Llave = Key.PrivateKey as RSACryptoServiceProvider;
Llave.ExportParameters(false);
// Add the key to the SignedXml document.
signedXml.SigningKey = Llave;
// Specify a canonicalization method.
signedXml.SignedInfo.CanonicalizationMethod = SignedXml.XmlDsigC14NWithCommentsTransformUrl;
// Set the InclusiveNamespacesPrefixList property.
XmlDsigC14NWithCommentsTransform canMethod = (XmlDsigC14NWithCommentsTransform)signedXml.SignedInfo.CanonicalizationMethodObject;
// Create a reference to be signed.
Reference reference = new Reference();
reference.Uri = "";
// Add an enveloped transformation to the reference.
XmlDsigEnvelopedSignatureTransform env = new XmlDsigEnvelopedSignatureTransform();
reference.AddTransform(env);
// Add the reference to the SignedXml object.
signedXml.AddReference(reference);
keyInfo.AddClause(new RSAKeyValue((RSA)Llave));
signedXml.KeyInfo = keyInfo;*/
/* Creamos el nodo <KeyInfo> con el subnodo <X509Data>, poniendo dentro de éste el
certificado, su número de serie y la entidad emisora del mismo (primero estos dos últimos
como subnodo <X509IssuerSerial>), y agregando todo al objeto firmante. */
KeyInfoX509Data NodoX509Data = new KeyInfoX509Data();
NodoX509Data.AddCertificate(Key);
signedXml.KeyInfo = new KeyInfo();
signedXml.KeyInfo.AddClause(NodoX509Data);
// Compute the signature.
signedXml.GetHashCode();
signedXml.ComputeSignature();
// Get the XML representation of the signature and save
// it to an XmlElement object.
XmlElement xmlDigitalSignature = signedXml.GetXml();
// Append the element to the XML document.
doc.DocumentElement.AppendChild(doc.ImportNode(xmlDigitalSignature, true));
// Save the signed XML document to a file specified
// using the passed string.
XmlTextWriter xmltw = new XmlTextWriter(SignedFileName, new UTF8Encoding(false));
doc.WriteTo(xmltw);
xmltw.Close();
}
With the above i can get two equivalent documents and both signed correctly.
So, I have a unsigned and a correctly signed document (obtained from two sources - C# and XMLSEC), from there i know the correct SHA1 Hash value of the document (called DigestValue) and the correct signature (called SignatureValue). I have something to compare to.
Like i said, i tried to do the canonicalization in Java, but could get the hash correctly so, instead of banging my head to the head hoping to find some sort of illumination as to how i'm messing this up, i simply decide to assume the input document will be canonnicalized. And if someone says "thats impossible because the line breaks will change with canonicalization" i simply would reply my input file wont have any line breaks. Once again, the document will be created by me.
Following that approach, i can get the correct digest value of the unsigned document with the following code:
JAVA:
/**
* Generates SHA-1 digest of the provided data.
*
* #param data the data to digest
* #return SHA-1 digest of the provided data.
*/
public static byte[] sha1Digest(byte[] data) {
MessageDigest mdSha1 = null;
try {
mdSha1 = MessageDigest.getInstance("SHA-1");
} catch (NoSuchAlgorithmException e1) {
Log.e(LOG_TAG, "Error initializing SHA1 message digest");
/*} catch (NoSuchProviderException e) {
// TODO Auto-generated catch block
e.printStackTrace();*/
}
mdSha1.update(data);
byte[] sha1hash = mdSha1.digest();
return sha1hash;
}
That means the input document is canonically equivalent to the one being signed with the methods stated above.
The Sha1 Bytes are
[55, -59, -1, 71, -62, 26, 57, 126, 76, 7, 120, 53, -38, -51, 8, 38,
127, -29, 5, 25]
And in B64
N8X/R8IaOX5MB3g12s0IJn/jBRk=
HERE COMES THE TROUBLING PART
According to the theory (from differents sources) i need to insert the digestValue inside the node. My approach was to read the bytes of an empty, canonicalized, node like this
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#"><SignedInfo><CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments"></CanonicalizationMethod><SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"></SignatureMethod><Reference URI=""><Transforms><Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"></Transform></Transforms><DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></DigestMethod><DigestValue></DigestValue></Reference></SignedInfo><SignatureValue></SignatureValue><KeyInfo><X509Data><X509Certificate></X509Certificate></X509Data></KeyInfo></Signature>
The above is translated into bytes:
[60, 83, 105, 103, 110, 97, 116, 117, 114, 101, 32, 120, 109, 108,
110, 115, 61, 34, 104, 116, 116, 112, 58, 47, 47, 119, 119, 119, 46,
119, 51, 46, 111, 114, 103, 47, 50, 48, 48, 48, 47, 48, 57, 47, 120,
109, 108, 100, 115, 105, 103, 35, 34, 62, 60, 83, 105, 103, 110, 101,
100, 73, 110, 102, 111, 62, 60, 67, 97, 110, 111, 110, 105, 99, 97,
108, 105, 122, 97, 116, 105, 111, 110, 77, 101, 116, 104, 111, 100,
32, 65, 108, 103, 111, 114, 105, 116, 104, 109, 61, 34, 104, 116, 116,
112, 58, 47, 47, 119, 119, 119, 46, 119, 51, 46, 111, 114, 103, 47,
84, 82, 47, 50, 48, 48, 49, 47, 82, 69, 67, 45, 120, 109, 108, 45, 99,
49, 52, 110, 45, 50, 48, 48, 49, 48, 51, 49, 53, 35, 87, 105, 116,
104, 67, 111, 109, 109, 101, 110, 116, 115, 34, 62, 60, 47, 67, 97,
110, 111, 110, 105, 99, 97, 108, 105, 122, 97, 116, 105, 111, 110, 77,
101, 116, 104, 111, 100, 62, 60, 83, 105, 103, 110, 97, 116, 117, 114,
101, 77, 101, 116, 104, 111, 100, 32, 65, 108, 103, 111, 114, 105,
116, 104, 109, 61, 34, 104, 116, 116, 112, 58, 47, 47, 119, 119, 119,
46, 119, 51, 46, 111, 114, 103, 47, 50, 48, 48, 48, 47, 48, 57, 47,
120, 109, 108, 100, 115, 105, 103, 35, 114, 115, 97, 45, 115, 104, 97,
49, 34, 62, 60, 47, 83, 105, 103, 110, 97, 116, 117, 114, 101, 77,
101, 116, 104, 111, 100, 62, 60, 82, 101, 102, 101, 114, 101, 110, 99,
101, 32, 85, 82, 73, 61, 34, 34, 62, 60, 84, 114, 97, 110, 115, 102,
111, 114, 109, 115, 62, 60, 84, 114, 97, 110, 115, 102, 111, 114, 109,
32, 65, 108, 103, 111, 114, 105, 116, 104, 109, 61, 34, 104, 116, 116,
112, 58, 47, 47, 119, 119, 119, 46, 119, 51, 46, 111, 114, 103, 47,
50, 48, 48, 48, 47, 48, 57, 47, 120, 109, 108, 100, 115, 105, 103, 35,
101, 110, 118, 101, 108, 111, 112, 101, 100, 45, 115, 105, 103, 110,
97, 116, 117, 114, 101, 34, 62, 60, 47, 84, 114, 97, 110, 115, 102,
111, 114, 109, 62, 60, 47, 84, 114, 97, 110, 115, 102, 111, 114, 109,
115, 62, 60, 68, 105, 103, 101, 115, 116, 77, 101, 116, 104, 111, 100,
32, 65, 108, 103, 111, 114, 105, 116, 104, 109, 61, 34, 104, 116, 116,
112, 58, 47, 47, 119, 119, 119, 46, 119, 51, 46, 111, 114, 103, 47,
50, 48, 48, 48, 47, 48, 57, 47, 120, 109, 108, 100, 115, 105, 103, 35,
115, 104, 97, 49, 34, 62, 60, 47, 68, 105, 103, 101, 115, 116, 77,
101, 116, 104, 111, 100, 62, 60, 68, 105, 103, 101, 115, 116, 86, 97,
108, 117, 101, 62, 60, 47, 68, 105, 103, 101, 115, 116, 86, 97, 108,
117, 101, 62, 60, 47, 82, 101, 102, 101, 114, 101, 110, 99, 101, 62,
60, 47, 83, 105, 103, 110, 101, 100, 73, 110, 102, 111, 62, 60, 83,
105, 103, 110, 97, 116, 117, 114, 101, 86, 97, 108, 117, 101, 62, 60,
47, 83, 105, 103, 110, 97, 116, 117, 114, 101, 86, 97, 108, 117, 101,
62, 60, 75, 101, 121, 73, 110, 102, 111, 62, 60, 88, 53, 48, 57, 68,
97, 116, 97, 62, 60, 88, 53, 48, 57, 67, 101, 114, 116, 105, 102, 105,
99, 97, 116, 101, 62, 60, 47, 88, 53, 48, 57, 67, 101, 114, 116, 105,
102, 105, 99, 97, 116, 101, 62, 60, 47, 88, 53, 48, 57, 68, 97, 116,
97, 62, 60, 47, 75, 101, 121, 73, 110, 102, 111, 62, 60, 47, 83, 105,
103, 110, 97, 116, 117, 114, 101, 62]
From that array i must obtain the bytes corresponding to the SignedInfo node. Those are the following bytes (I've bold barked the Middle Bytes of the SignedInfo Node):
[60, 83, 105, 103, 110, 101, 100, 73, 110, 102, 111, 62, 60, 67, 97,
110, 111, 110, 105, 99, 97, 108, 105, 122, 97, 116, 105, 111, 110, 77,
101, 116, 104, 111, 100, 32, 65, 108, 103, 111, 114, 105, 116, 104,
109, 61, 34, 104, 116, 116, 112, 58, 47, 47, 119, 119, 119, 46, 119,
51, 46, 111, 114, 103, 47, 84, 82, 47, 50, 48, 48, 49, 47, 82, 69, 67,
45, 120, 109, 108, 45, 99, 49, 52, 110, 45, 50, 48, 48, 49, 48, 51,
49, 53, 35, 87, 105, 116, 104, 67, 111, 109, 109, 101, 110, 116, 115,
34, 62, 60, 47, 67, 97, 110, 111, 110, 105, 99, 97, 108, 105, 122, 97,
116, 105, 111, 110, 77, 101, 116, 104, 111, 100, 62, 60, 83, 105, 103,
110, 97, 116, 117, 114, 101, 77, 101, 116, 104, 111, 100, 32, 65, 108,
103, 111, 114, 105, 116, 104, 109, 61, 34, 104, 116, 116, 112, 58, 47,
47, 119, 119, 119, 46, 119, 51, 46, 111, 114, 103, 47, 50, 48, 48, 48,
47, 48, 57, 47, 120, 109, 108, 100, 115, 105, 103, 35, 114, 115, 97,
45, 115, 104, 97, 49, 34, 62, 60, 47, 83, 105, 103, 110, 97, 116, 117,
114, 101, 77, 101, 116, 104, 111, 100, 62, 60, 82, 101, 102, 101, 114,
101, 110, 99, 101, 32, 85, 82, 73, 61, 34, 34, 62, 60, 84, 114, 97,
110, 115, 102, 111, 114, 109, 115, 62, 60, 84, 114, 97, 110, 115, 102,
111, 114, 109, 32, 65, 108, 103, 111, 114, 105, 116, 104, 109, 61, 34,
104, 116, 116, 112, 58, 47, 47, 119, 119, 119, 46, 119, 51, 46, 111,
114, 103, 47, 50, 48, 48, 48, 47, 48, 57, 47, 120, 109, 108, 100, 115,
105, 103, 35, 101, 110, 118, 101, 108, 111, 112, 101, 100, 45, 115,
105, 103, 110, 97, 116, 117, 114, 101, 34, 62, 60, 47, 84, 114, 97,
110, 115, 102, 111, 114, 109, 62, 60, 47, 84, 114, 97, 110, 115, 102,
111, 114, 109, 115, 62, 60, 68, 105, 103, 101, 115, 116, 77, 101, 116,
104, 111, 100, 32, 65, 108, 103, 111, 114, 105, 116, 104, 109, 61, 34,
104, 116, 116, 112, 58, 47, 47, 119, 119, 119, 46, 119, 51, 46, 111,
114, 103, 47, 50, 48, 48, 48, 47, 48, 57, 47, 120, 109, 108, 100, 115,
105, 103, 35, 115, 104, 97, 49, 34, 62, 60, 47, 68, 105, 103, 101,
115, 116, 77, 101, 116, 104, 111, 100, 62, 60, 68, 105, 103, 101, 115,
116, 86, 97, 108, 117, 101, 62, 60, 47, 68, 105, 103, 101, 115,
116, 86, 97, 108, 117, 101, 62, 60, 47, 82, 101, 102, 101, 114, 101,
110, 99, 101, 62, 60, 47, 83, 105, 103, 110, 101, 100, 73, 110, 102,
111, 62]
To that byte array i should insert the Bytes corresponding to the Sha1 of the document encoded in B64.
The Sha1 Bytes are
[55, -59, -1, 71, -62, 26, 57, 126, 76, 7, 120, 53, -38, -51, 8, 38,
127, -29, 5, 25]
And in B64
N8X/R8IaOX5MB3g12s0IJn/jBRk=
And that back into bytes is:
[78, 56, 88, 47, 82, 56, 73, 97, 79, 88, 53, 77, 66, 51, 103, 49, 50,
115, 48, 73, 74, 110, 47, 106, 66, 82, 107, 61]
The SignedInfo array with the hash attached then is:
[60, 83, 105, 103, 110, 101, 100, 73, 110, 102, 111, 62, 60, 67, 97,
110, 111, 110, 105, 99, 97, 108, 105, 122, 97, 116, 105, 111, 110, 77,
101, 116, 104, 111, 100, 32, 65, 108, 103, 111, 114, 105, 116, 104,
109, 61, 34, 104, 116, 116, 112, 58, 47, 47, 119, 119, 119, 46, 119,
51, 46, 111, 114, 103, 47, 84, 82, 47, 50, 48, 48, 49, 47, 82, 69, 67,
45, 120, 109, 108, 45, 99, 49, 52, 110, 45, 50, 48, 48, 49, 48, 51,
49, 53, 35, 87, 105, 116, 104, 67, 111, 109, 109, 101, 110, 116, 115,
34, 62, 60, 47, 67, 97, 110, 111, 110, 105, 99, 97, 108, 105, 122, 97,
116, 105, 111, 110, 77, 101, 116, 104, 111, 100, 62, 60, 83, 105, 103,
110, 97, 116, 117, 114, 101, 77, 101, 116, 104, 111, 100, 32, 65, 108,
103, 111, 114, 105, 116, 104, 109, 61, 34, 104, 116, 116, 112, 58, 47,
47, 119, 119, 119, 46, 119, 51, 46, 111, 114, 103, 47, 50, 48, 48, 48,
47, 48, 57, 47, 120, 109, 108, 100, 115, 105, 103, 35, 114, 115, 97,
45, 115, 104, 97, 49, 34, 62, 60, 47, 83, 105, 103, 110, 97, 116, 117,
114, 101, 77, 101, 116, 104, 111, 100, 62, 60, 82, 101, 102, 101, 114,
101, 110, 99, 101, 32, 85, 82, 73, 61, 34, 34, 62, 60, 84, 114, 97,
110, 115, 102, 111, 114, 109, 115, 62, 60, 84, 114, 97, 110, 115, 102,
111, 114, 109, 32, 65, 108, 103, 111, 114, 105, 116, 104, 109, 61, 34,
104, 116, 116, 112, 58, 47, 47, 119, 119, 119, 46, 119, 51, 46, 111,
114, 103, 47, 50, 48, 48, 48, 47, 48, 57, 47, 120, 109, 108, 100, 115,
105, 103, 35, 101, 110, 118, 101, 108, 111, 112, 101, 100, 45, 115,
105, 103, 110, 97, 116, 117, 114, 101, 34, 62, 60, 47, 84, 114, 97,
110, 115, 102, 111, 114, 109, 62, 60, 47, 84, 114, 97, 110, 115, 102,
111, 114, 109, 115, 62, 60, 68, 105, 103, 101, 115, 116, 77, 101, 116,
104, 111, 100, 32, 65, 108, 103, 111, 114, 105, 116, 104, 109, 61, 34,
104, 116, 116, 112, 58, 47, 47, 119, 119, 119, 46, 119, 51, 46, 111,
114, 103, 47, 50, 48, 48, 48, 47, 48, 57, 47, 120, 109, 108, 100, 115,
105, 103, 35, 115, 104, 97, 49, 34, 62, 60, 47, 68, 105, 103, 101,
115, 116, 77, 101, 116, 104, 111, 100, 62, 60, 68, 105, 103, 101, 115,
116, 86, 97, 108, 117, 101, 62, 78, 56, 88, 47, 82, 56, 73, 97, 79,
88, 53, 77, 66, 51, 103, 49, 50, 115, 48, 73, 74, 110, 47, 106, 66,
82, 107, 61, 60, 47, 68, 105, 103, 101, 115, 116, 86, 97, 108, 117,
101, 62, 60, 47, 82, 101, 102, 101, 114, 101, 110, 99, 101, 62, 60,
47, 83, 105, 103, 110, 101, 100, 73, 110, 102, 111, 62]
The above array, converted into string is:
<SignedInfo><CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments"></CanonicalizationMethod><SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"></SignatureMethod><Reference URI=""><Transforms><Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"></Transform></Transforms><DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></DigestMethod><DigestValue>N8X/R8IaOX5MB3g12s0IJn/jBRk=</DigestValue></Reference></SignedInfo>
Now, those are the bytes that (i think) should be RSA encrypted. I've applied several methods of signing:
Java using Cipher class (Privatekey read through PEM fime)
Java using Signature class (Privatekey read through PEM fime)
C# using BouncyCastle libraries (in windows mobile emulator) (Key read through CertificateStore and transformed into BC format)
C# using RSAFormatter (Key obtained through windows certificate store)
And in every single one of them i got the same signature result for the bytes inputted:
[2, -125, 23, -84, -28, -120, -45, -72, -73, -105, -71, -25, -100,
-81, -77, 119, 98, 0, 28, -124, -92, 116, -108, -9, 22, -90, -103, -119, 52, 105, 53, 24, -59, -87, 25, -38, -31, -15, 39, 104, -4, 0, 62, -117, 103, -79, 112, 65, -43, -49, -26, -126, -108, 120, -4, -44,
73, -33, 87, 39, 84, 7, 107, -81, 91, 61, -86, 100, 103, -112, -123,
-118, 98, 85, -14, -88, -92, -45, -79, 3, -28, -18, 64, 2, -125, 53, -70, 100, -10, 86, -52, 17, -22, 110, -126, -100, -115, 45, -18, 99, -79, -92, -8, -120, -104, -63, 43, 70, -41, 98, 121, -68, -8, 60, -93, -95, -83, 83, -86, 75, -128, 120, -6, -11, 24, -124, 70, -128]
AoMXrOSI07i3l7nnnK+zd2IAHISkdJT3FqaZiTRpNRjFqRna4fEnaPwAPotn
sXBB1c/mgpR4/NRJ31cnVAdrr1s9qmRnkIWKYlXyqKTTsQPk7kACgzW6ZPZW
zBHqboKcjS3uY7Gk+IiYwStG12J5vPg8o6GtU6pLgHj69RiERoA=
Since i get the same result for the same input data, the erorr is not in the signing procedure but in the data i'm inputting. And that's where i can't find a solution. By the way, the signature is valid if I validate it as a string with the corresponding public key or certificate... the error arises when i attach the signature node to the original document and validate it as an XMLDSIG.
The signature takes basically three inputs
Bytes to be signed
Private Key
Algorith
The key and the algorith are ok (i think), the problem then needs to be in the bytes being signed, however i cant find what I'm doing wrong. If someone could give me a hand, i will be very grateful.
I'm including some code below to show the methods im using to get the same signature on the differents languages and devices.
This is JAVA
public static byte[] firmarSignedInfoconHash(byte[] bSignedInfo, PrivateKey privateKey, X509Certificate Certificado) throws Throwable
{
try
{
String hexCan = bytesToHex(bSignedInfo);
String stringAFirmar = new String(bSignedInfo, "ISO-8859-1");
//ONE WAY OF SIGNING
byte[] signedInfoSha1Digest = sha1Digest(bSignedInfo);
//byte[] bytesCS = new byte[]{55,-59,-1,71,-62,26,57,126,76,7,120,53,-38,-51,8,38,127,-29,5,25};
String vSignedInfoSha1DigestString64 = Base64.encodeToString(signedInfoSha1Digest, Base64.DEFAULT);
byte[] signedInfoDerSha1Digest = mergeArrays(DER_SHA1_DIGEST_IDENTIFIER, signedInfoSha1Digest);
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding","BC");
cipher.init(Cipher.ENCRYPT_MODE, privateKey);
byte[] signatureBytes = cipher.doFinal(signedInfoDerSha1Digest);
String base64RsaSignature1 = base64encode(signatureBytes, true);
//String vFirma = bytesToHex(signatureBytes);
//ANOTHER WAY OF SIGNING
Signature instance2 = Signature.getInstance("SHA1withRSA");
instance2.initSign(privateKey);
instance2.update(bSignedInfo);
byte[] bFirma3 = instance2.sign();
String base64RsaSignature2 = base64encode(bFirma3, true);
Log.i("Log","nada");
//VALIDATE THE RESULT
Signature instanceValida = Signature.getInstance("SHA1withRSA");
instanceValida.initVerify(Certificado);
instanceValida.update(bSignedInfo);
if(instanceValida.verify(bFirma3)==true)
Log.i("Validacion","La firma es valida");
else
Log.i("Validacion","La firma NO ES valida");
return bFirma3;
}
catch (Throwable e) {
Log.e(LOG_TAG, "Error generating signature for XML", e);
throw e;
}
}
This is C#
public static void SignXmlFile3(string Cadena, X509Certificate2 Key)
{
/*opcion 1
RSACryptoServiceProvider RSA = Key.PrivateKey as RSACryptoServiceProvider;
RSAPKCS1SignatureFormatter RSAFormatter = new RSAPKCS1SignatureFormatter(RSA);
* */
//Opcion 2
RSAPKCS1SignatureFormatter RSAFormatter = new RSAPKCS1SignatureFormatter();
RSAFormatter.SetKey(Key.PrivateKey as RSACryptoServiceProvider);
RSAFormatter.SetHashAlgorithm("SHA1");
SHA1Managed SHhash = new SHA1Managed();
var bytes3 = Encoding.UTF8.GetBytes(Cadena);
var bytes = Convert.FromBase64String(Cadena);
byte[] SignedHashValue = RSAFormatter.CreateSignature(SHhash.ComputeHash(bytes));
string signature = System.Convert.ToBase64String(SignedHashValue);
}
This is c# using bouncyCastle on WindowsPhone
public String Sign(String data, String privateModulusHexString, String privateExponentHexString, X509Certificate2 vX509Certificate2)
{
//var test = DotNetUtilities.FromX509Certificate(vX509Certificate2);
/* Make the key */
RsaKeyParameters key = MakeKey(privateModulusHexString, privateExponentHexString, true);
/* Init alg */
ISigner sig = SignerUtilities.GetSigner("SHA1withRSA");
/* Populate key */
sig.Init(true, key);
/* Get the bytes to be signed from the string */
var bytes = Encoding.UTF8.GetBytes(data);
/* Calc the signature */
sig.BlockUpdate(bytes, 0, bytes.Length);
byte[] signature = sig.GenerateSignature();
/* Base 64 encode the sig so its 8-bit clean */
var signedString = Convert.ToBase64String(signature);
return signedString;
}
The answer couldn't be simplier. The problem was simply the SignedInfo i was passing for hashing. The correct signedInfo in my case was like this:
<ds:SignedInfo xmlns="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2"
xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2"
xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2"
xmlns:ccts="urn:un:unece:uncefact:documentation:2"
xmlns:ds="http://www.w3.org/2000/09/xmldsig#"
xmlns:ext="urn:oasis:names:specification:ubl:schema:xsd:CommonExtensionComponents-2"
xmlns:qdt="urn:oasis:names:specification:ubl:schema:xsd:QualifiedDatatypes-2"
xmlns:sac="urn:sunat:names:specification:ubl:peru:schema:xsd:SunatAggregateComponents-1"
xmlns:udt="urn:un:unece:uncefact:data:specification:UnqualifiedDataTypesSchemaModule:2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">jRNx5uoRrC2UcrSNyJjdZRTB8/o=
The namespaces included are all propagated from the parentmost node
So thats all...
PD. I tried canonicalizacion in JAVA using the XOM library, however among other things this library simply removed most of the namespaces from the starting node.