Skip to content

Commit 667774c

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

File tree

7 files changed

+1180
-8
lines changed

7 files changed

+1180
-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: 237 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,237 @@
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+
/* Lock around destroyed */
51+
private transient final Object destroyedLock = new Object();
52+
53+
/**
54+
* Create new WolfCryptSecretKey object.
55+
*
56+
* @param algorithm key algorithm name ("AES", "DESede")
57+
* @param encoded encoded key byte array
58+
*
59+
* @throws InvalidKeyException if algorithm is null/empty,
60+
* encoded is null/zero length, or key size is invalid
61+
*/
62+
public WolfCryptSecretKey(String algorithm, byte[] encoded)
63+
throws InvalidKeyException {
64+
65+
if (algorithm == null || algorithm.isEmpty()) {
66+
throw new InvalidKeyException(
67+
"Algorithm String cannot be null or empty");
68+
}
69+
70+
if (encoded == null || encoded.length == 0) {
71+
throw new InvalidKeyException(
72+
"Encoded key cannot be null or zero length");
73+
}
74+
75+
/* Validate key size based on algorithm. Sanitize matching wolfCrypt
76+
* aes.c and des3.c input sizes. */
77+
if (algorithm.equalsIgnoreCase("AES")) {
78+
if (encoded.length != Aes.KEY_SIZE_128 &&
79+
encoded.length != Aes.KEY_SIZE_192 &&
80+
encoded.length != Aes.KEY_SIZE_256) {
81+
throw new InvalidKeyException(
82+
"AES key must be 16, 24, or 32 bytes, got: " +
83+
encoded.length);
84+
}
85+
}
86+
else if (algorithm.equalsIgnoreCase("DESede") ||
87+
algorithm.equalsIgnoreCase("TripleDES")) {
88+
if (encoded.length != Des3.KEY_SIZE) {
89+
throw new InvalidKeyException(
90+
"DESede key must be 24 bytes, got: " + encoded.length);
91+
}
92+
}
93+
else {
94+
throw new InvalidKeyException(
95+
"Unsupported algorithm: " + algorithm);
96+
}
97+
98+
this.algorithm = algorithm;
99+
this.encoded = encoded.clone();
100+
}
101+
102+
/**
103+
* Check if this object has been destroyed with destroy().
104+
*
105+
* @throws IllegalStateException if object has been destroyed
106+
*/
107+
private void checkDestroyed()
108+
throws IllegalStateException {
109+
110+
synchronized (destroyedLock) {
111+
if (this.destroyed) {
112+
throw new IllegalStateException(
113+
"SecretKey has been destroyed");
114+
}
115+
}
116+
}
117+
118+
/**
119+
* Return algorithm String representing this SecretKey.
120+
*
121+
* @return algorithm string matching this object
122+
*
123+
* @throws IllegalStateException if object has been destroyed
124+
*/
125+
@Override
126+
public synchronized String getAlgorithm() {
127+
128+
checkDestroyed();
129+
130+
return this.algorithm;
131+
}
132+
133+
/**
134+
* Return encoding format for this SecretKey.
135+
*
136+
* @return encoding format string, will be "RAW" for this object
137+
*
138+
* @throws IllegalStateException if object has been destroyed
139+
*/
140+
@Override
141+
public synchronized String getFormat() {
142+
143+
checkDestroyed();
144+
145+
return "RAW";
146+
}
147+
148+
/**
149+
* Return encoded byte array of this SecretKey.
150+
*
151+
* @return encoded byte array
152+
*
153+
* @throws IllegalStateException if object has been destroyed
154+
*/
155+
@Override
156+
public synchronized byte[] getEncoded() {
157+
158+
checkDestroyed();
159+
160+
return this.encoded.clone();
161+
}
162+
163+
/**
164+
* Destroy this object.
165+
*
166+
* Zeroize key bytes contained in this object and mark it as unusable.
167+
*/
168+
@Override
169+
public synchronized void destroy() {
170+
synchronized (destroyedLock) {
171+
if (this.encoded != null) {
172+
Arrays.fill(this.encoded, (byte)0);
173+
this.encoded = null;
174+
}
175+
this.algorithm = null;
176+
this.destroyed = true;
177+
}
178+
}
179+
180+
/**
181+
* Return if this object has been destroyed.
182+
*
183+
* Object can be destroyed by calling destroy(), which will zeroize
184+
* internal buffers for this object.
185+
*
186+
* @return true if object has been destroyed, otherwise false
187+
*/
188+
@Override
189+
public synchronized boolean isDestroyed() {
190+
synchronized (destroyedLock) {
191+
if (this.destroyed) {
192+
return true;
193+
}
194+
return false;
195+
}
196+
}
197+
198+
@Override
199+
public synchronized int hashCode() {
200+
checkDestroyed();
201+
return Arrays.hashCode(encoded);
202+
}
203+
204+
@Override
205+
public synchronized boolean equals(Object obj) {
206+
207+
SecretKey sKey = null;
208+
209+
synchronized (destroyedLock) {
210+
checkDestroyed();
211+
212+
if (obj == this) {
213+
return true;
214+
}
215+
216+
if (!(obj instanceof SecretKey)) {
217+
return false;
218+
}
219+
sKey = (SecretKey)obj;
220+
221+
if (!Arrays.equals(sKey.getEncoded(), getEncoded())) {
222+
return false;
223+
}
224+
225+
if (!Objects.equals(sKey.getAlgorithm(), getAlgorithm())) {
226+
return false;
227+
}
228+
229+
if (!Objects.equals(sKey.getFormat(), getFormat())) {
230+
return false;
231+
}
232+
233+
return true;
234+
}
235+
}
236+
}
237+

0 commit comments

Comments
 (0)