Skip to content

Commit f0ae034

Browse files
Change DEK location scheme
1 parent 84d043a commit f0ae034

File tree

3 files changed

+164
-139
lines changed

3 files changed

+164
-139
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License;
4+
* you may not use this file except in compliance with the Elastic License.
5+
*/
6+
package org.elasticsearch.repositories.encrypted;
7+
8+
import javax.crypto.Cipher;
9+
import javax.crypto.IllegalBlockSizeException;
10+
import javax.crypto.NoSuchPaddingException;
11+
import javax.crypto.SecretKey;
12+
import javax.crypto.spec.SecretKeySpec;
13+
import java.nio.charset.StandardCharsets;
14+
import java.security.GeneralSecurityException;
15+
import java.security.InvalidKeyException;
16+
import java.security.Key;
17+
import java.security.NoSuchAlgorithmException;
18+
import java.util.Base64;
19+
20+
public final class AESKeyUtils {
21+
// The Id of any AES SecretKey is the AES-Wrap-ciphertext of this fixed 32 byte wide array.
22+
// Key wrapping encryption is deterministic (same plaintext generates the same ciphertext)
23+
// and the probability that two different keys map the same plaintext to the same ciphertext is very small
24+
// (2^-256, much lower than the UUID collision of 2^-128), assuming AES is indistinguishable from a pseudorandom permutation.
25+
private static final byte[] KEY_ID_PLAINTEXT = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
26+
21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
27+
28+
public static byte[] wrap(SecretKey wrappingKey, Key keyToWrap) throws NoSuchPaddingException, NoSuchAlgorithmException,
29+
InvalidKeyException, IllegalBlockSizeException {
30+
if (false == "AES".equals(wrappingKey.getAlgorithm())) {
31+
throw new IllegalArgumentException("wrappingKey argument is not an AES Key");
32+
}
33+
if (false == "AES".equals(keyToWrap.getAlgorithm())) {
34+
throw new IllegalArgumentException("toWrapKey argument is not an AES Key");
35+
}
36+
Cipher c = Cipher.getInstance("AESWrap");
37+
c.init(Cipher.WRAP_MODE, wrappingKey);
38+
return c.wrap(keyToWrap);
39+
}
40+
41+
public static SecretKey unwrap(SecretKey wrappingKey, byte[] keyToUnwrap) throws NoSuchPaddingException,
42+
NoSuchAlgorithmException, InvalidKeyException {
43+
if (false == "AES".equals(wrappingKey.getAlgorithm())) {
44+
throw new IllegalArgumentException("wrappingKey argument is not an AES Key");
45+
}
46+
Cipher c = Cipher.getInstance("AESWrap");
47+
c.init(Cipher.UNWRAP_MODE, wrappingKey);
48+
Key unwrappedKey = c.unwrap(keyToUnwrap, "AES", Cipher.SECRET_KEY);
49+
return new SecretKeySpec(unwrappedKey.getEncoded(), "AES"); // make sure unwrapped key is "AES"
50+
}
51+
52+
/**
53+
* Computes the ID of the given AES {@code SecretKey}.
54+
* The ID can be published as it does not leak any information about the key.
55+
* Different {@code SecretKey}s have different IDs with a very high probability.
56+
* <p>
57+
* The ID is the ciphertext of a known plaintext, using the AES Wrap cipher algorithm.
58+
* AES Wrap algorithm is deterministic, i.e. encryption using the same key, of the same plaintext, generates the same ciphertext.
59+
* Moreover, the ciphertext reveals no information on the key, and the probability of collision of ciphertexts given different
60+
* keys is statistically negligible.
61+
*/
62+
public static String computeId(SecretKey secretAESKey) throws GeneralSecurityException {
63+
byte[] ciphertextOfKnownPlaintext = wrap(secretAESKey, new SecretKeySpec(KEY_ID_PLAINTEXT, "AES"));
64+
return new String(Base64.getUrlEncoder().withoutPadding().encode(ciphertextOfKnownPlaintext), StandardCharsets.UTF_8);
65+
}
66+
}

0 commit comments

Comments
 (0)