Merge pull request elastic/elasticsearch#2770 from rjernst/simpler_crypto_api
Internal: Simplify CryptoService api Original commit: elastic/x-pack-elasticsearch@de3f270cbb
This commit is contained in:
commit
eade405b8f
|
@ -143,7 +143,7 @@ public class SecurityFeatureSet implements XPackFeatureSet {
|
||||||
|
|
||||||
static boolean systemKeyUsage(CryptoService cryptoService) {
|
static boolean systemKeyUsage(CryptoService cryptoService) {
|
||||||
// we can piggy back on the encryption enabled method as it is only enabled if there is a system key
|
// we can piggy back on the encryption enabled method as it is only enabled if there is a system key
|
||||||
return cryptoService != null && cryptoService.encryptionEnabled();
|
return cryptoService != null && cryptoService.isEncryptionEnabled();
|
||||||
}
|
}
|
||||||
|
|
||||||
static class Usage extends XPackFeatureSet.Usage {
|
static class Usage extends XPackFeatureSet.Usage {
|
||||||
|
|
|
@ -191,7 +191,7 @@ public class SecurityActionFilter extends AbstractComponent implements ActionFil
|
||||||
if (response instanceof SearchResponse) {
|
if (response instanceof SearchResponse) {
|
||||||
SearchResponse searchResponse = (SearchResponse) response;
|
SearchResponse searchResponse = (SearchResponse) response;
|
||||||
String scrollId = searchResponse.getScrollId();
|
String scrollId = searchResponse.getScrollId();
|
||||||
if (scrollId != null && !cryptoService.signed(scrollId)) {
|
if (scrollId != null && !cryptoService.isSigned(scrollId)) {
|
||||||
searchResponse.scrollId(cryptoService.sign(scrollId));
|
searchResponse.scrollId(cryptoService.sign(scrollId));
|
||||||
}
|
}
|
||||||
return response;
|
return response;
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
*/
|
*/
|
||||||
package org.elasticsearch.xpack.security.crypto;
|
package org.elasticsearch.xpack.security.crypto;
|
||||||
|
|
||||||
import javax.crypto.SecretKey;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -26,27 +25,10 @@ public interface CryptoService {
|
||||||
*/
|
*/
|
||||||
String unsignAndVerify(String text);
|
String unsignAndVerify(String text);
|
||||||
|
|
||||||
/**
|
|
||||||
* Signs the given text and returns the signed text (original text + signature)
|
|
||||||
* @param text the string to sign
|
|
||||||
* @param key the key to sign the text with
|
|
||||||
* @param systemKey the system key. This is optional and if the key != systemKey then the format of the
|
|
||||||
* message will change
|
|
||||||
*/
|
|
||||||
String sign(String text, SecretKey key, SecretKey systemKey) throws IOException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Unsigns the given signed text, verifies the original text with the attached signature and if valid returns
|
|
||||||
* the unsigned (original) text. If signature verification fails a {@link IllegalArgumentException} is thrown.
|
|
||||||
* @param text the string to unsign and verify
|
|
||||||
* @param key the key to unsign the text with
|
|
||||||
*/
|
|
||||||
String unsignAndVerify(String text, SecretKey key);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks whether the given text is signed.
|
* Checks whether the given text is signed.
|
||||||
*/
|
*/
|
||||||
boolean signed(String text);
|
boolean isSigned(String text);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Encrypts the provided char array and returns the encrypted values in a char array
|
* Encrypts the provided char array and returns the encrypted values in a char array
|
||||||
|
@ -55,13 +37,6 @@ public interface CryptoService {
|
||||||
*/
|
*/
|
||||||
char[] encrypt(char[] chars);
|
char[] encrypt(char[] chars);
|
||||||
|
|
||||||
/**
|
|
||||||
* Encrypts the provided byte array and returns the encrypted value
|
|
||||||
* @param bytes the data to encrypt
|
|
||||||
* @return encrypted data
|
|
||||||
*/
|
|
||||||
byte[] encrypt(byte[] bytes);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Decrypts the provided char array and returns the plain-text chars
|
* Decrypts the provided char array and returns the plain-text chars
|
||||||
* @param chars the data to decrypt
|
* @param chars the data to decrypt
|
||||||
|
@ -69,46 +44,16 @@ public interface CryptoService {
|
||||||
*/
|
*/
|
||||||
char[] decrypt(char[] chars);
|
char[] decrypt(char[] chars);
|
||||||
|
|
||||||
/**
|
|
||||||
* Decrypts the provided char array and returns the plain-text chars
|
|
||||||
* @param chars the data to decrypt
|
|
||||||
* @param key the key to decrypt the data with
|
|
||||||
* @return plaintext chars
|
|
||||||
*/
|
|
||||||
char[] decrypt(char[] chars, SecretKey key);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Decrypts the provided byte array and returns the unencrypted bytes
|
|
||||||
* @param bytes the bytes to decrypt
|
|
||||||
* @return plaintext bytes
|
|
||||||
*/
|
|
||||||
byte[] decrypt(byte[] bytes);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Decrypts the provided byte array and returns the unencrypted bytes
|
|
||||||
* @param bytes the bytes to decrypt
|
|
||||||
* @param key the key to decrypt the data with
|
|
||||||
* @return plaintext bytes
|
|
||||||
*/
|
|
||||||
byte[] decrypt(byte[] bytes, SecretKey key);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks whether the given chars are encrypted
|
* Checks whether the given chars are encrypted
|
||||||
* @param chars the chars to check if they are encrypted
|
* @param chars the chars to check if they are encrypted
|
||||||
* @return true is data is encrypted
|
* @return true is data is encrypted
|
||||||
*/
|
*/
|
||||||
boolean encrypted(char[] chars);
|
boolean isEncrypted(char[] chars);
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks whether the given bytes are encrypted
|
|
||||||
* @param bytes the chars to check if they are encrypted
|
|
||||||
* @return true is data is encrypted
|
|
||||||
*/
|
|
||||||
boolean encrypted(byte[] bytes);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Flag for callers to determine if values will actually be encrypted or returned plaintext
|
* Flag for callers to determine if values will actually be encrypted or returned plaintext
|
||||||
* @return true if values will be encrypted
|
* @return true if values will be encrypted
|
||||||
*/
|
*/
|
||||||
boolean encryptionEnabled();
|
boolean isEncryptionEnabled();
|
||||||
}
|
}
|
||||||
|
|
|
@ -157,23 +157,12 @@ public class InternalCryptoService extends AbstractComponent implements CryptoSe
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String sign(String text) throws IOException {
|
public String sign(String text) throws IOException {
|
||||||
return sign(text, this.signingKey, this.systemKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String sign(String text, SecretKey signingKey, @Nullable SecretKey systemKey) throws IOException {
|
|
||||||
assert signingKey != null;
|
|
||||||
String sigStr = signInternal(text, signingKey);
|
String sigStr = signInternal(text, signingKey);
|
||||||
return "$$" + sigStr.length() + "$$" + (systemKey == signingKey ? "" : randomKeyBase64) + "$$" + sigStr + text;
|
return "$$" + sigStr.length() + "$$" + (systemKey == signingKey ? "" : randomKeyBase64) + "$$" + sigStr + text;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String unsignAndVerify(String signedText) {
|
public String unsignAndVerify(String signedText) {
|
||||||
return unsignAndVerify(signedText, this.systemKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String unsignAndVerify(String signedText, SecretKey systemKey) {
|
|
||||||
if (!signedText.startsWith("$$") || signedText.length() < 2) {
|
if (!signedText.startsWith("$$") || signedText.length() < 2) {
|
||||||
throw new IllegalArgumentException("tampered signed text");
|
throw new IllegalArgumentException("tampered signed text");
|
||||||
}
|
}
|
||||||
|
@ -239,7 +228,7 @@ public class InternalCryptoService extends AbstractComponent implements CryptoSe
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean signed(String text) {
|
public boolean isSigned(String text) {
|
||||||
return SIG_PATTERN.matcher(text).matches();
|
return SIG_PATTERN.matcher(text).matches();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -257,33 +246,13 @@ public class InternalCryptoService extends AbstractComponent implements CryptoSe
|
||||||
return ENCRYPTED_TEXT_PREFIX.concat(base64).toCharArray();
|
return ENCRYPTED_TEXT_PREFIX.concat(base64).toCharArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public byte[] encrypt(byte[] bytes) {
|
|
||||||
SecretKey key = this.encryptionKey;
|
|
||||||
if (key == null) {
|
|
||||||
logger.warn("encrypt called without a key, returning plain text. run syskeygen and copy same key to all nodes to enable " +
|
|
||||||
"encryption");
|
|
||||||
return bytes;
|
|
||||||
}
|
|
||||||
byte[] encrypted = encryptInternal(bytes, key);
|
|
||||||
byte[] prefixed = new byte[ENCRYPTED_BYTE_PREFIX.length + encrypted.length];
|
|
||||||
System.arraycopy(ENCRYPTED_BYTE_PREFIX, 0, prefixed, 0, ENCRYPTED_BYTE_PREFIX.length);
|
|
||||||
System.arraycopy(encrypted, 0, prefixed, ENCRYPTED_BYTE_PREFIX.length, encrypted.length);
|
|
||||||
return prefixed;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public char[] decrypt(char[] chars) {
|
public char[] decrypt(char[] chars) {
|
||||||
return decrypt(chars, this.encryptionKey);
|
if (encryptionKey == null) {
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public char[] decrypt(char[] chars, SecretKey key) {
|
|
||||||
if (key == null) {
|
|
||||||
return chars;
|
return chars;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!encrypted(chars)) {
|
if (!isEncrypted(chars)) {
|
||||||
// Not encrypted
|
// Not encrypted
|
||||||
return chars;
|
return chars;
|
||||||
}
|
}
|
||||||
|
@ -296,41 +265,17 @@ public class InternalCryptoService extends AbstractComponent implements CryptoSe
|
||||||
throw new ElasticsearchException("unable to decode encrypted data", e);
|
throw new ElasticsearchException("unable to decode encrypted data", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
byte[] decrypted = decryptInternal(bytes, key);
|
byte[] decrypted = decryptInternal(bytes, encryptionKey);
|
||||||
return CharArrays.utf8BytesToChars(decrypted);
|
return CharArrays.utf8BytesToChars(decrypted);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public byte[] decrypt(byte[] bytes) {
|
public boolean isEncrypted(char[] chars) {
|
||||||
return decrypt(bytes, this.encryptionKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public byte[] decrypt(byte[] bytes, SecretKey key) {
|
|
||||||
if (key == null) {
|
|
||||||
return bytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!encrypted(bytes)) {
|
|
||||||
return bytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
byte[] encrypted = Arrays.copyOfRange(bytes, ENCRYPTED_BYTE_PREFIX.length, bytes.length);
|
|
||||||
return decryptInternal(encrypted, key);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean encrypted(char[] chars) {
|
|
||||||
return CharArrays.charsBeginsWith(ENCRYPTED_TEXT_PREFIX, chars);
|
return CharArrays.charsBeginsWith(ENCRYPTED_TEXT_PREFIX, chars);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean encrypted(byte[] bytes) {
|
public boolean isEncryptionEnabled() {
|
||||||
return bytesBeginsWith(ENCRYPTED_BYTE_PREFIX, bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean encryptionEnabled() {
|
|
||||||
return this.encryptionKey != null;
|
return this.encryptionKey != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -417,24 +362,6 @@ public class InternalCryptoService extends AbstractComponent implements CryptoSe
|
||||||
return new SecretKeySpec(truncatedDigest, algorithm);
|
return new SecretKeySpec(truncatedDigest, algorithm);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean bytesBeginsWith(byte[] prefix, byte[] bytes) {
|
|
||||||
if (bytes == null || prefix == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (prefix.length > bytes.length) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < prefix.length; i++) {
|
|
||||||
if (bytes[i] != prefix[i]) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provider class for the HmacSHA1 {@link Mac} that provides an optimization by using a thread local instead of calling
|
* Provider class for the HmacSHA1 {@link Mac} that provides an optimization by using a thread local instead of calling
|
||||||
* Mac#getInstance and obtaining a lock (in the internals)
|
* Mac#getInstance and obtaining a lock (in the internals)
|
||||||
|
|
|
@ -108,6 +108,6 @@ public class ScrollIdSigningTests extends SecurityIntegTestCase {
|
||||||
private void assertSigned(String scrollId) {
|
private void assertSigned(String scrollId) {
|
||||||
CryptoService cryptoService = internalCluster().getDataNodeInstance(InternalCryptoService.class);
|
CryptoService cryptoService = internalCluster().getDataNodeInstance(InternalCryptoService.class);
|
||||||
String message = String.format(Locale.ROOT, "Expected scrollId [%s] to be signed, but was not", scrollId);
|
String message = String.format(Locale.ROOT, "Expected scrollId [%s] to be signed, but was not", scrollId);
|
||||||
assertThat(message, cryptoService.signed(scrollId), is(true));
|
assertThat(message, cryptoService.isSigned(scrollId), is(true));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -96,7 +96,7 @@ public class SecurityFeatureSetTests extends ESTestCase {
|
||||||
public void testSystemKeyUsageEnabledByCryptoService() {
|
public void testSystemKeyUsageEnabledByCryptoService() {
|
||||||
final boolean enabled = randomBoolean();
|
final boolean enabled = randomBoolean();
|
||||||
|
|
||||||
when(cryptoService.encryptionEnabled()).thenReturn(enabled);
|
when(cryptoService.isEncryptionEnabled()).thenReturn(enabled);
|
||||||
|
|
||||||
assertThat(SecurityFeatureSet.systemKeyUsage(cryptoService), is(enabled));
|
assertThat(SecurityFeatureSet.systemKeyUsage(cryptoService), is(enabled));
|
||||||
}
|
}
|
||||||
|
@ -143,7 +143,7 @@ public class SecurityFeatureSetTests extends ESTestCase {
|
||||||
when(rolesStore.usageStats()).thenReturn(Collections.emptyMap());
|
when(rolesStore.usageStats()).thenReturn(Collections.emptyMap());
|
||||||
}
|
}
|
||||||
final boolean useSystemKey = randomBoolean();
|
final boolean useSystemKey = randomBoolean();
|
||||||
when(cryptoService.encryptionEnabled()).thenReturn(useSystemKey);
|
when(cryptoService.isEncryptionEnabled()).thenReturn(useSystemKey);
|
||||||
|
|
||||||
List<Realm> realmsList= new ArrayList<>();
|
List<Realm> realmsList= new ArrayList<>();
|
||||||
|
|
||||||
|
|
|
@ -105,7 +105,7 @@ public class SecurityActionFilterTests extends ESTestCase {
|
||||||
Task task = mock(Task.class);
|
Task task = mock(Task.class);
|
||||||
Authentication authentication = new Authentication(user, new RealmRef("test", "test", "foo"), null);
|
Authentication authentication = new Authentication(user, new RealmRef("test", "test", "foo"), null);
|
||||||
when(authcService.authenticate("_action", request, SystemUser.INSTANCE)).thenReturn(authentication);
|
when(authcService.authenticate("_action", request, SystemUser.INSTANCE)).thenReturn(authentication);
|
||||||
when(cryptoService.signed("signed_scroll_id")).thenReturn(true);
|
when(cryptoService.isSigned("signed_scroll_id")).thenReturn(true);
|
||||||
when(cryptoService.unsignAndVerify("signed_scroll_id")).thenReturn("scroll_id");
|
when(cryptoService.unsignAndVerify("signed_scroll_id")).thenReturn("scroll_id");
|
||||||
filter.apply(task, "_action", request, listener, chain);
|
filter.apply(task, "_action", request, listener, chain);
|
||||||
assertThat(request.scrollId(), equalTo("scroll_id"));
|
assertThat(request.scrollId(), equalTo("scroll_id"));
|
||||||
|
@ -122,7 +122,7 @@ public class SecurityActionFilterTests extends ESTestCase {
|
||||||
Task task = mock(Task.class);
|
Task task = mock(Task.class);
|
||||||
Authentication authentication = new Authentication(user, new RealmRef("test", "test", "foo"), null);
|
Authentication authentication = new Authentication(user, new RealmRef("test", "test", "foo"), null);
|
||||||
when(authcService.authenticate("_action", request, SystemUser.INSTANCE)).thenReturn(authentication);
|
when(authcService.authenticate("_action", request, SystemUser.INSTANCE)).thenReturn(authentication);
|
||||||
when(cryptoService.signed("scroll_id")).thenReturn(true);
|
when(cryptoService.isSigned("scroll_id")).thenReturn(true);
|
||||||
doThrow(sigException).when(cryptoService).unsignAndVerify("scroll_id");
|
doThrow(sigException).when(cryptoService).unsignAndVerify("scroll_id");
|
||||||
filter.apply(task, "_action", request, listener, chain);
|
filter.apply(task, "_action", request, listener, chain);
|
||||||
verify(listener).onFailure(isA(ElasticsearchSecurityException.class));
|
verify(listener).onFailure(isA(ElasticsearchSecurityException.class));
|
||||||
|
|
|
@ -7,7 +7,6 @@ package org.elasticsearch.xpack.security.crypto;
|
||||||
|
|
||||||
import javax.crypto.SecretKey;
|
import javax.crypto.SecretKey;
|
||||||
import javax.crypto.spec.SecretKeySpec;
|
import javax.crypto.spec.SecretKeySpec;
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
@ -46,7 +45,7 @@ public class InternalCryptoServiceTests extends ESTestCase {
|
||||||
InternalCryptoService service = new InternalCryptoService(settings, env);
|
InternalCryptoService service = new InternalCryptoService(settings, env);
|
||||||
String text = randomAsciiOfLength(10);
|
String text = randomAsciiOfLength(10);
|
||||||
String signed = service.sign(text);
|
String signed = service.sign(text);
|
||||||
assertThat(service.signed(signed), is(true));
|
assertThat(service.isSigned(signed), is(true));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testSignAndUnsign() throws Exception {
|
public void testSignAndUnsign() throws Exception {
|
||||||
|
@ -133,7 +132,7 @@ public class InternalCryptoServiceTests extends ESTestCase {
|
||||||
|
|
||||||
public void testEncryptionAndDecryptionChars() throws Exception {
|
public void testEncryptionAndDecryptionChars() throws Exception {
|
||||||
InternalCryptoService service = new InternalCryptoService(settings, env);
|
InternalCryptoService service = new InternalCryptoService(settings, env);
|
||||||
assertThat(service.encryptionEnabled(), is(true));
|
assertThat(service.isEncryptionEnabled(), is(true));
|
||||||
final char[] chars = randomAsciiOfLengthBetween(0, 1000).toCharArray();
|
final char[] chars = randomAsciiOfLengthBetween(0, 1000).toCharArray();
|
||||||
final char[] encrypted = service.encrypt(chars);
|
final char[] encrypted = service.encrypt(chars);
|
||||||
assertThat(encrypted, notNullValue());
|
assertThat(encrypted, notNullValue());
|
||||||
|
@ -143,21 +142,9 @@ public class InternalCryptoServiceTests extends ESTestCase {
|
||||||
assertThat(Arrays.equals(chars, decrypted), is(true));
|
assertThat(Arrays.equals(chars, decrypted), is(true));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testEncryptionAndDecryptionBytes() throws Exception {
|
|
||||||
InternalCryptoService service = new InternalCryptoService(settings, env);
|
|
||||||
assertThat(service.encryptionEnabled(), is(true));
|
|
||||||
final byte[] bytes = randomByteArray();
|
|
||||||
final byte[] encrypted = service.encrypt(bytes);
|
|
||||||
assertThat(encrypted, notNullValue());
|
|
||||||
assertThat(Arrays.equals(encrypted, bytes), is(false));
|
|
||||||
|
|
||||||
final byte[] decrypted = service.decrypt(encrypted);
|
|
||||||
assertThat(Arrays.equals(bytes, decrypted), is(true));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testEncryptionAndDecryptionCharsWithoutKey() throws Exception {
|
public void testEncryptionAndDecryptionCharsWithoutKey() throws Exception {
|
||||||
InternalCryptoService service = new InternalCryptoService(Settings.EMPTY, env);
|
InternalCryptoService service = new InternalCryptoService(Settings.EMPTY, env);
|
||||||
assertThat(service.encryptionEnabled(), is(false));
|
assertThat(service.isEncryptionEnabled(), is(false));
|
||||||
final char[] chars = randomAsciiOfLengthBetween(0, 1000).toCharArray();
|
final char[] chars = randomAsciiOfLengthBetween(0, 1000).toCharArray();
|
||||||
final char[] encryptedChars = service.encrypt(chars);
|
final char[] encryptedChars = service.encrypt(chars);
|
||||||
final char[] decryptedChars = service.decrypt(encryptedChars);
|
final char[] decryptedChars = service.decrypt(encryptedChars);
|
||||||
|
@ -165,68 +152,26 @@ public class InternalCryptoServiceTests extends ESTestCase {
|
||||||
assertThat(chars, equalTo(decryptedChars));
|
assertThat(chars, equalTo(decryptedChars));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testEncryptionAndDecryptionBytesWithoutKey() throws Exception {
|
|
||||||
InternalCryptoService service = new InternalCryptoService(Settings.EMPTY, env);
|
|
||||||
assertThat(service.encryptionEnabled(), is(false));
|
|
||||||
final byte[] bytes = randomByteArray();
|
|
||||||
final byte[] encryptedBytes = service.encrypt(bytes);
|
|
||||||
final byte[] decryptedBytes = service.decrypt(bytes);
|
|
||||||
assertThat(bytes, equalTo(encryptedBytes));
|
|
||||||
assertThat(decryptedBytes, equalTo(encryptedBytes));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testEncryptionEnabledWithKey() throws Exception {
|
public void testEncryptionEnabledWithKey() throws Exception {
|
||||||
InternalCryptoService service = new InternalCryptoService(settings, env);
|
InternalCryptoService service = new InternalCryptoService(settings, env);
|
||||||
assertThat(service.encryptionEnabled(), is(true));
|
assertThat(service.isEncryptionEnabled(), is(true));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testEncryptionEnabledWithoutKey() throws Exception {
|
public void testEncryptionEnabledWithoutKey() throws Exception {
|
||||||
InternalCryptoService service = new InternalCryptoService(Settings.EMPTY, env);
|
InternalCryptoService service = new InternalCryptoService(Settings.EMPTY, env);
|
||||||
assertThat(service.encryptionEnabled(), is(false));
|
assertThat(service.isEncryptionEnabled(), is(false));
|
||||||
}
|
|
||||||
|
|
||||||
public void testChangingAByte() throws Exception {
|
|
||||||
InternalCryptoService service = new InternalCryptoService(settings, env);
|
|
||||||
assertThat(service.encryptionEnabled(), is(true));
|
|
||||||
// We need at least one byte to test changing a byte, otherwise output is always the same
|
|
||||||
final byte[] bytes = randomByteArray(1);
|
|
||||||
final byte[] encrypted = service.encrypt(bytes);
|
|
||||||
assertThat(encrypted, notNullValue());
|
|
||||||
assertThat(Arrays.equals(encrypted, bytes), is(false));
|
|
||||||
|
|
||||||
int tamperedIndex = randomIntBetween(InternalCryptoService.ENCRYPTED_BYTE_PREFIX.length, encrypted.length - 1);
|
|
||||||
final byte untamperedByte = encrypted[tamperedIndex];
|
|
||||||
byte tamperedByte = randomByte();
|
|
||||||
while (tamperedByte == untamperedByte) {
|
|
||||||
tamperedByte = randomByte();
|
|
||||||
}
|
|
||||||
encrypted[tamperedIndex] = tamperedByte;
|
|
||||||
final byte[] decrypted = service.decrypt(encrypted);
|
|
||||||
assertThat(Arrays.equals(bytes, decrypted), is(false));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testEncryptedChar() throws Exception {
|
public void testEncryptedChar() throws Exception {
|
||||||
InternalCryptoService service = new InternalCryptoService(settings, env);
|
InternalCryptoService service = new InternalCryptoService(settings, env);
|
||||||
assertThat(service.encryptionEnabled(), is(true));
|
assertThat(service.isEncryptionEnabled(), is(true));
|
||||||
|
|
||||||
assertThat(service.encrypted((char[]) null), is(false));
|
assertThat(service.isEncrypted((char[]) null), is(false));
|
||||||
assertThat(service.encrypted(new char[0]), is(false));
|
assertThat(service.isEncrypted(new char[0]), is(false));
|
||||||
assertThat(service.encrypted(new char[InternalCryptoService.ENCRYPTED_TEXT_PREFIX.length()]), is(false));
|
assertThat(service.isEncrypted(new char[InternalCryptoService.ENCRYPTED_TEXT_PREFIX.length()]), is(false));
|
||||||
assertThat(service.encrypted(InternalCryptoService.ENCRYPTED_TEXT_PREFIX.toCharArray()), is(true));
|
assertThat(service.isEncrypted(InternalCryptoService.ENCRYPTED_TEXT_PREFIX.toCharArray()), is(true));
|
||||||
assertThat(service.encrypted(randomAsciiOfLengthBetween(0, 100).toCharArray()), is(false));
|
assertThat(service.isEncrypted(randomAsciiOfLengthBetween(0, 100).toCharArray()), is(false));
|
||||||
assertThat(service.encrypted(service.encrypt(randomAsciiOfLength(10).toCharArray())), is(true));
|
assertThat(service.isEncrypted(service.encrypt(randomAsciiOfLength(10).toCharArray())), is(true));
|
||||||
}
|
|
||||||
|
|
||||||
public void testEncryptedByte() throws Exception {
|
|
||||||
InternalCryptoService service = new InternalCryptoService(settings, env);
|
|
||||||
assertThat(service.encryptionEnabled(), is(true));
|
|
||||||
|
|
||||||
assertThat(service.encrypted((byte[]) null), is(false));
|
|
||||||
assertThat(service.encrypted(new byte[0]), is(false));
|
|
||||||
assertThat(service.encrypted(new byte[InternalCryptoService.ENCRYPTED_BYTE_PREFIX.length]), is(false));
|
|
||||||
assertThat(service.encrypted(InternalCryptoService.ENCRYPTED_BYTE_PREFIX), is(true));
|
|
||||||
assertThat(service.encrypted(randomAsciiOfLengthBetween(0, 100).getBytes(StandardCharsets.UTF_8)), is(false));
|
|
||||||
assertThat(service.encrypted(service.encrypt(randomAsciiOfLength(10).getBytes(StandardCharsets.UTF_8))), is(true));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testSigningKeyCanBeRecomputedConsistently() {
|
public void testSigningKeyCanBeRecomputedConsistently() {
|
||||||
|
@ -239,17 +184,4 @@ public class InternalCryptoServiceTests extends ESTestCase {
|
||||||
assertThat(regenerated, equalTo(signingKey));
|
assertThat(regenerated, equalTo(signingKey));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static byte[] randomByteArray() {
|
|
||||||
return randomByteArray(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static byte[] randomByteArray(int min) {
|
|
||||||
int count = randomIntBetween(min, 1000);
|
|
||||||
byte[] bytes = new byte[count];
|
|
||||||
for (int i = 0; i < count; i++) {
|
|
||||||
bytes[i] = randomByte();
|
|
||||||
}
|
|
||||||
return bytes;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue