Search code examples
phphashrsasha1private-key

How to get the SignatureValue with php?


It is said that to obtain the SignatureValue the following must be done:

    1. Hash using SHA-1
    1. Encrypt with RSA private key
    1. Base64 encode the result

Using this javascript code jsfiddle, of the following structure:

<ds:SignedInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:etsi="http://uri.etsi.org/01903/v1.3.2#" Id="Signature-SignedInfo284666">
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"></ds:CanonicalizationMethod>
<ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"></ds:SignatureMethod>
<ds:Reference Id="SignedPropertiesID687634" Type="http://uri.etsi.org/01903#SignedProperties" URI="#Signature680220-SignedProperties883886">
<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></ds:DigestMethod>
<ds:DigestValue>E+ZfetOb53KRrXMOx27aZUg7B5o=</ds:DigestValue>
</ds:Reference>
<ds:Reference URI="#Certificate280377">
<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></ds:DigestMethod>
<ds:DigestValue>X7MPKnMutOGD1ge+DhS6DBpsAk4=</ds:DigestValue>
</ds:Reference>
<ds:Reference Id="Reference-ID-863720" URI="#comprobante">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"></ds:Transform>
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></ds:DigestMethod>
<ds:DigestValue>wSfLV4gKPewaYvBC35hJVYA/oVs=</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>

The following result is obtained:

NW0PePGqFoDXSKTG5IwUuK89KIPj5aJuwykuml182fnedUKYg/8BfVbKbtPAJmHWv3Wb765Qf0A3
kyk6TG5r0RmKdt6KWjoOHrq1050QJtVqDzz34IpipfDX4D/qk4AE/zrr57BOMbbxxgbqjm3VvcbG
4tjSI2eiyxUu47KhlIfB6a5SKoWgfZrVmKQLiw+QB51S225EhxPVI6fimWtRcEaJlh4NormxGjcg
0Crf6MPjsAgk7pVW5RrliFTQdrmJHfwZl8tKpTtFiADeu2YsU3CG9okwU277ccHtCWlGs5ZKvUSm
mlDk5pdlFIaaw6PpAISk48PN926bH0EifTEVxQ==

Now I try to get the same result with PHP, as follows:

$privateKey = '-----BEGIN PRIVATE KEY-----
MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQCC2nH/FRU+za+w nKYrkToXxvYm7O2dxQK8Dtwen3VjnRNVFTgOOWI6bcHKp1NhGXbUehzdqG6A/B/f hg37ipWofhIezfGWaq8gxMSTsBAr8RwkSDXMgO8mQHCWJ3rbtGNbdYTFncWxGTiq eaNBnZpEJH6bPqzLnuhOqha5au7FfP0tUX8kFVNKq93K/fiyuWBeFYxHcqOR6xME +Gl/b3aIFaV0gEhYwzKfoQBxZjaBWxvA1H9qbjP1rkhhSKcqU8Ko8ZdzdnlI8T09 wO/v06R3AtB9j6Y4+hCeMbQZq6D8rOJ3Nd9VOO2tUXlHGksZ2BMIWPsgXOYG70dk b+k6Sgy5AgMBAAECggEAKImiDUMrzMQN7Knq9M5N7/XMZiy6REk3WqlD2hzOUijk R1SGhCmU28MK6UxDEW7BGHwoGydF7KGvAiFWjZnWWVeNJ4vnjxDH5l/vAk3mBKby b+8K86rx66jE+E+MySmuKjRTCKGjEAVfP7jlMbuwgfHIYzHceExnbY9V8OVGyVlI 1etLOoIw24L+LH11BhNoJWSHOb0DFIhDoPC5fevJQblLfPmPbKVhE9GZ1Vg4ezGc +vuYgFABNDYIh8ifK678oQF03ayLCDfmdpqYKcg2p+wcbFWpNgzGp/NByvzKb0Ki nHkLf6liRc+2ZeDZOsso4k3LprTdeq0ow19dYnYcHQKBgQCvCwoBDzNDaf7kMJg8 PGL+NRDWVR+eWL1TtN9dLxCWuFr6gijTle0UUGg5Dm8dn7QqwaIJAbDP4NYGVTaW IptDtUuDjbj6mIiC/5jkfHYyIXppGQJTe0AME20o1N9Da/MbY6u5Cl97rMIMW2fI yLaTmgbnYW4sS5JcdkNa3h1FgwKBgQC/X148u1QuZSW/a1H1dfDtyCxIUh/RUWVt MCRqe3OzuVqY6ZPpPXyCiSOMuvZrIx3hMLfIoieaOL1Q3XDPmS0C8U1pvNgagE6E eMZadCeWkhJKkCPkh5vsgA0cpapqtAeqNoisuGkGSAC9W8Z+L4kfVQS4vZOsfFKZ F2deDqlMEwKBgQCF+lsT6ICCTvULz64WHNpgXFmg09K5ro5rLXvxpP57fmwUZd+9 43ltHQZI9aVS9VQ/janqXuLomdz3R+3aCG7y6ib8cFNva6TBL8XkzObjBADfxIal QycIly3sHNMulcej5SwhG7FtxhNYxfWwFwC4BSLXoxliyg0ivFpdiLi65QKBgQCD ZPJqFmCdHjuFqyTxuJG8YRTubtyDtjRCfKx0I+D0BA6NMMqqeNn1Mj2jUXcBZnIM fIujCJrSS6TIUdIz50K9Y3o4YD2sLG48jEP8NQY9XnuKkF7keKt4/Q6DncddTdB5 cMn0dQU/F87SNKIbX33xckk0oo0y/4Uisav6K2zX2wKBgQCYEAEXMyfrKst0q8Gv lqUtCIV/9Cv/GiANeWdlqubzxvte7aIt5wwaEdJe+6cCl3teXzSHiKZ/zxHjRxvg axnexRIYGrsw7CldR3odxX8TDQExkXmd1NSOSDMX9mFyLgK0iTdx/5x/i8wYRlba 7tAM0w0wuONKwLXt9cQ7bjwoJg==
-----END PRIVATE KEY-----';
$SignedInfo = '<ds:SignedInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:etsi="http://uri.etsi.org/01903/v1.3.2#" Id="Signature-SignedInfo284666">
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"></ds:CanonicalizationMethod>
<ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"></ds:SignatureMethod>
<ds:Reference Id="SignedPropertiesID687634" Type="http://uri.etsi.org/01903#SignedProperties" URI="#Signature680220-SignedProperties883886">
<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></ds:DigestMethod>
<ds:DigestValue>E+ZfetOb53KRrXMOx27aZUg7B5o=</ds:DigestValue>
</ds:Reference>
<ds:Reference URI="#Certificate280377">
<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></ds:DigestMethod>
<ds:DigestValue>X7MPKnMutOGD1ge+DhS6DBpsAk4=</ds:DigestValue>
</ds:Reference>
<ds:Reference Id="Reference-ID-863720" URI="#comprobante">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"></ds:Transform>
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></ds:DigestMethod>
<ds:DigestValue>wSfLV4gKPewaYvBC35hJVYA/oVs=</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>';

$sha1 = sha1($SignedInfo);
openssl_sign($sha1, $SignatureValue, $privateKey, 'sha1WithRSAEncryption');
$resultSignature = base64_encode($SignatureValue);
echo $resultSignature;

But I get the following output:

Dfx4ck6bix1jL4f97hNjTikzMVEhsoJPMjd1SOSH8/AKVhAIhzejxQuHE8QT5DJqAY5hg18SLqam
p8OekAgu2CXzKPY5pVYVICP5hARGbxELAwsmpiVRSGSwnBxBw1hkrQHF63rfGCnHDRO9p/6t5du1
PIqZ+Ng9ibvJYPkRcEyRE/tRV1NaiaHUPX6vuNg2WJFj11ncyOWFKSMlJD4MT08zHovTPjiCBs87
+MuZsfL7fiEuynfurEByk7EcSWOhgVl/2A4u1InOPZjd7+XdDCo2uaftrrXW6hUzXfEkKOBxdIRp
SEKaaQ2xvvWaiISX1S0PufE6ODJP5UcKNKrJ8A==

What am I doing wrong? Any change I need to add in PHP to get the same result:

NW0PePGqFoDXSKTG5IwUuK89KIPj5aJuwykuml182fnedUKYg/8BfVbKbtPAJmHWv3Wb765Qf0A3
kyk6TG5r0RmKdt6KWjoOHrq1050QJtVqDzz34IpipfDX4D/qk4AE/zrr57BOMbbxxgbqjm3VvcbG
4tjSI2eiyxUu47KhlIfB6a5SKoWgfZrVmKQLiw+QB51S225EhxPVI6fimWtRcEaJlh4NormxGjcg
0Crf6MPjsAgk7pVW5RrliFTQdrmJHfwZl8tKpTtFiADeu2YsU3CG9okwU277ccHtCWlGs5ZKvUSm
mlDk5pdlFIaaw6PpAISk48PN926bH0EifTEVxQ==

Solution

  • openssl_sign() hashes implicitly, i.e. the unhashed data must be passed:

    ...
    openssl_sign($SignedInfo, $SignatureValue, $privateKey, 'sha1WithRSAEncryption');
    ...
    

    With this change, the PHP code returns the desired signature NW0P...EVxQ==.