Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[feature] Functions for listing hash providers and algorithms and specifying them when hashing #8

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@

<properties>
<package.title>EXPath Cryptographic Module Implementation</package.title>
<crypto.java.lib.version>1.8.0</crypto.java.lib.version>
<crypto.java.lib.version>1.8.1-SNAPSHOT</crypto.java.lib.version>
<exist.version>5.3.0</exist.version>
<crypto.module.ns>http://expath.org/ns/crypto</crypto.module.ns>
<crypto.module.java.class>org.expath.exist.crypto.ExistExpathCryptoModule</crypto.module.java.class>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,15 @@ public class ExistExpathCryptoModule extends AbstractInternalModule {

public final static ErrorCode NO_FUNCTION = new ExpathCryptoErrorCode("NO_FUNCTION", "No function");

private final static FunctionDef[] functions = functionDefs(functionDefs(HashFunction.class, HashFunction.FS_HASH),
private final static FunctionDef[] functions = functionDefs(
functionDefs(HashFunction.class, HashFunction.FS_HASH),
functionDefs(HashFunction.class, HashFunction.FS_HASH_PROVIDERS),
functionDefs(HashFunction.class, HashFunction.FS_HASH_ALGORITHMS),
functionDefs(HmacFunction.class, HmacFunction.FS_HMAC),
functionDefs(GenerateSignatureFunction.class, GenerateSignatureFunction.FS_GENERATE_SIGNATURE),
functionDefs(ValidateSignatureFunction.class, ValidateSignatureFunction.FS_VALIDATE_SIGNATURE),
functionDefs(EncryptionFunctions.class, EncryptionFunctions.FS_ENCRYPT, EncryptionFunctions.FS_DECRYPT));
functionDefs(EncryptionFunctions.class, EncryptionFunctions.FS_ENCRYPT, EncryptionFunctions.FS_DECRYPT)
);

public ExistExpathCryptoModule(final Map<String, List<? extends Object>> parameters) throws Exception {
super(functions, parameters);
Expand Down
108 changes: 95 additions & 13 deletions src/main/java/org/expath/exist/crypto/digest/HashFunction.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,16 +27,15 @@

import java.io.IOException;
import java.io.InputStream;
import java.util.Map;
import java.util.Set;

import org.exist.xquery.BasicFunction;
import org.exist.xquery.FunctionSignature;
import org.exist.xquery.XPathException;
import org.exist.xquery.XQueryContext;
import org.exist.xquery.value.BinaryValue;
import org.exist.xquery.value.FunctionParameterSequenceType;
import org.exist.xquery.value.Sequence;
import org.exist.xquery.value.StringValue;
import org.exist.xquery.value.Type;
import org.exist.xquery.functions.map.MapType;
import org.exist.xquery.value.*;
import org.expath.exist.crypto.EXpathCryptoException;

import org.slf4j.Logger;
Expand All @@ -46,6 +45,7 @@

import static org.exist.xquery.FunctionDSL.*;
import static org.expath.exist.crypto.ExistExpathCryptoModule.*;
import static org.expath.exist.crypto.ExistExpathCryptoModule.functionSignature;

public class HashFunction extends BasicFunction {

Expand All @@ -56,12 +56,53 @@ public class HashFunction extends BasicFunction {
"The data to be hashed.");
private static final FunctionParameterSequenceType FS_HASH_PARAM_ALGORITHM = param("algorithm", Type.STRING,
"The cryptographic hashing algorithm.");
private static final FunctionParameterSequenceType FS_HASH_PARAM_PROVIDER = param("provider", Type.STRING,
"The cryptographic hashing algorithm provider.");

public static final FunctionSignature FS_HASH[] = functionSignatures(FS_HASH_NAME,
"resulting hash value, as string.", returnsOptMany(Type.BYTE),
arities(arity(FS_HASH_PARAM_DATA, FS_HASH_PARAM_ALGORITHM),
arity(FS_HASH_PARAM_DATA, FS_HASH_PARAM_ALGORITHM, param("encoding", Type.STRING,
"The encoding of the output. The legal values are \"hex\" and \"base64\". The default value is \"base64\"."))));
public static final FunctionSignature FS_HASH[] = functionSignatures(
FS_HASH_NAME,
"resulting hash value, as string.",
returnsOptMany(Type.BYTE),
arities(
arity(
FS_HASH_PARAM_DATA,
FS_HASH_PARAM_ALGORITHM
),
arity(
FS_HASH_PARAM_DATA,
FS_HASH_PARAM_ALGORITHM,
param("encoding", Type.STRING, "The encoding of the output. The legal values are \"hex\" and \"base64\". The default value is \"base64\".")
),
arity(
FS_HASH_PARAM_DATA,
FS_HASH_PARAM_ALGORITHM,
param("encoding", Type.STRING, "The encoding of the output. The legal values are \"hex\" and \"base64\". The default value is \"base64\"."),
FS_HASH_PARAM_PROVIDER
)
)
);

private static final String FS_HASH_PROVIDERS_NAME = "hash-providers";
public static final FunctionSignature FS_HASH_PROVIDERS = functionSignature(
FS_HASH_PROVIDERS_NAME,
"Gets the names of all the hash providers",
returnsOptMany(Type.STRING)
);

private static final String FS_HASH_ALGORITHMS_NAME = "hash-algorithms";
public static final FunctionSignature FS_HASH_ALGORITHMS[] = {
functionSignature(
FS_HASH_ALGORITHMS_NAME,
"Gets the names of all the hash providers",
returnsOptMany(Type.STRING)
),
functionSignature(
FS_HASH_ALGORITHMS_NAME,
"Gets the names of all the hash providers",
returns(Type.MAP),
param("provider-name", Type.STRING, "The name of the hash provider.")
)
};

public HashFunction(final XQueryContext context, final FunctionSignature signature) {
super(context, signature);
Expand All @@ -70,6 +111,42 @@ public HashFunction(final XQueryContext context, final FunctionSignature signatu
@Override
public Sequence eval(final Sequence[] args, final Sequence contextSequence) throws XPathException {

if (isCalledAs(FS_HASH_NAME)) {
return hash(args);

} else if (isCalledAs(FS_HASH_PROVIDERS_NAME)) {
final ValueSequence providers = new ValueSequence();
for (final String provider : Hash.listProviders()) {
providers.add(new StringValue(provider));
}
return providers;

} else if (isCalledAs(FS_HASH_ALGORITHMS_NAME)) {
if (args.length == 1) {
final String providerName = args[0].getStringValue();
final ValueSequence algorithmNames = new ValueSequence();
for (final String algorithmName : Hash.listAlgorithms(providerName)) {
algorithmNames.add(new StringValue(algorithmName));
}
return algorithmNames;

} else {
final MapType mapType = new MapType(this.context);
for(final Map.Entry<String, Set<String>> providerAlgorithms : Hash.listAlgorithms().entrySet()) {
final ValueSequence algorithmNames = new ValueSequence();
for (final String algorithmName : providerAlgorithms.getValue()) {
algorithmNames.add(new StringValue(algorithmName));
}
mapType.add(new StringValue(providerAlgorithms.getKey()), algorithmNames);
}
return mapType;
}
} else {
throw new XPathException(this, "Unknown function name");
}
}

private Sequence hash(final Sequence[] args) throws XPathException {
final int inputType = args[0].itemAt(0).getType();
final String hashAlgorithm = args[1].getStringValue();
final String encoding;
Expand All @@ -78,20 +155,25 @@ public Sequence eval(final Sequence[] args, final Sequence contextSequence) thro
} else {
encoding = args[2].getStringValue().isEmpty() ? "base64" : args[2].getStringValue();
}
String provider = null;
if (args.length == 4) {
provider = args[3].getStringValue();
}

LOG.debug("encoding = {}", encoding);

final Sequence result;
if (inputType == Type.STRING || inputType == Type.ELEMENT || inputType == Type.DOCUMENT) {
try {
result = new StringValue(Hash.hashString(args[0].getStringValue(), hashAlgorithm, encoding));
result = new StringValue(Hash.hashString(args[0].getStringValue(), hashAlgorithm, provider, encoding));
} catch (CryptoException e) {
throw new EXpathCryptoException(this, e.getCryptoError());
}
} else if (inputType == Type.BASE64_BINARY || inputType == Type.HEX_BINARY) {
try {
final BinaryValue binaryValue = (BinaryValue) args[0].itemAt(0);
try (final InputStream is = binaryValue.getInputStream()) {
result = new StringValue(Hash.hashBinary(is, hashAlgorithm, encoding));
result = new StringValue(Hash.hashBinary(is, hashAlgorithm, provider, encoding));
}
} catch (CryptoException e) {
throw new EXpathCryptoException(this, e.getCryptoError());
Expand All @@ -104,4 +186,4 @@ public Sequence eval(final Sequence[] args, final Sequence contextSequence) thro

return result;
}
}
}