@@ -114,19 +114,18 @@ public void writeTo(StreamOutput out) throws IOException {
114
114
115
115
/** The oldest metadata format version that can be read. */
116
116
private static final int MIN_FORMAT_VERSION = 3 ;
117
- /** Legacy versions of the metadata written before the keystore data. */
118
- public static final int V2_VERSION = 2 ;
119
117
public static final int V3_VERSION = 3 ;
120
118
public static final int V4_VERSION = 4 ;
121
119
/** The version where lucene directory API changed from BE to LE. */
122
120
public static final int LE_VERSION = 5 ;
123
- public static final int CURRENT_VERSION = LE_VERSION ;
121
+ public static final int HIGHER_KDF_ITERATION_COUNT_VERSION = 6 ;
122
+ public static final int CURRENT_VERSION = HIGHER_KDF_ITERATION_COUNT_VERSION ;
124
123
125
124
/** The algorithm used to derive the cipher key from a password. */
126
125
private static final String KDF_ALGO = "PBKDF2WithHmacSHA512" ;
127
126
128
127
/** The number of iterations to derive the cipher key. */
129
- private static final int KDF_ITERS = 10000 ;
128
+ private static final int KDF_ITERS = 210000 ;
130
129
131
130
/**
132
131
* The number of bits for the cipher key.
@@ -155,6 +154,7 @@ public void writeTo(StreamOutput out) throws IOException {
155
154
// 3: FIPS compliant algos, ES 6.3
156
155
// 4: remove distinction between string/files, ES 6.8/7.1
157
156
// 5: Lucene directory API changed to LE, ES 8.0
157
+ // 6: increase KDF iteration count, ES 8.14
158
158
159
159
/** The metadata format version used to read the current keystore wrapper. */
160
160
private final int formatVersion ;
@@ -317,8 +317,8 @@ public boolean hasPassword() {
317
317
return hasPassword ;
318
318
}
319
319
320
- private static Cipher createCipher (int opmode , char [] password , byte [] salt , byte [] iv ) throws GeneralSecurityException {
321
- PBEKeySpec keySpec = new PBEKeySpec (password , salt , KDF_ITERS , CIPHER_KEY_BITS );
320
+ private static Cipher createCipher (int opmode , char [] password , byte [] salt , byte [] iv , int kdfIters ) throws GeneralSecurityException {
321
+ PBEKeySpec keySpec = new PBEKeySpec (password , salt , kdfIters , CIPHER_KEY_BITS );
322
322
SecretKeyFactory keyFactory = SecretKeyFactory .getInstance (KDF_ALGO );
323
323
SecretKey secretKey ;
324
324
try {
@@ -337,6 +337,11 @@ private static Cipher createCipher(int opmode, char[] password, byte[] salt, byt
337
337
return cipher ;
338
338
}
339
339
340
+ private static int getKdfIterationCountForVersion (int formatVersion ) {
341
+ // iteration count was increased in version 6; it was 10,000 in previous versions
342
+ return formatVersion < HIGHER_KDF_ITERATION_COUNT_VERSION ? 10000 : KDF_ITERS ;
343
+ }
344
+
340
345
/**
341
346
* Decrypts the underlying keystore data.
342
347
*
@@ -365,7 +370,7 @@ public void decrypt(char[] password) throws GeneralSecurityException, IOExceptio
365
370
throw new SecurityException ("Keystore has been corrupted or tampered with" , e );
366
371
}
367
372
368
- Cipher cipher = createCipher (Cipher .DECRYPT_MODE , password , salt , iv );
373
+ Cipher cipher = createCipher (Cipher .DECRYPT_MODE , password , salt , iv , getKdfIterationCountForVersion ( formatVersion ) );
369
374
try (
370
375
ByteArrayInputStream bytesStream = new ByteArrayInputStream (encryptedBytes );
371
376
CipherInputStream cipherStream = new CipherInputStream (bytesStream , cipher );
@@ -403,11 +408,11 @@ private static byte[] readByteArray(DataInput input) throws IOException {
403
408
}
404
409
405
410
/** Encrypt the keystore entries and return the encrypted data. */
406
- private byte [] encrypt (char [] password , byte [] salt , byte [] iv ) throws GeneralSecurityException , IOException {
411
+ private byte [] encrypt (char [] password , byte [] salt , byte [] iv , int kdfIterationCount ) throws GeneralSecurityException , IOException {
407
412
assert isLoaded ();
408
413
409
414
ByteArrayOutputStream bytes = new ByteArrayOutputStream ();
410
- Cipher cipher = createCipher (Cipher .ENCRYPT_MODE , password , salt , iv );
415
+ Cipher cipher = createCipher (Cipher .ENCRYPT_MODE , password , salt , iv , kdfIterationCount );
411
416
try (
412
417
CipherOutputStream cipherStream = new CipherOutputStream (bytes , cipher );
413
418
DataOutputStream output = new DataOutputStream (cipherStream )
@@ -450,7 +455,7 @@ public synchronized void save(Path configDir, char[] password, boolean preserveP
450
455
byte [] iv = new byte [12 ];
451
456
random .nextBytes (iv );
452
457
// encrypted data
453
- byte [] encryptedBytes = encrypt (password , salt , iv );
458
+ byte [] encryptedBytes = encrypt (password , salt , iv , getKdfIterationCountForVersion ( CURRENT_VERSION ) );
454
459
455
460
// size of data block
456
461
output .writeInt (4 + salt .length + 4 + iv .length + 4 + encryptedBytes .length );
0 commit comments