Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -63,27 +63,39 @@
* 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;
private String keyManager = null;
// Lets just load keks for reading once
private HashMap<String,Key> decryptingKeys = null;
private SecureRandom sr = null;
private boolean encryptEnabled = true;

private static final FileEncrypter DISABLED = new NoFileEncrypter();

@Override
public void init(Map<String,String> 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) {
Expand All @@ -101,6 +113,9 @@ public void init(Map<String,String> conf) throws CryptoException {

@Override
public FileEncrypter getFileEncrypter(CryptoEnvironment environment) {
if (!encryptEnabled) {
return DISABLED;
}
CryptoModule cm;
switch (environment.getScope()) {
case WAL:
Expand Down
41 changes: 41 additions & 0 deletions core/src/test/java/org/apache/accumulo/core/crypto/CryptoTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -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();
Expand All @@ -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();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down