Skip to content

Commit c6f7aaa

Browse files
committed
HMAC verification
1 parent 3b0fe81 commit c6f7aaa

File tree

10 files changed

+252
-3
lines changed

10 files changed

+252
-3
lines changed

.gitignore

+2-1
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,5 @@ p.txt
55
.DS_Store
66
*.*~
77
*.swp
8-
npm-debug.log
8+
npm-debug.log
9+
/test/validators/XmlCryptoJava/target/

lib/signed-xml.js

+11-1
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,15 @@ function RSASHA512() {
163163
}
164164
}
165165

166+
function HMACSHA1() {
167+
this.verifySignature = function(str, key, signatureValue) {
168+
var verifier = crypto.createHmac("SHA1", key);
169+
verifier.update(str);
170+
var res = verifier.digest('base64');
171+
return res === signatureValue;
172+
}
173+
}
174+
166175
/**
167176
* Xml signature implementation
168177
*
@@ -202,7 +211,8 @@ SignedXml.HashAlgorithms = {
202211
SignedXml.SignatureAlgorithms = {
203212
'http://www.w3.org/2000/09/xmldsig#rsa-sha1': RSASHA1,
204213
'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256': RSASHA256,
205-
'http://www.w3.org/2001/04/xmldsig-more#rsa-sha512': RSASHA512
214+
'http://www.w3.org/2001/04/xmldsig-more#rsa-sha512': RSASHA512,
215+
'http://www.w3.org/2000/09/xmldsig#hmac-sha1': HMACSHA1
206216
}
207217

208218
SignedXml.prototype.checkSignature = function(xml) {

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,6 @@
3434
}
3535
],
3636
"scripts": {
37-
"test": "nodeunit ./test/canonicalization-unit-tests.js ./test/c14nWithComments-unit-tests.js ./test/signature-unit-tests.js ./test/saml-response-test.js ./test/signature-integration-tests.js ./test/document-test.js"
37+
"test": "nodeunit ./test/canonicalization-unit-tests.js ./test/c14nWithComments-unit-tests.js ./test/signature-unit-tests.js ./test/saml-response-test.js ./test/signature-integration-tests.js ./test/document-test.js ./test/hmac-tests.js"
3838
}
3939
}

test/hmac-tests.js

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
var crypto = require('../index');
2+
var xmldom = require('xmldom');
3+
var fs = require('fs');
4+
5+
exports['test validating HMAC signature'] = function (test) {
6+
var xml = fs.readFileSync('./test/static/hmac_signature.xml', 'utf-8');
7+
var doc = new xmldom.DOMParser().parseFromString(xml);
8+
var signature = crypto.xpath(doc, "/*/*[local-name(.)='Signature' and namespace-uri(.)='http://www.w3.org/2000/09/xmldsig#']")[0];
9+
var sig = new crypto.SignedXml();
10+
sig.keyInfoProvider = new crypto.FileKeyInfo("./test/static/hmac.key");
11+
sig.loadSignature(signature);
12+
var result = sig.checkSignature(xml);
13+
test.equal(result, true);
14+
test.done();
15+
};
16+
17+
exports['test HMAC signature with incorrect key'] = function (test) {
18+
var xml = fs.readFileSync('./test/static/hmac_signature.xml', 'utf-8');
19+
var doc = new xmldom.DOMParser().parseFromString(xml);
20+
var signature = crypto.xpath(doc, "/*/*[local-name(.)='Signature' and namespace-uri(.)='http://www.w3.org/2000/09/xmldsig#']")[0];
21+
var sig = new crypto.SignedXml();
22+
sig.keyInfoProvider = new crypto.FileKeyInfo("./test/static/hmac-foobar.key");
23+
sig.loadSignature(signature);
24+
var result = sig.checkSignature(xml);
25+
test.equal(result, false);
26+
test.done();
27+
};

test/static/hmac-foobar.key

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
���F������G�}�P\���+=�(�9��(��z��
2+
)e�� �,�z6��8��ã

test/static/hmac.key

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
R���� -��B��%��P)�� ��A�kl�`9��7�<�YzC�Y^q�q_�"q؎1�C�o�

test/static/hmac_signature.xml

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<?xml version="1.0" encoding="UTF-8" standalone="no"?><test:Root xmlns:test="urn:test"><ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#"><ds:SignedInfo><ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/><ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#hmac-sha1"/><ds:Reference URI=""><ds:Transforms><ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/><ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/></ds:Transforms><ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/><ds:DigestValue>8ZvjCBK4twpNullktn5R4thOSezHWxuouNf6siHYJ1E=</ds:DigestValue></ds:Reference></ds:SignedInfo><ds:SignatureValue>EEX7i+HCAfEELjwwKP1vKyPrW10=</ds:SignatureValue><ds:KeyInfo><ds:KeyName>some-key-name</ds:KeyName></ds:KeyInfo></ds:Signature></test:Root>

test/validators/XmlCryptoJava/pom.xml

+72
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
3+
<modelVersion>4.0.0</modelVersion>
4+
<name>XML Crypto Java Tests</name>
5+
<groupId>org.nodejs</groupId>
6+
<artifactId>xml-crypto-java</artifactId>
7+
<version>1.0.0-SNAPSHOT</version>
8+
<packaging>jar</packaging>
9+
<inceptionYear>2015</inceptionYear>
10+
<licenses>
11+
<license>
12+
<name>MIT License</name>
13+
<url>http://www.opensource.org/licenses/mit-license.php</url>
14+
</license>
15+
</licenses>
16+
<developers>
17+
<developer>
18+
<id>fcorneli</id>
19+
<name>Frank Cornelis</name>
20+
<email>[email protected]</email>
21+
</developer>
22+
</developers>
23+
<dependencies>
24+
<dependency>
25+
<groupId>junit</groupId>
26+
<artifactId>junit</artifactId>
27+
<version>4.12</version>
28+
<scope>test</scope>
29+
</dependency>
30+
<dependency>
31+
<groupId>org.slf4j</groupId>
32+
<artifactId>slf4j-api</artifactId>
33+
<version>1.7.12</version>
34+
<scope>test</scope>
35+
</dependency>
36+
<dependency>
37+
<groupId>org.slf4j</groupId>
38+
<artifactId>slf4j-log4j12</artifactId>
39+
<version>1.7.12</version>
40+
<scope>test</scope>
41+
</dependency>
42+
<dependency>
43+
<groupId>log4j</groupId>
44+
<artifactId>log4j</artifactId>
45+
<version>1.2.17</version>
46+
<scope>test</scope>
47+
</dependency>
48+
<dependency>
49+
<groupId>commons-io</groupId>
50+
<artifactId>commons-io</artifactId>
51+
<version>2.4</version>
52+
<scope>test</scope>
53+
</dependency>
54+
</dependencies>
55+
<build>
56+
<plugins>
57+
<plugin>
58+
<groupId>org.apache.maven.plugins</groupId>
59+
<artifactId>maven-compiler-plugin</artifactId>
60+
<version>3.3</version>
61+
<configuration>
62+
<source>1.7</source>
63+
<target>1.7</target>
64+
<encoding>UTF-8</encoding>
65+
</configuration>
66+
</plugin>
67+
</plugins>
68+
</build>
69+
<properties>
70+
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
71+
</properties>
72+
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
package org.nodejs.xmlcrypto;
2+
3+
import java.io.File;
4+
import java.util.Collections;
5+
import java.util.LinkedList;
6+
import java.util.List;
7+
import javax.crypto.KeyGenerator;
8+
import javax.crypto.SecretKey;
9+
import javax.xml.crypto.dsig.CanonicalizationMethod;
10+
import javax.xml.crypto.dsig.DigestMethod;
11+
import javax.xml.crypto.dsig.Reference;
12+
import javax.xml.crypto.dsig.SignatureMethod;
13+
import javax.xml.crypto.dsig.SignedInfo;
14+
import javax.xml.crypto.dsig.Transform;
15+
import javax.xml.crypto.dsig.XMLSignature;
16+
import javax.xml.crypto.dsig.XMLSignatureFactory;
17+
import javax.xml.crypto.dsig.dom.DOMSignContext;
18+
import javax.xml.crypto.dsig.keyinfo.KeyInfo;
19+
import javax.xml.crypto.dsig.keyinfo.KeyInfoFactory;
20+
import javax.xml.crypto.dsig.spec.C14NMethodParameterSpec;
21+
import javax.xml.parsers.DocumentBuilder;
22+
import javax.xml.parsers.DocumentBuilderFactory;
23+
import javax.xml.transform.Transformer;
24+
import javax.xml.transform.TransformerFactory;
25+
import javax.xml.transform.dom.DOMSource;
26+
import javax.xml.transform.stream.StreamResult;
27+
import org.apache.commons.io.FileUtils;
28+
import org.junit.Test;
29+
import org.slf4j.Logger;
30+
import org.slf4j.LoggerFactory;
31+
import org.w3c.dom.Document;
32+
import org.w3c.dom.Element;
33+
import org.w3c.dom.Node;
34+
35+
public class HMACTest {
36+
37+
public static final String NamespaceSpecNS = "http://www.w3.org/2000/xmlns/";
38+
39+
private static final Logger LOGGER = LoggerFactory
40+
.getLogger(HMACTest.class);
41+
42+
@Test
43+
public void testCreateHMACSignature() throws Exception {
44+
// generate key
45+
KeyGenerator keyGenerator = KeyGenerator.getInstance("HmacSHA1");
46+
SecretKey secretKey = keyGenerator.generateKey();
47+
48+
// generate DOM document
49+
DocumentBuilderFactory documentBuilderFactory
50+
= DocumentBuilderFactory.newInstance();
51+
documentBuilderFactory.setNamespaceAware(true);
52+
DocumentBuilder documentBuilder = documentBuilderFactory
53+
.newDocumentBuilder();
54+
Document document = documentBuilder.newDocument();
55+
Element rootElement = document.createElementNS("urn:test",
56+
"test:Root");
57+
rootElement.setAttributeNS(NamespaceSpecNS,
58+
"xmlns:test", "urn:test");
59+
document.appendChild(rootElement);
60+
61+
XMLSignatureFactory xmlSignatureFactory = XMLSignatureFactory
62+
.getInstance("DOM");
63+
64+
// XML Signature references
65+
List<Reference> references = new LinkedList<>();
66+
List<Transform> transforms = new LinkedList<>();
67+
Transform envTransform = xmlSignatureFactory.newTransform(
68+
CanonicalizationMethod.ENVELOPED,
69+
(C14NMethodParameterSpec) null);
70+
transforms.add(envTransform);
71+
Transform exclTransform = xmlSignatureFactory.newTransform(
72+
CanonicalizationMethod.EXCLUSIVE,
73+
(C14NMethodParameterSpec) null);
74+
transforms.add(exclTransform);
75+
Reference reference = xmlSignatureFactory.newReference("",
76+
xmlSignatureFactory.newDigestMethod(DigestMethod.SHA256,
77+
null), transforms, null, null);
78+
references.add(reference);
79+
80+
// XML Signature SignedInfo
81+
SignedInfo signedInfo = xmlSignatureFactory.newSignedInfo(
82+
xmlSignatureFactory.newCanonicalizationMethod(
83+
CanonicalizationMethod.EXCLUSIVE,
84+
(C14NMethodParameterSpec) null),
85+
xmlSignatureFactory.newSignatureMethod(
86+
SignatureMethod.HMAC_SHA1,
87+
null), references);
88+
89+
// XML Signature KeyInfo
90+
KeyInfoFactory keyInfoFactory
91+
= xmlSignatureFactory.getKeyInfoFactory();
92+
KeyInfo keyInfo = keyInfoFactory.newKeyInfo(Collections
93+
.singletonList(keyInfoFactory.newKeyName("some-key-name")));
94+
95+
Element parentElement = document.getDocumentElement();
96+
DOMSignContext domSignContext = new DOMSignContext(
97+
secretKey, parentElement);
98+
domSignContext.setDefaultNamespacePrefix("ds");
99+
XMLSignature xmlSignature = xmlSignatureFactory.newXMLSignature(
100+
signedInfo, keyInfo);
101+
xmlSignature.sign(domSignContext);
102+
103+
File tmpFile = File.createTempFile("xml-signature-hmac-", ".xml");
104+
LOGGER.debug("XML signature file: {}", tmpFile.getAbsolutePath());
105+
toFile(document, tmpFile);
106+
107+
File tmpKeyFile = File.createTempFile("hmac-", ".key");
108+
FileUtils.writeByteArrayToFile(tmpKeyFile, secretKey.getEncoded());
109+
LOGGER.debug("key file: {}", tmpKeyFile.getAbsolutePath());
110+
111+
}
112+
113+
private void toFile(Node node, File file) throws Exception {
114+
TransformerFactory transformerFactory = TransformerFactory
115+
.newInstance();
116+
Transformer transformer = transformerFactory.newTransformer();
117+
transformer.transform(new DOMSource(node), new StreamResult(file));
118+
}
119+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
3+
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/"
4+
debug="false">
5+
<appender name="CONSOLE" class="org.apache.log4j.ConsoleAppender">
6+
<param name="Target" value="System.out" />
7+
<param name="Threshold" value="DEBUG" />
8+
<layout class="org.apache.log4j.PatternLayout">
9+
<param name="ConversionPattern"
10+
value="%-5p [%c{1}] %m%n" />
11+
</layout>
12+
</appender>
13+
<root>
14+
<appender-ref ref="CONSOLE" />
15+
</root>
16+
</log4j:configuration>

0 commit comments

Comments
 (0)