Skip to content

Commit 1b06acb

Browse files
committed
[feature] Facility for listing providers and algorithms
1 parent 1132fd8 commit 1b06acb

File tree

2 files changed

+103
-19
lines changed

2 files changed

+103
-19
lines changed

src/main/java/ro/kuberam/libs/java/crypto/CryptoError.java

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,22 +21,22 @@
2121

2222
public enum CryptoError {
2323

24-
NoSuchAlgorithmException("crypto:unknown-algorithm", "The specified algorithm is not supported."),
24+
UNKNOWN_ALGORITH("crypto:unknown-algorithm", "The specified algorithm is not supported."),
25+
UNKNOWN_PROVIDER("crypto:unknown-provider", "The specified provider is not available."),
2526
SIGNATURE_TYPE("crypto:signature-type", "The specified signature type is not supported."),
2627
UNREADABLE_KEYSTORE("crypto:unreadable-keystore", "I/O error while reading keystore, or the password is incorrect."),
2728
DENIED_KEYSTORE("crypto:denied-keystore", "Permission denied to read keystore."),
2829
KEYSTORE_URL("crypto:keystore-url", "The keystore URL is invalid."),
29-
KeyStoreException("crypto:keystore-type", "The keystore type is not supported."),
30+
KEYSTORE_TYPE("crypto:keystore-type", "The keystore type is not supported."),
3031
ALIAS_KEY("crypto:alias-key", "Cannot find key for alias in given keystore."),
3132
SIGNATURE_ELEMENT("crypto:signature-element", "Cannot find Signature element."),
32-
NoSuchPaddingException("crypto:inexistent-padding", "No such padding."),
33-
BadPaddingException("crypto:incorrect-padding", "Incorrect padding."),
33+
INEXISTENT_PADDING("crypto:inexistent-padding", "No such padding."),
34+
INCORRECT_PADDING("crypto:incorrect-padding", "Incorrect padding."),
3435
ENCRYPTION_TYPE("crypto:encryption-type", "The encryption type is not supported."),
35-
InvalidKeySpecException("crypto:invalid-crypto-key", "The cryptographic key is invalid."),
36-
InvalidKeyException("crypto:invalid-crypto-key", "The cryptographic key is invalid."),
37-
IllegalBlockSizeException("crypto:block-size", "Illegal block size."),
36+
INVALID_CRYPTO_KEY("crypto:invalid-crypto-key", "The cryptographic key is invalid."),
37+
BLOCK_SIZE("crypto:block-size", "Illegal block size."),
3838
DECRYPTION_TYPE("crypto:decryption-type", "The decryption type is not supported."),
39-
NoSuchProviderException("crypto:no-provider", "The provider is not set."),
39+
NO_PROVIDER("crypto:no-provider", "The provider is not set."),
4040
INPUT_RESOURCES("crypto.input-resources", "The 'enveloped' and 'enveloping' signatures have to be applied to only one resource."),
4141
INCORRECT_INITIALIZATION_VECTOR("crypto:incorrect-initialization-vector", "The initialization vector is not correct");
4242

src/main/java/ro/kuberam/libs/java/crypto/digest/Hash.java

Lines changed: 95 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,7 @@
2222
import java.io.IOException;
2323
import java.io.InputStream;
2424
import java.nio.charset.StandardCharsets;
25-
import java.security.MessageDigest;
26-
import java.security.NoSuchAlgorithmException;
25+
import java.security.*;
2726
import java.util.Base64;
2827
import java.util.Optional;
2928
import javax.annotation.Nullable;
@@ -47,16 +46,20 @@ public class Hash {
4746
private static final Logger LOG = LoggerFactory.getLogger(Hash.class);
4847

4948
public static String hashString(final String data, final String algorithm) throws CryptoException {
50-
return hashString(data, algorithm, null);
49+
return hashString(data, algorithm, null, null);
5150
}
5251

53-
public static String hashString(final String data, final String algorithm, final @Nullable String format)
52+
public static String hashString(final String data, final String algorithm, @Nullable final String provider) throws CryptoException {
53+
return hashString(data, algorithm, provider, null);
54+
}
55+
56+
public static String hashString(final String data, final String algorithm, @Nullable final String provider, final @Nullable String format)
5457
throws CryptoException {
5558

5659
// TODO: validate the format
5760
final String actualFormat = Optional.ofNullable(format).filter(str -> !str.isEmpty()).orElse("base64");
5861

59-
final MessageDigest messageDigester = getMessageDigester(algorithm);
62+
final MessageDigest messageDigester = getMessageDigester(algorithm, provider);
6063
messageDigester.update(data.getBytes(StandardCharsets.UTF_8));
6164

6265
final byte[] resultBytes = messageDigester.digest();
@@ -70,17 +73,22 @@ public static String hashString(final String data, final String algorithm, final
7073

7174
public static String hashBinary(final InputStream data, final String algorithm)
7275
throws CryptoException, IOException {
73-
return hashBinary(data, algorithm, null);
76+
return hashBinary(data, algorithm, null, null);
77+
}
78+
79+
public static String hashBinary(final InputStream data, final String algorithm, @Nullable final String provider)
80+
throws CryptoException, IOException {
81+
return hashBinary(data, algorithm, provider, null);
7482
}
7583

76-
public static String hashBinary(final InputStream data, final String algorithm, @Nullable final String format)
84+
public static String hashBinary(final InputStream data, final String algorithm, @Nullable final String provider, @Nullable final String format)
7785
throws CryptoException, IOException {
7886

7987
// TODO: validate the format
8088
final String actualFormat = Optional.ofNullable(format).filter(str -> !str.isEmpty()).orElse("base64");
8189

8290
final byte[] resultBytes;
83-
final MessageDigest messageDigester = getMessageDigester(algorithm);
91+
final MessageDigest messageDigester = getMessageDigester(algorithm, provider);
8492

8593
final byte[] buf = new byte[Buffer.TRANSFER_SIZE];
8694
int read = -1;
@@ -100,11 +108,87 @@ public static String hashBinary(final InputStream data, final String algorithm,
100108
return result;
101109
}
102110

103-
private static MessageDigest getMessageDigester(final String algorithm) throws CryptoException {
111+
private static MessageDigest getMessageDigester(final String algorithm, @Nullable final String provider) throws CryptoException {
104112
try {
105-
return MessageDigest.getInstance(algorithm);
106-
} catch (NoSuchAlgorithmException e) {
113+
if (provider != null) {
114+
return MessageDigest.getInstance(algorithm, provider);
115+
} else {
116+
return MessageDigest.getInstance(algorithm);
117+
}
118+
} catch (final NoSuchAlgorithmException e) {
107119
throw new CryptoException(CryptoError.NoSuchAlgorithmException, e);
120+
} catch (final NoSuchProviderException e) {
121+
throw new CryptoException(CryptoError.UNKNOWN_PROVIDER, e);
108122
}
109123
}
124+
125+
/**
126+
* Returns a list of security providers which
127+
* offer hash services.
128+
*
129+
* @return the names of the security providers which
130+
* offer hash services.
131+
*/
132+
public static List<String> listProviders() {
133+
final List<String> hashProviders = new ArrayList<>();
134+
135+
final Provider[] providers = Security.getProviders();
136+
for (final Provider provider : providers) {
137+
final Set<Provider.Service> services = provider.getServices();
138+
for (final Provider.Service service : services) {
139+
if (service.getType().equals("MessageDigest")) {
140+
hashProviders.add(provider.getName());
141+
break;
142+
}
143+
}
144+
}
145+
146+
return hashProviders;
147+
}
148+
149+
/**
150+
* Returns a Map of all hash services from each
151+
* security provider.
152+
*
153+
* @return a map from key: `service provider name` to value: `algorithm name(s)`.
154+
*/
155+
public static Map<String, Set<String>> listAlgorithms() {
156+
final Map<String, Set<String>> algorithms = new HashMap<>();
157+
158+
final Provider[] providers = Security.getProviders();
159+
for (final Provider provider : providers) {
160+
final Set<Provider.Service> services = provider.getServices();
161+
for (final Provider.Service service : services) {
162+
if (service.getType().equals("MessageDigest")) {
163+
164+
final Set<String> providerAlgs = algorithms.computeIfAbsent(provider.getName(), k -> new HashSet<>());
165+
providerAlgs.add(service.getAlgorithm());
166+
}
167+
}
168+
}
169+
170+
return algorithms;
171+
}
172+
173+
/**
174+
* Returns a Map of all hash services from a
175+
* security provider.
176+
*
177+
* @param providerName the name of the security provider.
178+
*
179+
* @return the names of the algorithms provided by the security provider.
180+
*/
181+
public static Set<String> listAlgorithms(final String providerName) {
182+
final Set<String> algorithms = new HashSet<>();
183+
184+
final Provider provider = Security.getProvider(providerName);
185+
final Set<Provider.Service> services = provider.getServices();
186+
for (final Provider.Service service : services) {
187+
if (service.getType().equals("MessageDigest")) {
188+
algorithms.add(service.getAlgorithm());
189+
}
190+
}
191+
192+
return algorithms;
193+
}
110194
}

0 commit comments

Comments
 (0)