Skip to content

Commit adf69dd

Browse files
committed
JCE: add optional KEK caching to WolfSSLKeyStore for performance
1 parent fd03d2c commit adf69dd

File tree

7 files changed

+1434
-32
lines changed

7 files changed

+1434
-32
lines changed

README_JCE.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ file for JCE provider customization:
3636
| --- | --- | --- | --- |
3737
| wolfjce.wks.iterationCount | 210,000 | Numeric | PBKDF2 iteration count (10,000 minimum) |
3838
| wolfjce.wks.maxCertChainLength | 100 | Integer | Max cert chain length |
39+
| wolfjce.keystore.kekCacheEnabled | false | true | Enable KEK caching in WKS KeyStore for performance |
40+
| wolfjce.keystore.kekCacheTtlSec | 300 | Integer | KEK cache TTL in seconds (1 second minimum) |
3941
| wolfjce.mapJKStoWKS | UNSET | true | Register fake JKS KeyStore service mapped to WKS |
4042
| wolfjce.mapPKCS12toWKS | UNSET | true | Register fake PKCS12 KeyStore service mapped to WKS |
4143

@@ -71,6 +73,32 @@ WolfCryptProvider prov = (WolfCryptProvider)Security.getProvider("wolfJCE");
7173
prov.refreshServices();
7274
```
7375

76+
**wolfjce.keystore.kekCacheEnabled** - this Security property enables KEK (Key
77+
Encryption Key) caching in the WKS KeyStore to improve performance when making
78+
repeated `getKey()` calls. When disabled (default), each `getKey()` call
79+
performs full PBKDF2 key derivation. When enabled, derived keys are cached in
80+
memory with configurable TTL. The cache is automatically cleared on entry
81+
deletion, overwrite, KeyStore reload, and TTL expiration. For manual cleanup,
82+
call `clearCache()` on the KeyStore instance:
83+
84+
```
85+
/* Enable KEK caching with 10 minute TTL */
86+
Security.setProperty("wolfjce.keystore.kekCacheEnabled", "true");
87+
Security.setProperty("wolfjce.keystore.kekCacheTtlSec", "600");
88+
89+
KeyStore store = KeyStore.getInstance("WKS", "wolfJCE");
90+
/* ... use KeyStore ... */
91+
92+
/* Explicitly clear cached keys when done (optional) */
93+
if (store instanceof com.wolfssl.provider.jce.WolfSSLKeyStore) {
94+
((com.wolfssl.provider.jce.WolfSSLKeyStore) store).clearCache();
95+
}
96+
```
97+
98+
Security Considerations: Cached derived keys remain in memory for the TTL
99+
duration. Only enable in trusted environments where performance benefits
100+
outweigh increased memory exposure.
101+
74102
#### System Property Support
75103

76104
The following Java System properties can be set on the command line or

docs/design/WolfSSLKeyStore.md

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ please reference the appropriate Security Policy or contact [email protected].
1313
| --- | --- | --- | --- |
1414
| `wolfjce.wks.iterationCount` | 210,000 | 10,000 | PBKDF2 iteration count |
1515
| `wolfjce.wks.maxCertChainLength` | 100 | N/A | Max cert chain length |
16+
| `wolfjce.keystore.kekCacheEnabled` | false | N/A | Enable KEK caching |
17+
| `wolfjce.keystore.kekCacheTtlSec` | 300 | 1 | Cache TTL in seconds |
1618

1719
## Notes on Algorithm and Security Properties
1820

@@ -229,6 +231,88 @@ there is no certificate so no certifiate or private key sanity checks are done.
229231
The same encrypt/decrypt process is shared between PrivateKey and SecretKey
230232
protection.
231233

234+
## KEK Caching for Performance
235+
236+
### Overview
237+
238+
Repeated calls to `getKey()` on the same KeyStore can be slow due to PBKDF2
239+
happening on each call to derive the Key Encryption Key (KEK) from the user
240+
password. PBKDF2 on each `getKey()` operation ensures that neither password
241+
nor KEK are stored in memory for more time that is needed to derive the KEK and
242+
decrypt the key entry. Although this is the most secure approach, PBKDF2 on
243+
each `getKey()` can be too performance expensive for some use cases.
244+
245+
The WKS KeyStore includes an optional KEK (Key Encryption Key) cache that
246+
stores derived keys in memory to avoid repeated PBKDF2 computations for the
247+
same password/salt combination. With KEK caching enabled, follow up calls
248+
to `getKey()` are much faster.
249+
250+
### Cache Design
251+
252+
The cache uses the following design:
253+
254+
- **Cache Key:** `SHA-256(passwordHash + kdfSalt + kdfIterations)`
255+
- `passwordHash` = `SHA-256(password)` - avoids storing plaintext passwords
256+
- Including `kdfSalt` and `kdfIterations` ensures different entries with
257+
the same password but different PBKDF2 parameters have separate cache keys
258+
- **Cache Entry:** Stores the derived key (KEK + HMAC key), password hash for
259+
verification, and TTL expiry timestamp
260+
- **Password Verification:** On cache hit, the provided password is hashed and
261+
compared against the stored hash.
262+
- **HMAC Verification:** Caching only occurs after successful HMAC verification
263+
to ensure data integrity is maintained.
264+
265+
### Security Properties
266+
267+
| Property | Default | Description |
268+
| --- | --- | --- |
269+
| `wolfjce.keystore.kekCacheEnabled` | `false` | Set to `"true"` to enable caching |
270+
| `wolfjce.keystore.kekCacheTtlSec` | `300` | Cache entry TTL in seconds (5 min) |
271+
272+
Example usage:
273+
274+
```java
275+
/* Enable KEK caching with 10 minute TTL */
276+
Security.setProperty("wolfjce.keystore.kekCacheEnabled", "true");
277+
Security.setProperty("wolfjce.keystore.kekCacheTtlSec", "600");
278+
```
279+
280+
### Cache Lifecycle
281+
282+
The cache is cleared in the following scenarios:
283+
- **Entry deletion:** When `deleteEntry()` is called on an encrypted entry
284+
- **Entry overwrite:** When `setKeyEntry()` overwrites an existing encrypted
285+
entry
286+
- **KeyStore reload:** When `load()` is called to load a new KeyStore
287+
- **TTL expiration:** Individual entries are removed when their TTL expires
288+
- **Explicit clear:** When `clearCache()` is called on the KeyStore instance
289+
- **Garbage collection:** Automatically when the KeyStore object is finalized
290+
291+
For deterministic cleanup of sensitive cached data, explicitly call
292+
`clearCache()` when the KeyStore is no longer needed:
293+
294+
```java
295+
KeyStore store = KeyStore.getInstance("WKS", "wolfJCE");
296+
/* ... use the KeyStore ... */
297+
298+
/* Explicitly clear cached keys before discarding */
299+
if (store instanceof com.wolfssl.provider.jce.WolfSSLKeyStore) {
300+
((com.wolfssl.provider.jce.WolfSSLKeyStore) store).clearCache();
301+
}
302+
```
303+
304+
### Security Considerations
305+
306+
1. **Memory exposure:** Cached derived keys remain in memory for the TTL
307+
duration. Only enable in trusted environments where performance benefits
308+
outweigh the increased memory exposure window.
309+
310+
### Performance Characteristics
311+
312+
- **First call:** Full PBKDF2 derivation to generate KEK from password
313+
- **Subsequent calls:** Cache lookup and verification
314+
- **Cache overhead:** ~1-2 SHA-256 operations per call for cache key computation
315+
232316
## Certificate Protection
233317

234318
A Certificate entry is stored into the KeyStore with the

0 commit comments

Comments
 (0)