Skip to content

Commit 35dac8d

Browse files
committed
[feature] Functions for listing hash providers and algorithms and specifying them when hashing
1 parent c6b9d23 commit 35dac8d

File tree

3 files changed

+102
-16
lines changed

3 files changed

+102
-16
lines changed

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@
9292

9393
<properties>
9494
<package.title>EXPath Cryptographic Module Implementation</package.title>
95-
<crypto.java.lib.version>1.8.0</crypto.java.lib.version>
95+
<crypto.java.lib.version>1.8.1-SNAPSHOT</crypto.java.lib.version>
9696
<exist.version>5.3.0</exist.version>
9797
<crypto.module.ns>http://expath.org/ns/crypto</crypto.module.ns>
9898
<crypto.module.java.class>org.expath.exist.crypto.ExistExpathCryptoModule</crypto.module.java.class>

src/main/java/org/expath/exist/crypto/ExistExpathCryptoModule.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,11 +57,15 @@ public class ExistExpathCryptoModule extends AbstractInternalModule {
5757

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

60-
private final static FunctionDef[] functions = functionDefs(functionDefs(HashFunction.class, HashFunction.FS_HASH),
60+
private final static FunctionDef[] functions = functionDefs(
61+
functionDefs(HashFunction.class, HashFunction.FS_HASH),
62+
functionDefs(HashFunction.class, HashFunction.FS_HASH_PROVIDERS),
63+
functionDefs(HashFunction.class, HashFunction.FS_HASH_ALGORITHMS),
6164
functionDefs(HmacFunction.class, HmacFunction.FS_HMAC),
6265
functionDefs(GenerateSignatureFunction.class, GenerateSignatureFunction.FS_GENERATE_SIGNATURE),
6366
functionDefs(ValidateSignatureFunction.class, ValidateSignatureFunction.FS_VALIDATE_SIGNATURE),
64-
functionDefs(EncryptionFunctions.class, EncryptionFunctions.FS_ENCRYPT, EncryptionFunctions.FS_DECRYPT));
67+
functionDefs(EncryptionFunctions.class, EncryptionFunctions.FS_ENCRYPT, EncryptionFunctions.FS_DECRYPT)
68+
);
6569

6670
public ExistExpathCryptoModule(final Map<String, List<? extends Object>> parameters) throws Exception {
6771
super(functions, parameters);

src/main/java/org/expath/exist/crypto/digest/HashFunction.java

Lines changed: 95 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -27,16 +27,15 @@
2727

2828
import java.io.IOException;
2929
import java.io.InputStream;
30+
import java.util.Map;
31+
import java.util.Set;
3032

3133
import org.exist.xquery.BasicFunction;
3234
import org.exist.xquery.FunctionSignature;
3335
import org.exist.xquery.XPathException;
3436
import org.exist.xquery.XQueryContext;
35-
import org.exist.xquery.value.BinaryValue;
36-
import org.exist.xquery.value.FunctionParameterSequenceType;
37-
import org.exist.xquery.value.Sequence;
38-
import org.exist.xquery.value.StringValue;
39-
import org.exist.xquery.value.Type;
37+
import org.exist.xquery.functions.map.MapType;
38+
import org.exist.xquery.value.*;
4039
import org.expath.exist.crypto.EXpathCryptoException;
4140

4241
import org.slf4j.Logger;
@@ -46,6 +45,7 @@
4645

4746
import static org.exist.xquery.FunctionDSL.*;
4847
import static org.expath.exist.crypto.ExistExpathCryptoModule.*;
48+
import static org.expath.exist.crypto.ExistExpathCryptoModule.functionSignature;
4949

5050
public class HashFunction extends BasicFunction {
5151

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

60-
public static final FunctionSignature FS_HASH[] = functionSignatures(FS_HASH_NAME,
61-
"resulting hash value, as string.", returnsOptMany(Type.BYTE),
62-
arities(arity(FS_HASH_PARAM_DATA, FS_HASH_PARAM_ALGORITHM),
63-
arity(FS_HASH_PARAM_DATA, FS_HASH_PARAM_ALGORITHM, param("encoding", Type.STRING,
64-
"The encoding of the output. The legal values are \"hex\" and \"base64\". The default value is \"base64\"."))));
62+
public static final FunctionSignature FS_HASH[] = functionSignatures(
63+
FS_HASH_NAME,
64+
"resulting hash value, as string.",
65+
returnsOptMany(Type.BYTE),
66+
arities(
67+
arity(
68+
FS_HASH_PARAM_DATA,
69+
FS_HASH_PARAM_ALGORITHM
70+
),
71+
arity(
72+
FS_HASH_PARAM_DATA,
73+
FS_HASH_PARAM_ALGORITHM,
74+
param("encoding", Type.STRING, "The encoding of the output. The legal values are \"hex\" and \"base64\". The default value is \"base64\".")
75+
),
76+
arity(
77+
FS_HASH_PARAM_DATA,
78+
FS_HASH_PARAM_ALGORITHM,
79+
param("encoding", Type.STRING, "The encoding of the output. The legal values are \"hex\" and \"base64\". The default value is \"base64\"."),
80+
FS_HASH_PARAM_PROVIDER
81+
)
82+
)
83+
);
84+
85+
private static final String FS_HASH_PROVIDERS_NAME = "hash-providers";
86+
public static final FunctionSignature FS_HASH_PROVIDERS = functionSignature(
87+
FS_HASH_PROVIDERS_NAME,
88+
"Gets the names of all the hash providers",
89+
returnsOptMany(Type.STRING)
90+
);
91+
92+
private static final String FS_HASH_ALGORITHMS_NAME = "hash-algorithms";
93+
public static final FunctionSignature FS_HASH_ALGORITHMS[] = {
94+
functionSignature(
95+
FS_HASH_ALGORITHMS_NAME,
96+
"Gets the names of all the hash providers",
97+
returnsOptMany(Type.STRING)
98+
),
99+
functionSignature(
100+
FS_HASH_ALGORITHMS_NAME,
101+
"Gets the names of all the hash providers",
102+
returns(Type.MAP),
103+
param("provider-name", Type.STRING, "The name of the hash provider.")
104+
)
105+
};
65106

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

114+
if (isCalledAs(FS_HASH_NAME)) {
115+
return hash(args);
116+
117+
} else if (isCalledAs(FS_HASH_PROVIDERS_NAME)) {
118+
final ValueSequence providers = new ValueSequence();
119+
for (final String provider : Hash.listProviders()) {
120+
providers.add(new StringValue(provider));
121+
}
122+
return providers;
123+
124+
} else if (isCalledAs(FS_HASH_ALGORITHMS_NAME)) {
125+
if (args.length == 1) {
126+
final String providerName = args[0].getStringValue();
127+
final ValueSequence algorithmNames = new ValueSequence();
128+
for (final String algorithmName : Hash.listAlgorithms(providerName)) {
129+
algorithmNames.add(new StringValue(algorithmName));
130+
}
131+
return algorithmNames;
132+
133+
} else {
134+
final MapType mapType = new MapType(this.context);
135+
for(final Map.Entry<String, Set<String>> providerAlgorithms : Hash.listAlgorithms().entrySet()) {
136+
final ValueSequence algorithmNames = new ValueSequence();
137+
for (final String algorithmName : providerAlgorithms.getValue()) {
138+
algorithmNames.add(new StringValue(algorithmName));
139+
}
140+
mapType.add(new StringValue(providerAlgorithms.getKey()), algorithmNames);
141+
}
142+
return mapType;
143+
}
144+
} else {
145+
throw new XPathException(this, "Unknown function name");
146+
}
147+
}
148+
149+
private Sequence hash(final Sequence[] args) throws XPathException {
73150
final int inputType = args[0].itemAt(0).getType();
74151
final String hashAlgorithm = args[1].getStringValue();
75152
final String encoding;
@@ -78,20 +155,25 @@ public Sequence eval(final Sequence[] args, final Sequence contextSequence) thro
78155
} else {
79156
encoding = args[2].getStringValue().isEmpty() ? "base64" : args[2].getStringValue();
80157
}
158+
String provider = null;
159+
if (args.length == 4) {
160+
provider = args[3].getStringValue();
161+
}
162+
81163
LOG.debug("encoding = {}", encoding);
82164

83165
final Sequence result;
84166
if (inputType == Type.STRING || inputType == Type.ELEMENT || inputType == Type.DOCUMENT) {
85167
try {
86-
result = new StringValue(Hash.hashString(args[0].getStringValue(), hashAlgorithm, encoding));
168+
result = new StringValue(Hash.hashString(args[0].getStringValue(), hashAlgorithm, provider, encoding));
87169
} catch (CryptoException e) {
88170
throw new EXpathCryptoException(this, e.getCryptoError());
89171
}
90172
} else if (inputType == Type.BASE64_BINARY || inputType == Type.HEX_BINARY) {
91173
try {
92174
final BinaryValue binaryValue = (BinaryValue) args[0].itemAt(0);
93175
try (final InputStream is = binaryValue.getInputStream()) {
94-
result = new StringValue(Hash.hashBinary(is, hashAlgorithm, encoding));
176+
result = new StringValue(Hash.hashBinary(is, hashAlgorithm, provider, encoding));
95177
}
96178
} catch (CryptoException e) {
97179
throw new EXpathCryptoException(this, e.getCryptoError());
@@ -104,4 +186,4 @@ public Sequence eval(final Sequence[] args, final Sequence contextSequence) thro
104186

105187
return result;
106188
}
107-
}
189+
}

0 commit comments

Comments
 (0)