Fix TUWENI-30: expose key for GenericHash
diff --git a/crypto/src/main/java/org/apache/tuweni/crypto/sodium/GenericHash.java b/crypto/src/main/java/org/apache/tuweni/crypto/sodium/GenericHash.java
index b37003f..84a32cd 100644
--- a/crypto/src/main/java/org/apache/tuweni/crypto/sodium/GenericHash.java
+++ b/crypto/src/main/java/org/apache/tuweni/crypto/sodium/GenericHash.java
@@ -128,6 +128,106 @@
}
/**
+ * Key of generic hash function.
+ */
+ public static final class Key implements Destroyable {
+ private final Allocated value;
+
+ private Key(Pointer ptr, int length) {
+ this.value = new Allocated(ptr, length);
+ }
+
+ @Override
+ public void destroy() {
+ value.destroy();
+ }
+
+ @Override
+ public boolean isDestroyed() {
+ return value.isDestroyed();
+ }
+
+ /**
+ *
+ * @return the length of the key
+ */
+ public int length() {
+ return value.length();
+ }
+
+ /**
+ * Create a {@link GenericHash.Key} from a pointer.
+ *
+ * @param allocated the allocated pointer
+ * @return A key.
+ */
+ public static Key fromPointer(Allocated allocated) {
+ return new Key(Sodium.dup(allocated.pointer(), allocated.length()), allocated.length());
+ }
+
+ /**
+ * Create a {@link GenericHash.Key} from a hash.
+ *
+ * @param hash the hash
+ * @return A key.
+ */
+ public static Key fromHash(Hash hash) {
+ return new Key(Sodium.dup(hash.value.pointer(), hash.value.length()), hash.value.length());
+ }
+
+ /**
+ * Create a {@link GenericHash.Key} from an array of bytes.
+ *
+ * @param bytes The bytes for the key.
+ * @return A key.
+ */
+ public static Key fromBytes(Bytes bytes) {
+ return fromBytes(bytes.toArrayUnsafe());
+ }
+
+ /**
+ * Create a {@link GenericHash.Key} from an array of bytes.
+ *
+ * @param bytes The bytes for the key.
+ * @return A key.
+ */
+ public static Key fromBytes(byte[] bytes) {
+ return Sodium.dup(bytes, GenericHash.Key::new);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ if (!(obj instanceof GenericHash.Key)) {
+ return false;
+ }
+ Key other = (Key) obj;
+ return other.value.equals(value);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(value);
+ }
+
+ /**
+ * @return The bytes of this key.
+ */
+ public Bytes bytes() {
+ return value.bytes();
+ }
+
+ /**
+ * @return The bytes of this key.
+ */
+ public byte[] bytesArray() {
+ return value.bytesArray();
+ }
+ }
+
+ /**
* Generic hash function output.
*/
public static final class Hash implements Destroyable {
@@ -210,4 +310,24 @@
Sodium.crypto_generichash(output, hashLength, input.value.pointer(), input.length(), null, 0);
return new Hash(output, hashLength);
}
+
+ /**
+ * Creates a generic hash of specified length of the input
+ *
+ * @param hashLength the length of the hash
+ * @param input the input of the hash function
+ * @param key the key of the hash function
+ * @return the hash of the input
+ */
+ public static Hash hash(int hashLength, Input input, Key key) {
+ Pointer output = Sodium.malloc(hashLength);
+ Sodium.crypto_generichash(
+ output,
+ hashLength,
+ input.value.pointer(),
+ input.length(),
+ key.value.pointer(),
+ key.length());
+ return new Hash(output, hashLength);
+ }
}
diff --git a/crypto/src/test/java/org/apache/tuweni/crypto/sodium/GenericHashTest.java b/crypto/src/test/java/org/apache/tuweni/crypto/sodium/GenericHashTest.java
index 9e5193e..489ce69 100644
--- a/crypto/src/test/java/org/apache/tuweni/crypto/sodium/GenericHashTest.java
+++ b/crypto/src/test/java/org/apache/tuweni/crypto/sodium/GenericHashTest.java
@@ -34,4 +34,11 @@
assertNotNull(output);
assertEquals(64, output.bytes().size());
}
+
+ @Test
+ void hashWithKeyValue() {
+ GenericHash.Hash output = GenericHash.hash(64, GenericHash.Input.fromBytes(Bytes.random(384)), GenericHash.Key.fromBytes(Bytes.random(32)));
+ assertNotNull(output);
+ assertEquals(64, output.bytes().size());
+ }
}