Skip to content

Commit ab3db33

Browse files
committed
JNI/JCE: add AES and DESede SecretKeyFactory and SecretKey support to wolfJCE
1 parent 87c7bfb commit ab3db33

File tree

7 files changed

+1183
-8
lines changed

7 files changed

+1183
-8
lines changed

scripts/infer.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ infer --fail-on-issue run -- javac \
100100
src/main/java/com/wolfssl/provider/jce/WolfCryptProvider.java \
101101
src/main/java/com/wolfssl/provider/jce/WolfCryptPssParameters.java \
102102
src/main/java/com/wolfssl/provider/jce/WolfCryptRandom.java \
103+
src/main/java/com/wolfssl/provider/jce/WolfCryptSecretKey.java \
103104
src/main/java/com/wolfssl/provider/jce/WolfCryptSecretKeyFactory.java \
104105
src/main/java/com/wolfssl/provider/jce/WolfCryptSignature.java \
105106
src/main/java/com/wolfssl/provider/jce/WolfCryptUtil.java \

src/main/java/com/wolfssl/provider/jce/WolfCryptProvider.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -484,6 +484,14 @@ private void registerServices() {
484484
"com.wolfssl.provider.jce.WolfCryptSecretKeyFactory$wcPBKDF2WithHmacSHA3_512");
485485
}
486486
}
487+
if (FeatureDetect.AesEnabled()) {
488+
put("SecretKeyFactory.AES",
489+
"com.wolfssl.provider.jce.WolfCryptSecretKeyFactory$wcAES");
490+
}
491+
if (FeatureDetect.Des3Enabled() && !Fips.enabled) {
492+
put("SecretKeyFactory.DESede",
493+
"com.wolfssl.provider.jce.WolfCryptSecretKeyFactory$wcDESede");
494+
}
487495

488496
/* KeyFactory */
489497
if (FeatureDetect.EccEnabled()) {
Lines changed: 240 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,240 @@
1+
/* WolfCryptSecretKey.java
2+
*
3+
* Copyright (C) 2006-2025 wolfSSL Inc.
4+
*
5+
* This file is part of wolfSSL.
6+
*
7+
* wolfSSL is free software; you can redistribute it and/or modify
8+
* it under the terms of the GNU General Public License as published by
9+
* the Free Software Foundation; either version 2 of the License, or
10+
* (at your option) any later version.
11+
*
12+
* wolfSSL is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
* GNU General Public License for more details.
16+
*
17+
* You should have received a copy of the GNU General Public License
18+
* along with this program; if not, write to the Free Software
19+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
20+
*/
21+
22+
package com.wolfssl.provider.jce;
23+
24+
import java.util.Arrays;
25+
import java.util.Objects;
26+
import java.security.InvalidKeyException;
27+
import javax.crypto.SecretKey;
28+
29+
import com.wolfssl.wolfcrypt.Aes;
30+
import com.wolfssl.wolfcrypt.Des3;
31+
32+
/**
33+
* wolfCrypt SecretKey implementation for symmetric algorithms.
34+
*
35+
* Supports AES and 3DES/DESede algorithms with key size validation.
36+
*/
37+
public class WolfCryptSecretKey implements SecretKey {
38+
39+
private static final long serialVersionUID = 1L;
40+
41+
/** Encoded key byte array */
42+
private byte[] encoded = null;
43+
44+
/** Key algorithm name */
45+
private String algorithm = null;
46+
47+
/** Has object been destroyed or not */
48+
private boolean destroyed = false;
49+
50+
/**
51+
* Create new WolfCryptSecretKey object.
52+
*
53+
* @param algorithm key algorithm name ("AES", "DESede")
54+
* @param encoded encoded key byte array
55+
*
56+
* @throws InvalidKeyException if algorithm is null/empty,
57+
* encoded is null/zero length, or key size is invalid
58+
*/
59+
public WolfCryptSecretKey(String algorithm, byte[] encoded)
60+
throws InvalidKeyException {
61+
62+
if (algorithm == null || algorithm.isEmpty()) {
63+
throw new InvalidKeyException(
64+
"Algorithm String cannot be null or empty");
65+
}
66+
67+
if (encoded == null || encoded.length == 0) {
68+
throw new InvalidKeyException(
69+
"Encoded key cannot be null or zero length");
70+
}
71+
72+
/* Validate key size based on algorithm. Sanitize matching wolfCrypt
73+
* aes.c and des3.c input sizes. */
74+
if (algorithm.equalsIgnoreCase("AES")) {
75+
if (encoded.length != Aes.KEY_SIZE_128 &&
76+
encoded.length != Aes.KEY_SIZE_192 &&
77+
encoded.length != Aes.KEY_SIZE_256) {
78+
throw new InvalidKeyException(
79+
"AES key must be 16, 24, or 32 bytes, got: " +
80+
encoded.length);
81+
}
82+
}
83+
else if (algorithm.equalsIgnoreCase("DESede") ||
84+
algorithm.equalsIgnoreCase("TripleDES")) {
85+
if (encoded.length != Des3.KEY_SIZE) {
86+
throw new InvalidKeyException(
87+
"DESede key must be 24 bytes, got: " + encoded.length);
88+
}
89+
}
90+
else {
91+
throw new InvalidKeyException(
92+
"Unsupported algorithm: " + algorithm);
93+
}
94+
95+
this.algorithm = algorithm;
96+
this.encoded = encoded.clone();
97+
}
98+
99+
/**
100+
* Check if this object has been destroyed with destroy().
101+
* Must be called from synchronized context.
102+
*
103+
* @throws IllegalStateException if object has been destroyed
104+
*/
105+
private void checkDestroyed()
106+
throws IllegalStateException {
107+
108+
if (this.destroyed) {
109+
throw new IllegalStateException(
110+
"SecretKey has been destroyed");
111+
}
112+
}
113+
114+
/**
115+
* Return algorithm String representing this SecretKey.
116+
*
117+
* @return algorithm string matching this object
118+
*
119+
* @throws IllegalStateException if object has been destroyed
120+
*/
121+
@Override
122+
public synchronized String getAlgorithm() {
123+
124+
checkDestroyed();
125+
126+
return this.algorithm;
127+
}
128+
129+
/**
130+
* Return encoding format for this SecretKey.
131+
*
132+
* @return encoding format string, will be "RAW" for this object
133+
*
134+
* @throws IllegalStateException if object has been destroyed
135+
*/
136+
@Override
137+
public synchronized String getFormat() {
138+
139+
checkDestroyed();
140+
141+
return "RAW";
142+
}
143+
144+
/**
145+
* Return encoded byte array of this SecretKey.
146+
*
147+
* @return encoded byte array
148+
*
149+
* @throws IllegalStateException if object has been destroyed
150+
*/
151+
@Override
152+
public synchronized byte[] getEncoded() {
153+
154+
checkDestroyed();
155+
156+
return this.encoded.clone();
157+
}
158+
159+
/**
160+
* Destroy this object.
161+
*
162+
* Zeroize key bytes contained in this object and mark it as unusable.
163+
*/
164+
@Override
165+
public synchronized void destroy() {
166+
167+
if (this.encoded != null) {
168+
Arrays.fill(this.encoded, (byte)0);
169+
this.encoded = null;
170+
}
171+
172+
this.algorithm = null;
173+
this.destroyed = true;
174+
}
175+
176+
/**
177+
* Return if this object has been destroyed.
178+
*
179+
* Object can be destroyed by calling destroy(), which will zeroize
180+
* internal buffers for this object.
181+
*
182+
* @return true if object has been destroyed, otherwise false
183+
*/
184+
@Override
185+
public synchronized boolean isDestroyed() {
186+
return this.destroyed;
187+
}
188+
189+
@Override
190+
public synchronized int hashCode() {
191+
checkDestroyed();
192+
return Arrays.hashCode(encoded);
193+
}
194+
195+
@Override
196+
public synchronized boolean equals(Object obj) {
197+
198+
byte[] sKeyEncoded = null;
199+
byte[] thisEncoded = null;
200+
SecretKey sKey;
201+
202+
checkDestroyed();
203+
204+
if (obj == this) {
205+
return true;
206+
}
207+
208+
if (!(obj instanceof SecretKey)) {
209+
return false;
210+
}
211+
sKey = (SecretKey)obj;
212+
213+
try {
214+
sKeyEncoded = sKey.getEncoded();
215+
thisEncoded = getEncoded();
216+
} catch (Exception e) {
217+
/* If encoding fails for either key, cannot be equal */
218+
return false;
219+
}
220+
221+
if (sKeyEncoded == null || thisEncoded == null) {
222+
return false;
223+
}
224+
225+
if (!Arrays.equals(sKeyEncoded, thisEncoded)) {
226+
return false;
227+
}
228+
229+
if (!Objects.equals(sKey.getAlgorithm(), getAlgorithm())) {
230+
return false;
231+
}
232+
233+
if (!Objects.equals(sKey.getFormat(), getFormat())) {
234+
return false;
235+
}
236+
237+
return true;
238+
}
239+
}
240+

0 commit comments

Comments
 (0)