diff --git a/core/src/main/java/org/apache/accumulo/core/spi/crypto/AESCryptoService.java b/core/src/main/java/org/apache/accumulo/core/spi/crypto/AESCryptoService.java index 95d10a4c848..1f0d3844cf7 100644 --- a/core/src/main/java/org/apache/accumulo/core/spi/crypto/AESCryptoService.java +++ b/core/src/main/java/org/apache/accumulo/core/spi/crypto/AESCryptoService.java @@ -63,12 +63,18 @@ * Example implementation of AES encryption for Accumulo */ public class AESCryptoService implements CryptoService { + // properties required for using this service + private static final String CRYPTO_PREFIX = "instance.crypto.opts."; + private static final String KEY_URI = CRYPTO_PREFIX + "key.uri"; + // optional properties + // defaults to true + private static final String ENCRYPT_ENABLED = CRYPTO_PREFIX + "enabled"; // Hard coded NoCryptoService.VERSION - this permits the removal of NoCryptoService from the // core jar, allowing use of only one crypto service private static final String NO_CRYPTO_VERSION = "U+1F47B"; - public static final String URI = "uri"; - public static final String KEY_WRAP_TRANSFORM = "AESWrap"; + private static final String URI = "uri"; + private static final String KEY_WRAP_TRANSFORM = "AESWrap"; private Key encryptingKek = null; private String keyLocation = null; @@ -76,14 +82,20 @@ public class AESCryptoService implements CryptoService { // Lets just load keks for reading once private HashMap decryptingKeys = null; private SecureRandom sr = null; + private boolean encryptEnabled = true; + + private static final FileEncrypter DISABLED = new NoFileEncrypter(); @Override public void init(Map conf) throws CryptoException { - String keyLocation = conf.get("instance.crypto.opts.key.uri"); + String keyLocation = + Objects.requireNonNull(conf.get(KEY_URI), "Config property " + KEY_URI + " is required."); + String enabledProp = conf.get(ENCRYPT_ENABLED); + if (enabledProp != null) + encryptEnabled = Boolean.parseBoolean(enabledProp); + // get key from URI for now, keyMgr framework could be expanded on in the future String keyMgr = "uri"; - Objects.requireNonNull(keyLocation, - "Config property instance.crypto.opts.key.uri is required."); this.sr = CryptoUtils.newSha1SecureRandom(); this.decryptingKeys = new HashMap<>(); switch (keyMgr) { @@ -101,6 +113,9 @@ public void init(Map conf) throws CryptoException { @Override public FileEncrypter getFileEncrypter(CryptoEnvironment environment) { + if (!encryptEnabled) { + return DISABLED; + } CryptoModule cm; switch (environment.getScope()) { case WAL: diff --git a/core/src/test/java/org/apache/accumulo/core/crypto/CryptoTest.java b/core/src/test/java/org/apache/accumulo/core/crypto/CryptoTest.java index 5568a8d465a..8c0c3751b00 100644 --- a/core/src/test/java/org/apache/accumulo/core/crypto/CryptoTest.java +++ b/core/src/test/java/org/apache/accumulo/core/crypto/CryptoTest.java @@ -83,6 +83,7 @@ public class CryptoTest { public static final int MARKER_INT = 0xCADEFEDD; public static final String MARKER_STRING = "1 2 3 4 5 6 7 8 a b c d e f g h "; public static final String CRYPTO_ON_CONF = "ON"; + public static final String CRYPTO_ON_DISABLED_CONF = "ON_DISABLED"; public static final String CRYPTO_OFF_CONF = "OFF"; public static final String keyPath = System.getProperty("user.dir") + "/target/CryptoTest-testkeyfile"; @@ -155,6 +156,26 @@ public void testAESCryptoServiceWAL() throws Exception { decrypt(resultingBytes, Scope.WAL, CRYPTO_ON_CONF); } + /** + * AESCryptoService is configured but only for reading + */ + @Test + public void testAESCryptoServiceWALDisabled() throws Exception { + AESCryptoService cs = new AESCryptoService(); + // make sure we can read encrypted + byte[] encryptedBytes = encrypt(cs, Scope.WAL, CRYPTO_ON_CONF); + String stringEncryptedBytes = Arrays.toString(encryptedBytes); + String stringifiedMarkerBytes = getStringifiedBytes(null, MARKER_STRING, MARKER_INT); + assertNotEquals(stringEncryptedBytes, stringifiedMarkerBytes); + decrypt(encryptedBytes, Scope.WAL, CRYPTO_ON_DISABLED_CONF); + + // make sure we don't encrypt when disabled + byte[] plainBytes = encrypt(cs, Scope.WAL, CRYPTO_ON_DISABLED_CONF); + String stringPlainBytes = Arrays.toString(plainBytes); + assertNotEquals(stringEncryptedBytes, stringPlainBytes); + decrypt(plainBytes, Scope.WAL, CRYPTO_ON_DISABLED_CONF); + } + @Test public void testAESCryptoServiceRFILE() throws Exception { AESCryptoService cs = new AESCryptoService(); @@ -168,6 +189,26 @@ public void testAESCryptoServiceRFILE() throws Exception { decrypt(resultingBytes, Scope.RFILE, CRYPTO_ON_CONF); } + /** + * AESCryptoService is configured but only for reading + */ + @Test + public void testAESCryptoServiceRFILEDisabled() throws Exception { + AESCryptoService cs = new AESCryptoService(); + // make sure we can read encrypted + byte[] encryptedBytes = encrypt(cs, Scope.RFILE, CRYPTO_ON_CONF); + String stringEncryptedBytes = Arrays.toString(encryptedBytes); + String stringifiedMarkerBytes = getStringifiedBytes(null, MARKER_STRING, MARKER_INT); + assertNotEquals(stringEncryptedBytes, stringifiedMarkerBytes); + decrypt(encryptedBytes, Scope.RFILE, CRYPTO_ON_DISABLED_CONF); + + // make sure we don't encrypt when disabled + byte[] plainBytes = encrypt(cs, Scope.RFILE, CRYPTO_ON_DISABLED_CONF); + String stringPlainBytes = Arrays.toString(plainBytes); + assertNotEquals(stringEncryptedBytes, stringPlainBytes); + decrypt(plainBytes, Scope.RFILE, CRYPTO_ON_DISABLED_CONF); + } + @Test public void testNoEncryptionWAL() throws Exception { CryptoService cs = CryptoServiceFactory.newDefaultInstance(); diff --git a/core/src/test/java/org/apache/accumulo/core/file/rfile/RFileTest.java b/core/src/test/java/org/apache/accumulo/core/file/rfile/RFileTest.java index f0cee846529..66572edd8be 100644 --- a/core/src/test/java/org/apache/accumulo/core/file/rfile/RFileTest.java +++ b/core/src/test/java/org/apache/accumulo/core/file/rfile/RFileTest.java @@ -1796,13 +1796,18 @@ private void runVersionTest(int version, ConfigurationCopy aconf) throws Excepti reader.close(); } + @SuppressWarnings("fallthrough") public static ConfigurationCopy getAccumuloConfig(String cryptoOn) { ConfigurationCopy cfg = new ConfigurationCopy(DefaultConfiguration.getInstance()); switch (cryptoOn) { + case CryptoTest.CRYPTO_ON_DISABLED_CONF: + cfg.set(INSTANCE_CRYPTO_PREFIX.getKey() + "enabled", "false"); + // fall through to set remaining config case CryptoTest.CRYPTO_ON_CONF: cfg.set(Property.INSTANCE_CRYPTO_SERVICE, "org.apache.accumulo.core.spi.crypto.AESCryptoService"); cfg.set(INSTANCE_CRYPTO_PREFIX.getKey() + "key.uri", CryptoTest.keyPath); + break; } return cfg; }