Skip to content

Commit b831d83

Browse files
committed
Support for PBES2, PBEKeyfactory, PBEKey and PBEParameters
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 b831d83

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)