From 28f3130cf903d518747e9b3e9a01ddc8d0d844a2 Mon Sep 17 00:00:00 2001 From: vanitasvitae Date: Sat, 3 Jun 2017 00:33:56 +0200 Subject: [PATCH] Add Use of Cryptographic Hashfunctions (XEP-300) Also move bouncycastle dep from smack-omemo to smack-experimental. --- smack-experimental/build.gradle | 2 + .../smackx/hashes/HashManager.java | 317 ++++++++++++++++++ .../smackx/hashes/element/HashElement.java | 119 +++++++ .../smackx/hashes/element/package-info.java | 22 ++ .../smackx/hashes/package-info.java | 21 ++ .../hashes/provider/HashElementProvider.java | 35 ++ .../smackx/hashes/provider/package-info.java | 22 ++ .../smackx/hashes/HashElementTest.java | 60 ++++ .../jivesoftware/smackx/hashes/HashTest.java | 172 ++++++++++ smack-omemo/build.gradle | 1 - 10 files changed, 770 insertions(+), 1 deletion(-) create mode 100644 smack-experimental/src/main/java/org/jivesoftware/smackx/hashes/HashManager.java create mode 100644 smack-experimental/src/main/java/org/jivesoftware/smackx/hashes/element/HashElement.java create mode 100644 smack-experimental/src/main/java/org/jivesoftware/smackx/hashes/element/package-info.java create mode 100644 smack-experimental/src/main/java/org/jivesoftware/smackx/hashes/package-info.java create mode 100644 smack-experimental/src/main/java/org/jivesoftware/smackx/hashes/provider/HashElementProvider.java create mode 100644 smack-experimental/src/main/java/org/jivesoftware/smackx/hashes/provider/package-info.java create mode 100644 smack-experimental/src/test/java/org/jivesoftware/smackx/hashes/HashElementTest.java create mode 100644 smack-experimental/src/test/java/org/jivesoftware/smackx/hashes/HashTest.java diff --git a/smack-experimental/build.gradle b/smack-experimental/build.gradle index 51315f23a..2f4d4e0d5 100644 --- a/smack-experimental/build.gradle +++ b/smack-experimental/build.gradle @@ -10,4 +10,6 @@ dependencies { testCompile project(path: ":smack-core", configuration: "testRuntime") testCompile project(path: ":smack-core", configuration: "archives") testCompile project(path: ":smack-extensions", configuration: "testRuntime") + + compile "org.bouncycastle:bcprov-jdk15on:1.57" } diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/hashes/HashManager.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/hashes/HashManager.java new file mode 100644 index 000000000..29fac9310 --- /dev/null +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/hashes/HashManager.java @@ -0,0 +1,317 @@ +/** + * + * Copyright © 2017 Paul Schaub + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jivesoftware.smackx.hashes; + +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.jivesoftware.smack.Manager; +import org.jivesoftware.smack.XMPPConnection; +import org.jivesoftware.smackx.disco.ServiceDiscoveryManager; +import org.jivesoftware.smackx.hashes.element.HashElement; + +import java.math.BigInteger; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.Security; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.WeakHashMap; + +import static org.jivesoftware.smackx.hashes.HashManager.ALGORITHM.BLAKE2B160; +import static org.jivesoftware.smackx.hashes.HashManager.ALGORITHM.BLAKE2B256; +import static org.jivesoftware.smackx.hashes.HashManager.ALGORITHM.BLAKE2B384; +import static org.jivesoftware.smackx.hashes.HashManager.ALGORITHM.BLAKE2B512; +import static org.jivesoftware.smackx.hashes.HashManager.ALGORITHM.MD5; +import static org.jivesoftware.smackx.hashes.HashManager.ALGORITHM.SHA3_224; +import static org.jivesoftware.smackx.hashes.HashManager.ALGORITHM.SHA3_256; +import static org.jivesoftware.smackx.hashes.HashManager.ALGORITHM.SHA3_384; +import static org.jivesoftware.smackx.hashes.HashManager.ALGORITHM.SHA3_512; +import static org.jivesoftware.smackx.hashes.HashManager.ALGORITHM.SHA_1; +import static org.jivesoftware.smackx.hashes.HashManager.ALGORITHM.SHA_224; +import static org.jivesoftware.smackx.hashes.HashManager.ALGORITHM.SHA_256; +import static org.jivesoftware.smackx.hashes.HashManager.ALGORITHM.SHA_384; +import static org.jivesoftware.smackx.hashes.HashManager.ALGORITHM.SHA_512; + +/** + * Manager that can be used to determine support for hash functions. + */ +public final class HashManager extends Manager { + + static { + Security.addProvider(new BouncyCastleProvider()); + } + public static final String PROVIDER = "BC"; + + public static final String PREFIX_NS_ALGO = "urn:xmpp:hash-function-text-names:"; + + public enum NAMESPACE { + V1 ("urn:xmpp:hashes:1"), + V2 ("urn:xmpp:hashes:2"); + + final String name; + + NAMESPACE(String name) { + this.name = name; + } + + @Override + public String toString() { + return this.name; + } + } + + public static final List RECOMMENDED = Collections.unmodifiableList(Arrays.asList( + SHA_256, SHA_384, SHA_512, + SHA3_256, SHA3_384, SHA3_512, + BLAKE2B256, BLAKE2B384, BLAKE2B512)); + + private static final WeakHashMap INSTANCES = new WeakHashMap<>(); + + /** + * Constructor of the HashManager. + * By default the Manager announces support for XEP-0300, as well as for the RECOMMENDED set of hash algorithms. + * Those contain SHA256, SHA384, SHA512, SHA3-256, SHA3-384, SHA3-512, BLAKE2B256, BLAKE2B384 and BLAKE2B512. + * Those algorithms got recommended here: https://xmpp.org/extensions/xep-0300.html#recommendations + * @param connection connection + */ + private HashManager(XMPPConnection connection) { + super(connection); + ServiceDiscoveryManager sdm = ServiceDiscoveryManager.getInstanceFor(connection); + sdm.addFeature(NAMESPACE.V2.toString()); + addAlgorithmsToFeatures(RECOMMENDED); + } + + public static HashElement calculateHashElement(ALGORITHM algorithm, byte[] data) { + return new HashElement(algorithm, hash(algorithm, data)); + } + + public static HashElement assembleHashElement(ALGORITHM algorithm, byte[] hash) { + return new HashElement(algorithm, hash); + } + + /** + * Announce support for the given list of algorithms. + * @param algorithms + */ + public void addAlgorithmsToFeatures(List algorithms) { + ServiceDiscoveryManager sdm = ServiceDiscoveryManager.getInstanceFor(connection()); + for (ALGORITHM algo : algorithms) { + sdm.addFeature(asFeature(algo)); + } + } + + /** + * Get an instance of the HashManager for the given connection. + * @param connection + * @return + */ + public HashManager getInstanceFor(XMPPConnection connection) { + HashManager hashManager = INSTANCES.get(connection); + if (hashManager == null) { + hashManager = new HashManager(connection); + INSTANCES.put(connection, hashManager); + } + return hashManager; + } + + /** + * Return the feature name of the given algorithm. + * @param algorithm eg. 'SHA_1' + * @return feature name (eg. urn:xmpp:hash-function-text-names:sha-1') + */ + public static String asFeature(ALGORITHM algorithm) { + return PREFIX_NS_ALGO + algorithm.toString(); + } + + public enum ALGORITHM { // RECOMMENDATION: + MD5 ("md5"), // MUST NOT use this + SHA_1 ("sha-1"), // SHOULD NOT use this + SHA_224 ("sha-224"), + SHA_256 ("sha-256"), // MUST use this + SHA_384 ("sha-384"), + SHA_512 ("sha-512"), // SHOULD use this + SHA3_224 ("sha3-224"), + SHA3_256 ("sha3-256"), // MUST use this + SHA3_384 ("sha3-384"), + SHA3_512 ("sha3-512"), // SHOULD use this + BLAKE2B160("id-blake2b160"), + BLAKE2B256("id-blake2b256"), // MUST use this + BLAKE2B384("id-blake2b384"), + BLAKE2B512("id-blake2b512"); // SHOULD use this + + private final String name; + + ALGORITHM(String name) { + this.name = name; + } + + /** + * Return the name of the algorithm as it is used in the XEP. + * @return name. + */ + @Override + public String toString() { + return this.name; + } + + /** + * Compensational method for static 'valueOf' function. + * @param s + * @return + */ + public static ALGORITHM valueOfName(String s) { + for (ALGORITHM a : ALGORITHM.values()) { + if (a.toString().equals(s)) { + return a; + } + } + throw new IllegalArgumentException("No ALGORITHM enum with this name (" + s + ") found."); + } + } + + /** + * Calculate the hash sum of data using algorithm. + * @param algorithm + * @param data + * @return + */ + public static byte[] hash(ALGORITHM algorithm, byte[] data) { + return getMessageDigest(algorithm).digest(data); + } + + public static MessageDigest getMessageDigest(ALGORITHM algorithm) { + MessageDigest md; + try { + switch (algorithm) { + case MD5: + md = MessageDigest.getInstance("MD5", PROVIDER); + break; + case SHA_1: + md = MessageDigest.getInstance("SHA-1", PROVIDER); + break; + case SHA_224: + md = MessageDigest.getInstance("SHA-224", PROVIDER); + break; + case SHA_256: + md = MessageDigest.getInstance("SHA-256", PROVIDER); + break; + case SHA_384: + md = MessageDigest.getInstance("SHA-384", PROVIDER); + break; + case SHA_512: + md = MessageDigest.getInstance("SHA-512", PROVIDER); + break; + case SHA3_224: + md = MessageDigest.getInstance("SHA3-224", PROVIDER); + break; + case SHA3_256: + md = MessageDigest.getInstance("SHA3-256", PROVIDER); + break; + case SHA3_384: + md = MessageDigest.getInstance("SHA3-384", PROVIDER); + break; + case SHA3_512: + md = MessageDigest.getInstance("SHA3-512", PROVIDER); + break; + case BLAKE2B160: + md = MessageDigest.getInstance("BLAKE2b-160", PROVIDER); + break; + case BLAKE2B256: + md = MessageDigest.getInstance("BLAKE2b-256", PROVIDER); + break; + case BLAKE2B384: + md = MessageDigest.getInstance("BLAKE2b-384", PROVIDER); + break; + case BLAKE2B512: + md = MessageDigest.getInstance("BLAKE2b-512", PROVIDER); + break; + default: + throw new AssertionError("Invalid enum value."); + } + return md; + } catch (NoSuchAlgorithmException | NoSuchProviderException e) { + throw new AssertionError(e); + } + } + + public static byte[] md5(byte[] data) { + return getMessageDigest(MD5).digest(data); + } + + public static byte[] sha_1(byte[] data) { + return getMessageDigest(SHA_1).digest(data); + } + + public static byte[] sha_224(byte[] data) { + return getMessageDigest(SHA_224).digest(data); + } + + public static byte[] sha_256(byte[] data) { + return getMessageDigest(SHA_256).digest(data); + } + + public static byte[] sha_384(byte[] data) { + return getMessageDigest(SHA_384).digest(data); + } + + public static byte[] sha_512(byte[] data) { + return getMessageDigest(SHA_512).digest(data); + } + + public static byte[] sha3_224(byte[] data) { + return getMessageDigest(SHA3_224).digest(data); + } + + public static byte[] sha3_256(byte[] data) { + return getMessageDigest(SHA3_256).digest(data); + } + + public static byte[] sha3_384(byte[] data) { + return getMessageDigest(SHA3_384).digest(data); + } + + public static byte[] sha3_512(byte[] data) { + return getMessageDigest(SHA3_512).digest(data); + } + + public static byte[] blake2b160(byte[] data) { + return getMessageDigest(BLAKE2B160).digest(data); + } + + public static byte[] blake2b256(byte[] data) { + return getMessageDigest(BLAKE2B256).digest(data); + } + + public static byte[] blake2b384(byte[] data) { + return getMessageDigest(BLAKE2B384).digest(data); + } + + public static byte[] blake2b512(byte[] data) { + return getMessageDigest(BLAKE2B512).digest(data); + } + + /** + * Encode a byte array in HEX. + * @param hash + * @return + */ + public static String hex(byte[] hash) { + return new BigInteger(1, hash).toString(16); + } + +} diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/hashes/element/HashElement.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/hashes/element/HashElement.java new file mode 100644 index 000000000..c1dad6a0a --- /dev/null +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/hashes/element/HashElement.java @@ -0,0 +1,119 @@ +/** + * + * Copyright © 2017 Paul Schaub + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jivesoftware.smackx.hashes.element; + + +import org.jivesoftware.smack.packet.ExtensionElement; +import org.jivesoftware.smack.util.XmlStringBuilder; +import org.jivesoftware.smack.util.stringencoder.Base64; +import org.jivesoftware.smackx.hashes.HashManager; + +import static org.jivesoftware.smack.util.Objects.requireNonNull; + +/** + * Represent a hash element. + * + * @author Paul Schaub + */ +public class HashElement implements ExtensionElement { + + public static final String ELEMENT = "hash"; + public static final String ATTR_ALGO = "algo"; + + private final HashManager.ALGORITHM algorithm; + private final byte[] hash; + private final String hashB64; + + /** + * Create a HashElement from pre-calculated values. + * @param algorithm The algorithm which was used. + * @param hash the checksum as byte array. + */ + public HashElement(HashManager.ALGORITHM algorithm, byte[] hash) { + this.algorithm = requireNonNull(algorithm); + this.hash = requireNonNull(hash); + hashB64 = Base64.encodeToString(hash); + } + + /** + * Create a HashElement from pre-calculated values. + * @param algorithm the algorithm that was used. + * @param hashB64 the checksum in base 64. + */ + public HashElement(HashManager.ALGORITHM algorithm, String hashB64) { + this.algorithm = algorithm; + this.hash = Base64.decode(hashB64); + this.hashB64 = hashB64; + } + + /** + * Return the hash algorithm used in this HashElement. + * @return algorithm + */ + public HashManager.ALGORITHM getAlgorithm() { + return algorithm; + } + + /** + * Return the checksum as a byte array. + * @return + */ + public byte[] getHash() { + return hash; + } + + /** + * Return the checksum as a base16 (hex) string. + * @return + */ + public String getHashB64() { + return hashB64; + } + + @Override + public String getElementName() { + return ELEMENT; + } + + @Override + public CharSequence toXML() { + XmlStringBuilder sb = new XmlStringBuilder(this); + sb.attribute(ATTR_ALGO, algorithm.toString()); + sb.rightAngleBracket(); + sb.append(hashB64); + sb.closeElement(this); + return sb; + } + + @Override + public String getNamespace() { + return HashManager.NAMESPACE.V2.toString(); + } + + @Override + public boolean equals(Object other) { + if (other == null || !(other instanceof HashElement)) { + return false; + } + return this.hashCode() == other.hashCode(); + } + + @Override + public int hashCode() { + return toXML().toString().hashCode(); + } +} diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/hashes/element/package-info.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/hashes/element/package-info.java new file mode 100644 index 000000000..64fc23700 --- /dev/null +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/hashes/element/package-info.java @@ -0,0 +1,22 @@ +/** + * + * Copyright © 2017 Paul Schaub + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * XEP-0300 - Use of cryptographic hash functions. + * Element classes. + */ +package org.jivesoftware.smackx.hashes.element; diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/hashes/package-info.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/hashes/package-info.java new file mode 100644 index 000000000..b5fef5cbf --- /dev/null +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/hashes/package-info.java @@ -0,0 +1,21 @@ +/** + * + * Copyright © 2017 Paul Schaub + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * XEP-0300 - Use of cryptographic hash functions. + */ +package org.jivesoftware.smackx.hashes; diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/hashes/provider/HashElementProvider.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/hashes/provider/HashElementProvider.java new file mode 100644 index 000000000..0042f2930 --- /dev/null +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/hashes/provider/HashElementProvider.java @@ -0,0 +1,35 @@ +/** + * + * Copyright © 2017 Paul Schaub + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jivesoftware.smackx.hashes.provider; + +import org.jivesoftware.smack.provider.ExtensionElementProvider; +import org.jivesoftware.smackx.hashes.HashManager; +import org.jivesoftware.smackx.hashes.element.HashElement; +import org.xmlpull.v1.XmlPullParser; + +/** + * Provider for HashElements. + */ +public class HashElementProvider extends ExtensionElementProvider { + + @Override + public HashElement parse(XmlPullParser parser, int initialDepth) throws Exception { + String algo = parser.getAttributeValue(null, HashElement.ATTR_ALGO); + String hashB64 = parser.nextText(); + return new HashElement(HashManager.ALGORITHM.valueOfName(algo), hashB64); + } +} diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/hashes/provider/package-info.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/hashes/provider/package-info.java new file mode 100644 index 000000000..c5ad13fed --- /dev/null +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/hashes/provider/package-info.java @@ -0,0 +1,22 @@ +/** + * + * Copyright © 2017 Paul Schaub + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * XEP-0300 - Use of cryptographic hash functions. + * Provider classes. + */ +package org.jivesoftware.smackx.hashes.provider; diff --git a/smack-experimental/src/test/java/org/jivesoftware/smackx/hashes/HashElementTest.java b/smack-experimental/src/test/java/org/jivesoftware/smackx/hashes/HashElementTest.java new file mode 100644 index 000000000..a9b1d6af6 --- /dev/null +++ b/smack-experimental/src/test/java/org/jivesoftware/smackx/hashes/HashElementTest.java @@ -0,0 +1,60 @@ +/** + * + * Copyright 2017 Paul Schaub + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jivesoftware.smackx.hashes; + +import org.jivesoftware.smack.test.util.SmackTestSuite; +import org.jivesoftware.smack.test.util.TestUtils; +import org.jivesoftware.smack.util.StringUtils; +import org.jivesoftware.smackx.hashes.element.HashElement; +import org.jivesoftware.smackx.hashes.provider.HashElementProvider; +import org.junit.Test; + +import static junit.framework.TestCase.assertEquals; +import static org.jivesoftware.smackx.hashes.HashManager.ALGORITHM.SHA_256; +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +/** + * Test toXML and parse of HashElement and HashElementProvider. + */ +public class HashElementTest extends SmackTestSuite { + + @Test + public void stanzaTest() throws Exception { + String message = "Hello World!"; + HashElement element = HashManager.calculateHashElement(SHA_256, message.getBytes(StringUtils.UTF8)); + String expected = "f4OxZX/x/FO5LcGBSKHWXfwtSx+j1ncoSt3SABJtkGk="; + assertEquals(expected, element.toXML().toString()); + + HashElement parsed = new HashElementProvider().parse(TestUtils.getParser(expected)); + assertEquals(expected, parsed.toXML().toString()); + assertEquals(SHA_256, parsed.getAlgorithm()); + assertEquals("f4OxZX/x/FO5LcGBSKHWXfwtSx+j1ncoSt3SABJtkGk=", parsed.getHashB64()); + assertArrayEquals(HashManager.sha_256(message.getBytes(StringUtils.UTF8)), parsed.getHash()); + + assertFalse(parsed.equals(expected)); + assertFalse(parsed.equals(null)); + assertEquals(element, parsed); + assertTrue(element.equals(parsed)); + + HashElement other = new HashElement(HashManager.ALGORITHM.SHA_512, + "861844d6704e8573fec34d967e20bcfef3d424cf48be04e6dc08f2bd58c729743371015ead891cc3cf1c9d34b49264b510751b1ff9e537937bc46b5d6ff4ecc8".getBytes(StringUtils.UTF8)); + assertFalse(element.equals(other)); + } + +} diff --git a/smack-experimental/src/test/java/org/jivesoftware/smackx/hashes/HashTest.java b/smack-experimental/src/test/java/org/jivesoftware/smackx/hashes/HashTest.java new file mode 100644 index 000000000..a24ed05c3 --- /dev/null +++ b/smack-experimental/src/test/java/org/jivesoftware/smackx/hashes/HashTest.java @@ -0,0 +1,172 @@ +/** + * + * Copyright 2017 Paul Schaub + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jivesoftware.smackx.hashes; + +import org.jivesoftware.smack.test.util.SmackTestSuite; +import org.jivesoftware.smack.util.StringUtils; +import org.junit.Test; + +import java.io.UnsupportedEncodingException; + +import static junit.framework.TestCase.assertEquals; + +/** + * Test HashManager functionality. + * The test sums got calculated using 'echo "Hello World!" | { md5sum, sha1sum, sha224sum, sha256sum, sha384sum, sha512sum, + * sha3-224sum -l, sha3-256sum -l, sha3-384sum -l, sha3-512sum -l, b2sum -l 160, b2sum -l 256, b2sum -l 384, b2sum -l 512 } + */ +public class HashTest extends SmackTestSuite { + + private static final String testString = "Hello World!"; + private static final String md5sum = "ed076287532e86365e841e92bfc50d8c"; + private static final String sha1sum = "2ef7bde608ce5404e97d5f042f95f89f1c232871"; + private static final String sha224sum = "4575bb4ec129df6380cedde6d71217fe0536f8ffc4e18bca530a7a1b"; + private static final String sha256sum = "7f83b1657ff1fc53b92dc18148a1d65dfc2d4b1fa3d677284addd200126d9069"; + private static final String sha384sum = "bfd76c0ebbd006fee583410547c1887b0292be76d582d96c242d2a792723e3fd6fd061f9d5cfd13b8f961358e6adba4a"; + private static final String sha512sum = "861844d6704e8573fec34d967e20bcfef3d424cf48be04e6dc08f2bd58c729743371015ead891cc3cf1c9d34b49264b510751b1ff9e537937bc46b5d6ff4ecc8"; + private static final String sha3_224sum = "716596afadfa17cd1cb35133829a02b03e4eed398ce029ce78a2161d"; + private static final String sha3_256sum = "d0e47486bbf4c16acac26f8b653592973c1362909f90262877089f9c8a4536af"; + private static final String sha3_384sum = "f324cbd421326a2abaedf6f395d1a51e189d4a71c755f531289e519f079b224664961e385afcc37da348bd859f34fd1c"; + private static final String sha3_512sum = "32400b5e89822de254e8d5d94252c52bdcb27a3562ca593e980364d9848b8041b98eabe16c1a6797484941d2376864a1b0e248b0f7af8b1555a778c336a5bf48"; + private static final String b2_160sum = "e7338d05e5aa2b5e4943389f9475fce2525b92f2"; + private static final String b2_256sum = "bf56c0728fd4e9cf64bfaf6dabab81554103298cdee5cc4d580433aa25e98b00"; + private static final String b2_384sum = "53fd759520545fe93270e61bac03b243b686af32ed39a4aa635555be47a89004851d6a13ece00d95b7bdf9910cb71071"; + private static final String b2_512sum = "54b113f499799d2f3c0711da174e3bc724737ad18f63feb286184f0597e1466436705d6c8e8c7d3d3b88f5a22e83496e0043c44a3c2b1700e0e02259f8ac468e"; + + private byte[] array() { + if (testArray == null) { + try { + testArray = testString.getBytes(StringUtils.UTF8); + } catch (UnsupportedEncodingException e) { + throw new AssertionError("UTF8 MUST be supported."); + } + } + return testArray; + } + + private byte[] testArray; + + @Test + public void hashTest() { + assertEquals(md5sum, HashManager.hex(HashManager.hash(HashManager.ALGORITHM.MD5, array()))); + assertEquals(sha1sum, HashManager.hex(HashManager.hash(HashManager.ALGORITHM.SHA_1, array()))); + assertEquals(sha224sum, HashManager.hex(HashManager.hash(HashManager.ALGORITHM.SHA_224, array()))); + assertEquals(sha256sum, HashManager.hex(HashManager.hash(HashManager.ALGORITHM.SHA_256, array()))); + assertEquals(sha384sum, HashManager.hex(HashManager.hash(HashManager.ALGORITHM.SHA_384, array()))); + assertEquals(sha512sum, HashManager.hex(HashManager.hash(HashManager.ALGORITHM.SHA_512, array()))); + assertEquals(sha3_224sum, HashManager.hex(HashManager.hash(HashManager.ALGORITHM.SHA3_224, array()))); + assertEquals(sha3_256sum, HashManager.hex(HashManager.hash(HashManager.ALGORITHM.SHA3_256, array()))); + assertEquals(sha3_384sum, HashManager.hex(HashManager.hash(HashManager.ALGORITHM.SHA3_384, array()))); + assertEquals(sha3_512sum, HashManager.hex(HashManager.hash(HashManager.ALGORITHM.SHA3_512, array()))); + assertEquals(b2_160sum, HashManager.hex(HashManager.hash(HashManager.ALGORITHM.BLAKE2B160, array()))); + assertEquals(b2_256sum, HashManager.hex(HashManager.hash(HashManager.ALGORITHM.BLAKE2B256, array()))); + assertEquals(b2_384sum, HashManager.hex(HashManager.hash(HashManager.ALGORITHM.BLAKE2B384, array()))); + assertEquals(b2_512sum, HashManager.hex(HashManager.hash(HashManager.ALGORITHM.BLAKE2B512, array()))); + } + + @Test + public void md5Test() { + String actual = HashManager.hex(HashManager.md5(array())); + assertEquals(md5sum, actual); + } + + @Test + public void sha1Test() { + String actual = HashManager.hex(HashManager.sha_1(array())); + assertEquals(sha1sum, actual); + } + + @Test + public void sha224Test() { + String actual = HashManager.hex(HashManager.sha_224(array())); + assertEquals(sha224sum, actual); + } + + @Test + public void sha256Test() { + String actual = HashManager.hex(HashManager.sha_256(array())); + assertEquals(sha256sum, actual); + } + + @Test + public void sha384Test() { + String actual = HashManager.hex(HashManager.sha_384(array())); + assertEquals(sha384sum, actual); + } + + @Test + public void sha512Test() { + String actual = HashManager.hex(HashManager.sha_512(array())); + assertEquals(sha512sum, actual); + } + + @Test + public void sha3_224Test() { + String actual = HashManager.hex(HashManager.sha3_224(array())); + assertEquals(sha3_224sum, actual); + } + + @Test + public void sha3_256Test() { + String actual = HashManager.hex(HashManager.sha3_256(array())); + assertEquals(sha3_256sum, actual); + } + + @Test + public void sha3_384Test() { + String actual = HashManager.hex(HashManager.sha3_384(array())); + assertEquals(sha3_384sum, actual); + } + + @Test + public void sha3_512Test() { + String actual = HashManager.hex(HashManager.sha3_512(array())); + assertEquals(sha3_512sum, actual); + } + + @Test + public void blake2b160Test() { + String actual = HashManager.hex(HashManager.blake2b160(array())); + assertEquals(b2_160sum, actual); + } + + @Test + public void blake2b256Test() { + String actual = HashManager.hex(HashManager.blake2b256(array())); + assertEquals(b2_256sum, actual); + } + + @Test + public void blake2b384Test() { + String actual = HashManager.hex(HashManager.blake2b384(array())); + assertEquals(b2_384sum, actual); + } + + @Test + public void blake2b512Test() { + String actual = HashManager.hex(HashManager.blake2b512(array())); + assertEquals(b2_512sum, actual); + } + + @Test + public void asFeatureTest() { + assertEquals("urn:xmpp:hash-function-text-names:id-blake2b384", HashManager.asFeature(HashManager.ALGORITHM.BLAKE2B384)); + assertEquals("urn:xmpp:hash-function-text-names:md5", HashManager.asFeature(HashManager.ALGORITHM.MD5)); + assertEquals("urn:xmpp:hash-function-text-names:sha3-512", HashManager.asFeature(HashManager.ALGORITHM.SHA3_512)); + assertEquals("urn:xmpp:hash-function-text-names:sha-512", HashManager.asFeature(HashManager.ALGORITHM.SHA_512)); + } +} diff --git a/smack-omemo/build.gradle b/smack-omemo/build.gradle index b6b838986..9c16a3739 100644 --- a/smack-omemo/build.gradle +++ b/smack-omemo/build.gradle @@ -8,7 +8,6 @@ dependencies { compile project(":smack-im") compile project(":smack-extensions") compile project(":smack-experimental") - compile "org.bouncycastle:bcprov-jdk15on:1.57" testCompile project(path: ":smack-core", configuration: "testRuntime") }