Skip to content

Commit 589439b

Browse files
authored
Support for PBES2, PBEKeyfactory, PBEKey and PBEParameters (#910)
This update adds support for PBES2, PBEKeyFactory, PBEKey, and PBEParameters for PBE algorithms with Hmac and AES for OpenJCEPlus provider. Signed-off-by: Dev Agarwal <[email protected]>
1 parent 1941028 commit 589439b

21 files changed

+2513
-138
lines changed

JenkinsfilePerformance

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,7 @@ pipeline {
356356
'ibm.jceplus.jmh.MessageDigestBenchmark', \
357357
'ibm.jceplus.jmh.MessageDigestInstanceBenchmark', \
358358
'ibm.jceplus.jmh.MLDSABenchmark', \
359+
'ibm.jceplus.jmh.PBEBenchmark', \
359360
'ibm.jceplus.jmh.PBKDF2Benchmark', \
360361
'ibm.jceplus.jmh.RandomBenchmark', \
361362
'ibm.jceplus.jmh.RSAKeyGeneratorBenchmark', \

README.md

Lines changed: 194 additions & 137 deletions
Large diffs are not rendered by default.

src/main/java/com/ibm/crypto/plus/provider/OpenJCEPlus.java

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,14 @@ public final class OpenJCEPlus extends OpenJCEPlusProvider {
3232

3333
private static final String info = "OpenJCEPlus Provider implements the following:\n"
3434
+ "Algorithm parameter : AES, ChaCha20, ChaCha20-Poly1305, DESede, DiffieHellman, DSA, EC, XEC, GCM, CCM, OAEP, RSAPSS\n"
35+
+ " PBEWithHmacSHA1AndAES_128, PBEWithHmacSHA1AndAES_256, PBEWithHmacSHA224AndAES_128, PBEWithHmacSHA224AndAES_256\n"
36+
+ " PBEWithHmacSHA256AndAES_128, PBEWithHmacSHA256AndAES_256, PBEWithHmacSHA384AndAES_128, PBEWithHmacSHA384AndAES_256\n"
37+
+ " PBEWithHmacSHA512AndAES_128, PBEWithHmacSHA512AndAES_256\n"
3538
+ "Algorithm parameter generator : DiffieHellman, DSA, EC, XEC, GCM, CCM\n"
3639
+ "Cipher algorithms : AES, ChaCha20, ChaCha20-Poly1305, DESede, RSA\n"
40+
+ " PBEWithHmacSHA1AndAES_128, PBEWithHmacSHA1AndAES_256, PBEWithHmacSHA224AndAES_128, PBEWithHmacSHA224AndAES_256\n"
41+
+ " PBEWithHmacSHA256AndAES_128, PBEWithHmacSHA256AndAES_256, PBEWithHmacSHA384AndAES_128, PBEWithHmacSHA384AndAES_256\n"
42+
+ " PBEWithHmacSHA512AndAES_128, PBEWithHmacSHA512AndAES_256\n"
3743
+ "Key agreement algorithms : DiffieHellman, ECDH, XDH\n"
3844
+ "Key factory : DiffieHellman, DSA, EC, XEC, RSA, RSAPSS\n"
3945
+ "Key generator : AES, ChaCha20, DESede, HmacMD5, HmacSHA1, HmacSHA224,\n"
@@ -48,6 +54,9 @@ public final class OpenJCEPlus extends OpenJCEPlusProvider {
4854
+ "Message digest : MD5, SHA-1, SHA-224, SHA-256, SHA-384, SHA-512, SHA-512/224, SHA-512/256, SHA3-224, SHA3-256, SHA3-384, SHA3-512\n"
4955
+ "Secret key factory : AES, ChaCha20, DESede, PBKDF2WithHmacSHA1, PBKDF2WithHmacSHA224, PBKDF2WithHmacSHA256, PBKDF2WithHmacSHA384, PBKDF2WithHmacSHA512\n"
5056
+ " PBKDF2WithHmacSHA512/224, PBKDF2WithHmacSHA512/256\n"
57+
+ " PBEWithHmacSHA1AndAES_128, PBEWithHmacSHA1AndAES_256, PBEWithHmacSHA224AndAES_128, PBEWithHmacSHA224AndAES_256\n"
58+
+ " PBEWithHmacSHA256AndAES_128, PBEWithHmacSHA256AndAES_256, PBEWithHmacSHA384AndAES_128, PBEWithHmacSHA384AndAES_256\n"
59+
+ " PBEWithHmacSHA512AndAES_128, PBEWithHmacSHA512AndAES_256\n"
5160
+ "Secure random : HASHDRBG, SHA256DRBG, SHA512DRBG\n"
5261
+ "Signature algorithms : NONEwithDSA, SHA1withDSA, SHA224withDSA, SHA256withDSA,\n"
5362
+ " SHA3-224withDSA, SHA3-256withDSA, SHA3-384withDSA, SHA3-512withDSA,\n"
@@ -150,7 +159,47 @@ private void registerAlgorithms(Provider jce) {
150159
aliases = null;
151160
putService(new OpenJCEPlusService(jce, "AlgorithmParameters", "OAEP",
152161
"com.ibm.crypto.plus.provider.OAEPParameters", aliases));
162+
163+
aliases = null;
164+
putService(new OpenJCEPlusService(jce, "AlgorithmParameters", "PBEWithHmacSHA1AndAES_128",
165+
"com.ibm.crypto.plus.provider.PBES2Parameters$HmacSHA1AndAES_128", aliases));
166+
167+
aliases = null;
168+
putService(new OpenJCEPlusService(jce, "AlgorithmParameters", "PBEWithHmacSHA1AndAES_256",
169+
"com.ibm.crypto.plus.provider.PBES2Parameters$HmacSHA1AndAES_256", aliases));
170+
171+
aliases = null;
172+
putService(new OpenJCEPlusService(jce, "AlgorithmParameters", "PBEWithHmacSHA224AndAES_128",
173+
"com.ibm.crypto.plus.provider.PBES2Parameters$HmacSHA224AndAES_128", aliases));
174+
175+
aliases = null;
176+
putService(new OpenJCEPlusService(jce, "AlgorithmParameters", "PBEWithHmacSHA224AndAES_256",
177+
"com.ibm.crypto.plus.provider.PBES2Parameters$HmacSHA224AndAES_256", aliases));
178+
179+
aliases = null;
180+
putService(new OpenJCEPlusService(jce, "AlgorithmParameters", "PBEWithHmacSHA256AndAES_128",
181+
"com.ibm.crypto.plus.provider.PBES2Parameters$HmacSHA256AndAES_128", aliases));
182+
183+
aliases = null;
184+
putService(new OpenJCEPlusService(jce, "AlgorithmParameters", "PBEWithHmacSHA256AndAES_256",
185+
"com.ibm.crypto.plus.provider.PBES2Parameters$HmacSHA256AndAES_256", aliases));
186+
187+
aliases = null;
188+
putService(new OpenJCEPlusService(jce, "AlgorithmParameters", "PBEWithHmacSHA384AndAES_128",
189+
"com.ibm.crypto.plus.provider.PBES2Parameters$HmacSHA384AndAES_128", aliases));
153190

191+
aliases = null;
192+
putService(new OpenJCEPlusService(jce, "AlgorithmParameters", "PBEWithHmacSHA384AndAES_256",
193+
"com.ibm.crypto.plus.provider.PBES2Parameters$HmacSHA384AndAES_256", aliases));
194+
195+
aliases = null;
196+
putService(new OpenJCEPlusService(jce, "AlgorithmParameters", "PBEWithHmacSHA512AndAES_128",
197+
"com.ibm.crypto.plus.provider.PBES2Parameters$HmacSHA512AndAES_128", aliases));
198+
199+
aliases = null;
200+
putService(new OpenJCEPlusService(jce, "AlgorithmParameters", "PBEWithHmacSHA512AndAES_256",
201+
"com.ibm.crypto.plus.provider.PBES2Parameters$HmacSHA512AndAES_256", aliases));
202+
154203
/*aliases = null;
155204
putService(new OpenJCEPlusService(jce,
156205
"AlgorithmParameters",
@@ -265,6 +314,47 @@ private void registerAlgorithms(Provider jce) {
265314
putService(new OpenJCEPlusService(jce, "Cipher", "ChaCha20-Poly1305",
266315
"com.ibm.crypto.plus.provider.ChaCha20Poly1305Cipher", aliases));
267316

317+
aliases = null;
318+
putService(new OpenJCEPlusService(jce, "Cipher", "PBEWithHmacSHA1AndAES_128",
319+
"com.ibm.crypto.plus.provider.PBES2Core$HmacSHA1AndAES_128", aliases));
320+
321+
aliases = null;
322+
putService(new OpenJCEPlusService(jce, "Cipher", "PBEWithHmacSHA1AndAES_256",
323+
"com.ibm.crypto.plus.provider.PBES2Core$HmacSHA1AndAES_256", aliases));
324+
325+
aliases = null;
326+
putService(new OpenJCEPlusService(jce, "Cipher", "PBEWithHmacSHA224AndAES_128",
327+
"com.ibm.crypto.plus.provider.PBES2Core$HmacSHA224AndAES_128", aliases));
328+
329+
aliases = null;
330+
putService(new OpenJCEPlusService(jce, "Cipher", "PBEWithHmacSHA224AndAES_256",
331+
"com.ibm.crypto.plus.provider.PBES2Core$HmacSHA224AndAES_256", aliases));
332+
333+
aliases = null;
334+
putService(new OpenJCEPlusService(jce, "Cipher", "PBEWithHmacSHA256AndAES_128",
335+
"com.ibm.crypto.plus.provider.PBES2Core$HmacSHA256AndAES_128", aliases));
336+
337+
aliases = null;
338+
putService(new OpenJCEPlusService(jce, "Cipher", "PBEWithHmacSHA256AndAES_256",
339+
"com.ibm.crypto.plus.provider.PBES2Core$HmacSHA256AndAES_256", aliases));
340+
341+
aliases = null;
342+
putService(new OpenJCEPlusService(jce, "Cipher", "PBEWithHmacSHA384AndAES_128",
343+
"com.ibm.crypto.plus.provider.PBES2Core$HmacSHA384AndAES_128", aliases));
344+
345+
aliases = null;
346+
putService(new OpenJCEPlusService(jce, "Cipher", "PBEWithHmacSHA384AndAES_256",
347+
"com.ibm.crypto.plus.provider.PBES2Core$HmacSHA384AndAES_256", aliases));
348+
349+
aliases = null;
350+
putService(new OpenJCEPlusService(jce, "Cipher", "PBEWithHmacSHA512AndAES_128",
351+
"com.ibm.crypto.plus.provider.PBES2Core$HmacSHA512AndAES_128", aliases));
352+
353+
aliases = null;
354+
putService(new OpenJCEPlusService(jce, "Cipher", "PBEWithHmacSHA512AndAES_256",
355+
"com.ibm.crypto.plus.provider.PBES2Core$HmacSHA512AndAES_256", aliases));
356+
357+
268358
/* =======================================================================
269359
* Key agreement
270360
* =======================================================================
@@ -670,6 +760,47 @@ private void registerAlgorithms(Provider jce) {
670760
putService(new OpenJCEPlusService(jce, "SecretKeyFactory", "ChaCha20",
671761
"com.ibm.crypto.plus.provider.ChaCha20KeyFactory", aliases));
672762

763+
aliases = null;
764+
putService(new OpenJCEPlusService(jce, "SecretKeyFactory", "PBEWithHmacSHA1AndAES_128",
765+
"com.ibm.crypto.plus.provider.PBEKeyFactory$PBEWithHmacSHA1AndAES_128", aliases));
766+
767+
aliases = null;
768+
putService(new OpenJCEPlusService(jce, "SecretKeyFactory", "PBEWithHmacSHA1AndAES_256",
769+
"com.ibm.crypto.plus.provider.PBEKeyFactory$PBEWithHmacSHA1AndAES_256", aliases));
770+
771+
aliases = null;
772+
putService(new OpenJCEPlusService(jce, "SecretKeyFactory", "PBEWithHmacSHA224AndAES_128",
773+
"com.ibm.crypto.plus.provider.PBEKeyFactory$PBEWithHmacSHA224AndAES_128", aliases));
774+
775+
aliases = null;
776+
putService(new OpenJCEPlusService(jce, "SecretKeyFactory", "PBEWithHmacSHA224AndAES_256",
777+
"com.ibm.crypto.plus.provider.PBEKeyFactory$PBEWithHmacSHA224AndAES_256", aliases));
778+
779+
aliases = null;
780+
putService(new OpenJCEPlusService(jce, "SecretKeyFactory", "PBEWithHmacSHA256AndAES_128",
781+
"com.ibm.crypto.plus.provider.PBEKeyFactory$PBEWithHmacSHA256AndAES_128", aliases));
782+
783+
aliases = null;
784+
putService(new OpenJCEPlusService(jce, "SecretKeyFactory", "PBEWithHmacSHA256AndAES_256",
785+
"com.ibm.crypto.plus.provider.PBEKeyFactory$PBEWithHmacSHA256AndAES_256", aliases));
786+
787+
aliases = null;
788+
putService(new OpenJCEPlusService(jce, "SecretKeyFactory", "PBEWithHmacSHA384AndAES_128",
789+
"com.ibm.crypto.plus.provider.PBEKeyFactory$PBEWithHmacSHA384AndAES_128", aliases));
790+
791+
aliases = null;
792+
putService(new OpenJCEPlusService(jce, "SecretKeyFactory", "PBEWithHmacSHA384AndAES_256",
793+
"com.ibm.crypto.plus.provider.PBEKeyFactory$PBEWithHmacSHA384AndAES_256", aliases));
794+
795+
aliases = null;
796+
putService(new OpenJCEPlusService(jce, "SecretKeyFactory", "PBEWithHmacSHA512AndAES_128",
797+
"com.ibm.crypto.plus.provider.PBEKeyFactory$PBEWithHmacSHA512AndAES_128", aliases));
798+
799+
aliases = null;
800+
putService(new OpenJCEPlusService(jce, "SecretKeyFactory", "PBEWithHmacSHA512AndAES_256",
801+
"com.ibm.crypto.plus.provider.PBEKeyFactory$PBEWithHmacSHA512AndAES_256", aliases));
802+
803+
673804
/* =======================================================================
674805
* SecureRandom
675806
* =======================================================================
Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
/*
2+
* Copyright IBM Corp. 2025
3+
*
4+
* This code is free software; you can redistribute it and/or modify it
5+
* under the terms provided by IBM in the LICENSE file that accompanied
6+
* this code, including the "Classpath" Exception described therein.
7+
*/
8+
9+
package com.ibm.crypto.plus.provider;
10+
11+
import java.io.IOException;
12+
import java.io.InvalidObjectException;
13+
import java.lang.ref.Reference;
14+
import java.security.MessageDigest;
15+
import java.security.spec.InvalidKeySpecException;
16+
import java.util.Arrays;
17+
import java.util.Locale;
18+
import javax.crypto.SecretKey;
19+
import javax.crypto.spec.PBEKeySpec;
20+
21+
final class PBEKey implements SecretKey {
22+
23+
private static final long serialVersionUID = 9223372036854775807L;
24+
25+
private byte[] key;
26+
27+
private final String type;
28+
29+
private boolean destroyed = false;
30+
31+
private OpenJCEPlusProvider provider = null;
32+
33+
/**
34+
* Creates a PBE key from a given PBE key specification.
35+
*
36+
* @param keytype the given PBE key specification
37+
*/
38+
PBEKey(OpenJCEPlusProvider provider, PBEKeySpec keySpec, String keytype) throws InvalidKeySpecException {
39+
char[] passwd = keySpec.getPassword();
40+
41+
if (passwd == null || passwd.length == 0) {
42+
// Should allow an empty password.
43+
passwd = new char[0];
44+
}
45+
46+
for (char c : passwd) {
47+
if (Character.isISOControl(c))
48+
throw new InvalidKeySpecException("Invalid Password.");
49+
}
50+
51+
this.key = PBEUtil.encodePassword(passwd);
52+
Arrays.fill(passwd, '\0');
53+
type = keytype;
54+
this.provider = provider;
55+
}
56+
57+
public byte[] getEncoded() {
58+
try {
59+
return key.clone();
60+
} finally {
61+
// prevent this from being cleaned for the above block
62+
Reference.reachabilityFence(this);
63+
}
64+
}
65+
66+
public String getAlgorithm() {
67+
return type;
68+
}
69+
70+
public String getFormat() {
71+
return "RAW";
72+
}
73+
74+
@Override
75+
public int hashCode() {
76+
try {
77+
int retval = 0;
78+
for (int i = 1; i < this.key.length; i++) {
79+
retval += this.key[i] * i;
80+
}
81+
return(retval ^ getAlgorithm().toLowerCase(Locale.ENGLISH).hashCode());
82+
} finally {
83+
// prevent this from being cleaned for the above block
84+
Reference.reachabilityFence(this);
85+
}
86+
}
87+
88+
@Override
89+
public boolean equals(Object obj) {
90+
try {
91+
if (obj == this)
92+
return true;
93+
94+
SecretKey that;
95+
if (!(obj instanceof SecretKey))
96+
return false;
97+
that = (SecretKey) obj;
98+
99+
if (isDestroyed() || that.isDestroyed()) {
100+
return false;
101+
}
102+
103+
if (!(that.getAlgorithm().equalsIgnoreCase(type)))
104+
return false;
105+
106+
byte[] thatEncoded = that.getEncoded();
107+
boolean ret = MessageDigest.isEqual(this.key, thatEncoded);
108+
Arrays.fill(thatEncoded, (byte) 0x00);
109+
return ret;
110+
} finally {
111+
// prevent this from being cleaned for the above block
112+
Reference.reachabilityFence(this);
113+
}
114+
}
115+
116+
@Override
117+
public void destroy() {
118+
if (this.key != null) {
119+
Arrays.fill(this.key, (byte) 0x00);
120+
destroyed = true;
121+
}
122+
}
123+
124+
@Override
125+
public boolean isDestroyed() {
126+
return destroyed;
127+
}
128+
129+
/**
130+
* Restores the state of this object from the stream.
131+
*
132+
* @param s the {@code ObjectInputStream} from which data is read
133+
* @throws IOException if an I/O error occurs
134+
* @throws ClassNotFoundException if a serialized class cannot be loaded
135+
*/
136+
private void readObject(java.io.ObjectInputStream s)
137+
throws IOException, ClassNotFoundException
138+
{
139+
s.defaultReadObject();
140+
if (key == null) {
141+
throw new InvalidObjectException(
142+
"PBEKey couldn't be deserialized");
143+
}
144+
byte[] temp = key;
145+
key = temp.clone();
146+
Arrays.fill(temp, (byte) 0x00);
147+
148+
// Accept "\0" to signify "zero-length password with no terminator".
149+
if (!(key.length == 1 && key[0] == 0)) {
150+
for (int i = 0; i < key.length; i++) {
151+
if ((key[i] < '\u0020') || (key[i] > '\u007E')) {
152+
throw new InvalidObjectException(
153+
"PBEKey had non-ASCII chars");
154+
}
155+
}
156+
}
157+
}
158+
159+
160+
/**
161+
* Replace the PBE key to be serialized.
162+
*
163+
* @return the standard KeyRep object to be serialized
164+
*
165+
* @throws java.io.ObjectStreamException if a new object representing
166+
* this PBE key could not be created
167+
*/
168+
private Object writeReplace() throws java.io.ObjectStreamException {
169+
try {
170+
return new JCEPlusKeyRep(JCEPlusKeyRep.Type.SECRET,
171+
getAlgorithm(), getFormat(), getEncoded(), provider.getName());
172+
} finally {
173+
// prevent this from being cleaned for the above block
174+
Reference.reachabilityFence(this);
175+
}
176+
}
177+
178+
protected void finalize() throws Throwable {
179+
try {
180+
destroy();
181+
} finally {
182+
super.finalize();
183+
}
184+
}
185+
}

0 commit comments

Comments
 (0)