accumulo-notifications mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From GitBox <...@apache.org>
Subject [GitHub] keith-turner closed pull request #322: ACCUMULO-4740 Enable GCM mode for crypto
Date Thu, 01 Jan 1970 00:00:00 GMT
keith-turner closed pull request #322: ACCUMULO-4740 Enable GCM mode for crypto
URL: https://github.com/apache/accumulo/pull/322
 
 
   

This is a PR merged from a forked repository.
As GitHub hides the original diff on merge, it is displayed below for
the sake of provenance:

As this is a foreign pull request (from a fork), the diff is supplied
below (as it won't show otherwise due to GitHub magic):

diff --git a/core/src/main/java/org/apache/accumulo/core/conf/ConfigSanityCheck.java b/core/src/main/java/org/apache/accumulo/core/conf/ConfigSanityCheck.java
index baf1818bff..f787d5e7f2 100644
--- a/core/src/main/java/org/apache/accumulo/core/conf/ConfigSanityCheck.java
+++ b/core/src/main/java/org/apache/accumulo/core/conf/ConfigSanityCheck.java
@@ -81,6 +81,8 @@ else if (!prop.getType().isValidFormat(value))
 
       if (key.equals(Property.CRYPTO_CIPHER_SUITE.getKey())) {
         cipherSuite = Objects.requireNonNull(value);
+        Preconditions.checkArgument(cipherSuite.equals("NullCipher") || cipherSuite.split("/").length
== 3,
+            "Cipher suite must be NullCipher or in the form algorithm/mode/padding. Suite:
" + cipherSuite + " is invalid.");
       }
 
       if (key.equals(Property.CRYPTO_CIPHER_KEY_ALGORITHM_NAME.getKey())) {
diff --git a/core/src/main/java/org/apache/accumulo/core/conf/Property.java b/core/src/main/java/org/apache/accumulo/core/conf/Property.java
index 48a4796948..b885124dfd 100644
--- a/core/src/main/java/org/apache/accumulo/core/conf/Property.java
+++ b/core/src/main/java/org/apache/accumulo/core/conf/Property.java
@@ -49,14 +49,13 @@
           + "(future) other parts of the code."),
   @Experimental
   CRYPTO_CIPHER_SUITE("crypto.cipher.suite", "NullCipher", PropertyType.STRING,
-      "Describes the cipher suite to use for rfile encryption. If a WAL cipher suite is not
set, it will default to this value. The suite should be in the "
-          + "form of algorithm/mode/padding, e.g. AES/CBC/NoPadding"),
+      "Describes the cipher suite to use for rfile encryption. The value must be either NullCipher
or in the form of algorithm/mode/padding, "
+          + "e.g. AES/CBC/NoPadding"),
   @Experimental
-  CRYPTO_WAL_CIPHER_SUITE(
-      "crypto.wal.cipher.suite",
-      "NullCipher",
-      PropertyType.STRING,
-      "Describes the cipher suite to use for the write-ahead log. Defaults to 'cyrpto.cipher.suite'
and will use that value for WAL encryption unless otherwise specified."),
+  CRYPTO_WAL_CIPHER_SUITE("crypto.wal.cipher.suite", "", PropertyType.STRING,
+      "Describes the cipher suite to use for the write-ahead log. Defaults to 'cyrpto.cipher.suite'
"
+          + "and will use that value for WAL encryption unless otherwise specified. Valid
suite values include: an empty string, NullCipher, or a string the "
+          + "form of algorithm/mode/padding, e.g. AES/CBC/NOPadding"),
   @Experimental
   CRYPTO_CIPHER_KEY_ALGORITHM_NAME("crypto.cipher.key.algorithm.name", "NullCipher", PropertyType.STRING,
       "States the name of the algorithm used for the key for the corresponding cipher suite.
The key type must be compatible with the cipher suite."),
diff --git a/core/src/main/java/org/apache/accumulo/core/file/rfile/bcfile/BCFile.java b/core/src/main/java/org/apache/accumulo/core/file/rfile/bcfile/BCFile.java
index f9a61a7e38..e74558321a 100644
--- a/core/src/main/java/org/apache/accumulo/core/file/rfile/bcfile/BCFile.java
+++ b/core/src/main/java/org/apache/accumulo/core/file/rfile/bcfile/BCFile.java
@@ -160,9 +160,8 @@ public WBlockState(Algorithm compressionAlgo, PositionedDataOutputStream
fsOut,
         // *This* is also very important. We don't want the underlying stream messed with.
         cryptoParams.setRecordParametersToStream(false);
 
-        // It is also important to make sure we get a new initialization vector on every
call in here,
-        // so set any existing one to null, in case we're reusing a parameters object for
its RNG or other bits
-        cryptoParams.setInitializationVector(null);
+        // Create a new IV for the block or update an existing one in the case of GCM
+        cryptoParams.updateInitializationVector();
 
         // Initialize the cipher including generating a new IV
         cryptoParams = cryptoModule.initializeCipher(cryptoParams);
diff --git a/core/src/main/java/org/apache/accumulo/core/security/crypto/CryptoModuleParameters.java
b/core/src/main/java/org/apache/accumulo/core/security/crypto/CryptoModuleParameters.java
index 10535e8312..fd210b159d 100644
--- a/core/src/main/java/org/apache/accumulo/core/security/crypto/CryptoModuleParameters.java
+++ b/core/src/main/java/org/apache/accumulo/core/security/crypto/CryptoModuleParameters.java
@@ -569,6 +569,52 @@ public void setBlockStreamSize(int blockStreamSize) {
     this.blockStreamSize = blockStreamSize;
   }
 
+  /**
+   * Returns the mode from the cipher suite. Assumes the suite is in the form of algorithm/mode/padding,
returns null if the cipher suite is malformed or
+   * NullCipher.
+   *
+   * @return the encryption mode from the cipher suite
+   */
+  public String getCipherSuiteEncryptionMode() {
+    String[] parts = this.cipherSuite.split("/");
+    if (parts.length == 3) {
+      return parts[1];
+    } else {
+      return null;
+    }
+  }
+
+  /**
+   * Updates the initialization vector for use when the encryption mode is GCM. If the IV
is not currently null, and the encryption mode is GCM, it will
+   * increment the IV instead of letting the CryptoModule decide what to do.
+   */
+  public void updateInitializationVector() {
+    if (this.initializationVector != null && getCipherSuiteEncryptionMode().equals(DefaultCryptoModule.ALGORITHM_PARAMETER_SPEC_GCM))
{
+      incrementIV(this.initializationVector, this.initializationVector.length - 1);
+    } else {
+      this.initializationVector = null;
+    }
+  }
+
+  /**
+   * Because IVs can be longer than longs, this increments arbitrarily sized byte arrays
by 1, with a roll over to 0 after the max value is reached.
+   *
+   * @param iv
+   *          The iv to be incremented
+   * @param i
+   *          The current byte being incremented
+   */
+  static void incrementIV(byte[] iv, int i) {
+    iv[i]++;
+    if (iv[i] == 0) {
+      if (i != 0) {
+        incrementIV(iv, i - 1);
+      } else
+        return;
+    }
+
+  }
+
   /**
    * Gets the overall set of options for the {@link CryptoModule}.
    *
@@ -617,7 +663,7 @@ public void setAllOptions(Map<String,String> allOptions) {
 
   private Cipher cipher;
   private SecureRandom secureRandom;
-  private byte[] initializationVector;
+  private byte[] initializationVector = null;
 
   private Map<String,String> allOptions;
   private int blockStreamSize;
diff --git a/core/src/main/java/org/apache/accumulo/core/security/crypto/DefaultCryptoModule.java
b/core/src/main/java/org/apache/accumulo/core/security/crypto/DefaultCryptoModule.java
index c97e7f561e..f0d0a6050c 100644
--- a/core/src/main/java/org/apache/accumulo/core/security/crypto/DefaultCryptoModule.java
+++ b/core/src/main/java/org/apache/accumulo/core/security/crypto/DefaultCryptoModule.java
@@ -30,6 +30,7 @@
 
 import javax.crypto.Cipher;
 import javax.crypto.CipherInputStream;
+import javax.crypto.spec.GCMParameterSpec;
 import javax.crypto.spec.IvParameterSpec;
 import javax.crypto.spec.SecretKeySpec;
 
@@ -50,6 +51,17 @@
 
   private static final String ENCRYPTION_HEADER_MARKER_V1 = "---Log File Encrypted (v1)---";
   private static final String ENCRYPTION_HEADER_MARKER_V2 = "---Log File Encrypted (v2)---";
+  public static final String ALGORITHM_PARAMETER_SPEC_GCM = "GCM";
+
+  // 128-bit tags are the longest available for GCM
+  private static final Integer GCM_TAG_LENGTH_IN_BYTES = 16;
+
+  /*
+   * According to NIST Special Publication 800-38D, Section 5.2.1.1: "For IVs, it is recommended
that implementations restrict support to the length of 96 bits,
+   * to promote interoperability, efficiency, and simplicity of design"
+   */
+  private static final Integer GCM_IV_LENGTH_IN_BYTES = 12;
+
   private static final Logger log = LoggerFactory.getLogger(DefaultCryptoModule.class);
 
   public DefaultCryptoModule() {}
@@ -69,26 +81,21 @@ public CryptoModuleParameters initializeCipher(CryptoModuleParameters
params) {
     Cipher cipher = DefaultCryptoModuleUtils.getCipher(params.getCipherSuite(), params.getSecurityProvider());
 
     if (params.getInitializationVector() == null) {
-      try {
-        cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(params.getPlaintextKey(), params.getKeyAlgorithmName()),
params.getSecureRandom());
-      } catch (InvalidKeyException e) {
-        log.error("Accumulo encountered an unknown error in generating the secret key object
(SecretKeySpec) for an encrypted stream");
-        throw new RuntimeException(e);
+      if (params.getCipherSuiteEncryptionMode().equals(ALGORITHM_PARAMETER_SPEC_GCM)) {
+        byte[] gcmIV = new byte[GCM_IV_LENGTH_IN_BYTES];
+        params.getSecureRandom().nextBytes(gcmIV);
+        params.setInitializationVector(gcmIV);
       }
+    }
 
-      params.setInitializationVector(cipher.getIV());
-
-    } else {
-      try {
-        cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(params.getPlaintextKey(), params.getKeyAlgorithmName()),
-            new IvParameterSpec(params.getInitializationVector()));
-      } catch (InvalidKeyException e) {
-        log.error("Accumulo encountered an unknown error in generating the secret key object
(SecretKeySpec) for an encrypted stream");
-        throw new RuntimeException(e);
-      } catch (InvalidAlgorithmParameterException e) {
-        log.error("Accumulo encountered an unknown error in setting up the initialization
vector for an encrypted stream");
-        throw new RuntimeException(e);
-      }
+    try {
+      initCipher(params, cipher, Cipher.ENCRYPT_MODE);
+    } catch (InvalidKeyException e) {
+      log.error("Accumulo encountered an unknown error in generating the secret key object
(SecretKeySpec) for an encrypted stream");
+      throw new RuntimeException(e);
+    } catch (InvalidAlgorithmParameterException e) {
+      log.error("Accumulo encountered an unknown error in setting up the initialization vector
for an encrypted stream");
+      throw new RuntimeException(e);
     }
 
     params.setCipher(cipher);
@@ -370,8 +377,7 @@ public CryptoModuleParameters getDecryptingInputStream(CryptoModuleParameters
pa
     Cipher cipher = DefaultCryptoModuleUtils.getCipher(params.getCipherSuite(), params.getSecurityProvider());
 
     try {
-      cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(params.getPlaintextKey(), params.getKeyAlgorithmName()),
-          new IvParameterSpec(params.getInitializationVector()));
+      initCipher(params, cipher, Cipher.DECRYPT_MODE);
     } catch (InvalidKeyException e) {
       log.error("Error when trying to initialize cipher with secret key");
       throw new RuntimeException(e);
@@ -392,6 +398,33 @@ public CryptoModuleParameters getDecryptingInputStream(CryptoModuleParameters
pa
     return params;
   }
 
+  /**
+   *
+   * @param params
+   *          the crypto parameters
+   * @param cipher
+   *          the Java Cipher object to be init'd
+   * @param opMode
+   *          encrypt or decrypt
+   * @throws InvalidKeyException
+   *           if the crypto params are missing necessary values
+   * @throws InvalidAlgorithmParameterException
+   *           if an invalid algorithm is chosen
+   */
+  private void initCipher(CryptoModuleParameters params, Cipher cipher, int opMode) throws
InvalidKeyException, InvalidAlgorithmParameterException {
+    if (params.getCipherSuiteEncryptionMode().equals(ALGORITHM_PARAMETER_SPEC_GCM)) {
+      cipher.init(opMode, new SecretKeySpec(params.getPlaintextKey(), params.getKeyAlgorithmName()),
+          new GCMParameterSpec(GCM_TAG_LENGTH_IN_BYTES * 8, params.getInitializationVector()));
+    } else {
+      if (params.getInitializationVector() == null) {
+        cipher.init(opMode, new SecretKeySpec(params.getPlaintextKey(), params.getKeyAlgorithmName()),
params.getSecureRandom());
+        params.setInitializationVector(cipher.getIV());
+      } else {
+        cipher.init(opMode, new SecretKeySpec(params.getPlaintextKey(), params.getKeyAlgorithmName()),
new IvParameterSpec(params.getInitializationVector()));
+      }
+    }
+  }
+
   @Override
   public CryptoModuleParameters generateNewRandomSessionKey(CryptoModuleParameters params)
{
 
diff --git a/core/src/test/java/org/apache/accumulo/core/security/crypto/CryptoTest.java b/core/src/test/java/org/apache/accumulo/core/security/crypto/CryptoTest.java
index 1e2975772e..a403f69583 100644
--- a/core/src/test/java/org/apache/accumulo/core/security/crypto/CryptoTest.java
+++ b/core/src/test/java/org/apache/accumulo/core/security/crypto/CryptoTest.java
@@ -17,8 +17,11 @@
 
 package org.apache.accumulo.core.security.crypto;
 
+import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNotSame;
 import static org.junit.Assert.assertTrue;
 
 import java.io.ByteArrayInputStream;
@@ -35,6 +38,7 @@
 import java.util.Arrays;
 import java.util.Map.Entry;
 
+import javax.crypto.AEADBadTagException;
 import javax.crypto.BadPaddingException;
 import javax.crypto.Cipher;
 import javax.crypto.IllegalBlockSizeException;
@@ -92,8 +96,9 @@ public void testCryptoModuleParamsParsing() {
     CryptoModuleParameters params = CryptoModuleFactory.createParamsObjectFromAccumuloConfiguration(conf);
 
     assertNotNull(params);
-    assertEquals("AES/CFB/NoPadding", params.getCipherSuite());
+    assertEquals("AES/GCM/NoPadding", params.getCipherSuite());
     assertEquals("AES/CBC/NoPadding", params.getAllOptions().get(Property.CRYPTO_WAL_CIPHER_SUITE.getKey()));
+    assertEquals("GCM", params.getCipherSuiteEncryptionMode());
     assertEquals("AES", params.getKeyAlgorithmName());
     assertEquals(128, params.getKeyLength());
     assertEquals("SHA1PRNG", params.getRandomNumberGenerator());
@@ -196,7 +201,7 @@ public void testCryptoModuleBasicReadWrite() throws IOException {
     InputStream plaintextIn = params.getPlaintextInputStream();
 
     assertNotNull(plaintextIn);
-    assertTrue(plaintextIn != in);
+    assertNotSame(plaintextIn, in);
     DataInputStream dataIn = new DataInputStream(plaintextIn);
     String markerString = dataIn.readUTF();
     int markerInt = dataIn.readInt();
@@ -213,7 +218,7 @@ public void testCryptoModuleBasicReadWrite() throws IOException {
     params = cryptoModule.getEncryptingOutputStream(params);
 
     assertNotNull(params.getEncryptedOutputStream());
-    assertTrue(params.getEncryptedOutputStream() != out);
+    assertNotSame(params.getEncryptedOutputStream(), out);
 
     DataOutputStream dataOut = new DataOutputStream(params.getEncryptedOutputStream());
     dataOut.writeUTF(MARKER_STRING);
@@ -227,8 +232,8 @@ public void testCryptoModuleBasicReadWrite() throws IOException {
     String stringifiedOtherBytes = getStringifiedBytes(MARKER_INT);
 
     // OK, let's make sure it's encrypted
-    assertTrue(!stringifiedBytes.contains(stringifiedMarkerBytes));
-    assertTrue(!stringifiedBytes.contains(stringifiedOtherBytes));
+    assertFalse(stringifiedBytes.contains(stringifiedMarkerBytes));
+    assertFalse(stringifiedBytes.contains(stringifiedOtherBytes));
     return resultingBytes;
   }
 
@@ -239,6 +244,9 @@ public void testKeyEncryptionAndCheckThatFileCannotBeReadWithoutKEK()
throws IOE
     CryptoModule cryptoModule = CryptoModuleFactory.getCryptoModule(conf);
     CryptoModuleParameters params = CryptoModuleFactory.createParamsObjectFromAccumuloConfiguration(conf);
 
+    // CRYPTO_ON_CONF uses AESWrap which produces wrapped keys that are too large and require
a change to
+    // JCE Unlimited Strength Jurisdiction. Using AES/ECB/NoPadding should avoid this problem.
+    params.getAllOptions().put(Property.CRYPTO_DEFAULT_KEY_STRATEGY_CIPHER_SUITE.getKey(),
"AES/ECB/NoPadding");
     assertTrue(cryptoModule instanceof DefaultCryptoModule);
     assertNotNull(params.getKeyEncryptionStrategyClass());
     assertEquals("org.apache.accumulo.core.security.crypto.CachingHDFSSecretKeyEncryptionStrategy",
params.getKeyEncryptionStrategyClass());
@@ -342,7 +350,7 @@ private AccumuloConfiguration setAndGetAccumuloConfig(String cryptoConfSetting)
   @Test
   public void testKeyWrapAndUnwrap() throws NoSuchAlgorithmException, NoSuchPaddingException,
NoSuchProviderException, InvalidKeyException,
       IllegalBlockSizeException, BadPaddingException {
-    Cipher keyWrapCipher = Cipher.getInstance("AES/ECB/NoPadding");
+    Cipher keyWrapCipher = Cipher.getInstance("AESWrap/ECB/NoPadding");
     SecureRandom random = SecureRandom.getInstance("SHA1PRNG", "SUN");
 
     byte[] kek = new byte[16];
@@ -356,15 +364,208 @@ public void testKeyWrapAndUnwrap() throws NoSuchAlgorithmException,
NoSuchPaddin
 
     byte[] wrappedKey = keyWrapCipher.wrap(randKey);
 
-    assert (wrappedKey != null);
-    assert (wrappedKey.length == randomKey.length);
+    assertNotNull(wrappedKey);
+    // AESWrap will produce 24 bytes given 128 bits of key data with a 128-bit KEK
+    assertEquals(wrappedKey.length, randomKey.length + 8);
 
-    Cipher keyUnwrapCipher = Cipher.getInstance("AES/ECB/NoPadding");
+    Cipher keyUnwrapCipher = Cipher.getInstance("AESWrap/ECB/NoPadding");
     keyUnwrapCipher.init(Cipher.UNWRAP_MODE, new SecretKeySpec(kek, "AES"));
     Key unwrappedKey = keyUnwrapCipher.unwrap(wrappedKey, "AES", Cipher.SECRET_KEY);
 
     byte[] unwrappedKeyBytes = unwrappedKey.getEncoded();
-    assert (Arrays.equals(unwrappedKeyBytes, randomKey));
+    assertArrayEquals(unwrappedKeyBytes, randomKey);
 
   }
+
+  @Test
+  public void AESGCM_Encryption_Test_Correct_Encryption_And_Decryption() throws IOException,
AEADBadTagException {
+    AccumuloConfiguration conf = setAndGetAccumuloConfig(CRYPTO_ON_CONF);
+    byte[] encryptedBytes = testEncryption(conf, new byte[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
10, 20});
+    Integer result = testDecryption(conf, encryptedBytes);
+    assertEquals(result, Integer.valueOf(1));
+  }
+
+  @Test
+  public void AESGCM_Encryption_Test_Tag_Integrity_Compromised() throws IOException, AEADBadTagException
{
+    AccumuloConfiguration conf = setAndGetAccumuloConfig(CRYPTO_ON_CONF);
+    byte[] encryptedBytes = testEncryption(conf, new byte[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
10, 20});
+
+    encryptedBytes[encryptedBytes.length - 1]++; // modify the tag
+    exception.expect(AEADBadTagException.class);
+    testDecryption(conf, encryptedBytes);
+    encryptedBytes[encryptedBytes.length - 1]--;
+    encryptedBytes[1486]++; // modify the data
+    exception.expect(AEADBadTagException.class);
+    testDecryption(conf, encryptedBytes);
+  }
+
+  @Test
+  public void testIVIncrements() {
+    // One byte
+    byte[] testIv1 = new byte[1];
+    // 11111110
+    testIv1[0] = (byte) 0xFE;
+
+    // 11111111
+    CryptoModuleParameters.incrementIV(testIv1, testIv1.length - 1);
+    assertArrayEquals(testIv1, new byte[] {(byte) 0xff});
+
+    // 00000000
+    CryptoModuleParameters.incrementIV(testIv1, testIv1.length - 1);
+    assertArrayEquals(testIv1, new byte[] {(byte) 0x00});
+
+    // Two bytes
+    byte[] testIv2 = new byte[2];
+    // 00000000 11111110
+    testIv2[0] = (byte) 0x00;
+    testIv2[1] = (byte) 0xFE;
+
+    // 00000000 11111111
+    CryptoModuleParameters.incrementIV(testIv2, testIv2.length - 1);
+    assertArrayEquals(testIv2, new byte[] {(byte) 0x00, (byte) 0xFF});
+
+    // 00000001 00000000
+    CryptoModuleParameters.incrementIV(testIv2, testIv2.length - 1);
+    assertArrayEquals(testIv2, new byte[] {(byte) 0x01, (byte) 0x00});
+
+    // 00000001 00000001
+    CryptoModuleParameters.incrementIV(testIv2, testIv2.length - 1);
+    assertArrayEquals(testIv2, new byte[] {(byte) 0x01, (byte) 0x01});
+
+    // 11111111 11111111
+    testIv2[0] = (byte) 0xFF;
+    testIv2[1] = (byte) 0xFF;
+
+    // 00000000 00000000
+    CryptoModuleParameters.incrementIV(testIv2, testIv2.length - 1);
+    assertArrayEquals(testIv2, new byte[] {(byte) 0x00, (byte) 0x00});
+
+    // Three bytes
+    byte[] testIv3 = new byte[3];
+    // 00000000 00000000 11111110
+    testIv3[0] = (byte) 0x00;
+    testIv3[1] = (byte) 0x00;
+    testIv3[2] = (byte) 0xFE;
+
+    // 00000000 00000000 11111111
+    CryptoModuleParameters.incrementIV(testIv3, testIv3.length - 1);
+    assertArrayEquals(testIv3, new byte[] {(byte) 0x00, (byte) 0x00, (byte) 0xFF});
+
+    // 00000000 00000001 00000000
+    CryptoModuleParameters.incrementIV(testIv3, testIv3.length - 1);
+    assertArrayEquals(testIv3, new byte[] {(byte) 0x00, (byte) 0x01, (byte) 0x00});
+
+    // 00000000 00000001 00000001
+    CryptoModuleParameters.incrementIV(testIv3, testIv3.length - 1);
+    assertArrayEquals(testIv3, new byte[] {(byte) 0x00, (byte) 0x01, (byte) 0x01});
+
+    // 00000000 11111111 11111110
+    testIv3[0] = (byte) 0x00;
+    testIv3[1] = (byte) 0xFF;
+    testIv3[2] = (byte) 0xFE;
+
+    // 00000000 11111111 11111111
+    CryptoModuleParameters.incrementIV(testIv3, testIv3.length - 1);
+    assertArrayEquals(testIv3, new byte[] {(byte) 0x00, (byte) 0xFF, (byte) 0xFF});
+
+    // 00000001 00000000 00000000
+    CryptoModuleParameters.incrementIV(testIv3, testIv3.length - 1);
+    assertArrayEquals(testIv3, new byte[] {(byte) 0x01, (byte) 0x00, (byte) 0x00});
+
+    // 00000001 00000000 00000001
+    CryptoModuleParameters.incrementIV(testIv3, testIv3.length - 1);
+    assertArrayEquals(testIv3, new byte[] {(byte) 0x01, (byte) 0x00, (byte) 0x01});
+
+    // 11111111 11111111 11111110
+    testIv3[0] = (byte) 0xFF;
+    testIv3[1] = (byte) 0xFF;
+    testIv3[2] = (byte) 0xFE;
+
+    // 11111111 11111111 11111111
+    CryptoModuleParameters.incrementIV(testIv3, testIv3.length - 1);
+    assertArrayEquals(testIv3, new byte[] {(byte) 0xFF, (byte) 0xFF, (byte) 0xFF});
+
+    // 00000000 00000000 00000000
+    CryptoModuleParameters.incrementIV(testIv3, testIv3.length - 1);
+    assertArrayEquals(testIv3, new byte[] {(byte) 0x00, (byte) 0x00, (byte) 0x00});
+
+    // 00000000 00000000 00000001
+    CryptoModuleParameters.incrementIV(testIv3, testIv3.length - 1);
+    assertArrayEquals(testIv3, new byte[] {(byte) 0x00, (byte) 0x00, (byte) 0x01});
+
+  }
+
+  /**
+   * Used in AESGCM unit tests to encrypt data. Uses MARKER_STRING and MARKER_INT
+   *
+   * @param conf
+   *          The accumulo configuration
+   * @param initVector
+   *          The IV to be used in encryption
+   * @return the encrypted string
+   * @throws IOException
+   *           if DataOutputStream fails
+   */
+  private static byte[] testEncryption(AccumuloConfiguration conf, byte[] initVector) throws
IOException {
+    CryptoModuleParameters params = CryptoModuleFactory.createParamsObjectFromAccumuloConfiguration(conf);
+    CryptoModule cryptoModule = CryptoModuleFactory.getCryptoModule(conf);
+    params.getAllOptions().put(Property.CRYPTO_WAL_CIPHER_SUITE.getKey(), "AES/GCM/NoPadding");
+    params.setInitializationVector(initVector);
+
+    /*
+     * Now lets encrypt this data!
+     */
+    ByteArrayOutputStream encryptedByteStream = new ByteArrayOutputStream();
+    params.setPlaintextOutputStream(new NoFlushOutputStream(encryptedByteStream));
+    params = cryptoModule.getEncryptingOutputStream(params);
+    DataOutputStream encryptedDataStream = new DataOutputStream(params.getEncryptedOutputStream());
+    encryptedDataStream.writeUTF(MARKER_STRING);
+    encryptedDataStream.writeInt(MARKER_INT);
+    encryptedDataStream.close();
+    byte[] encryptedBytes = encryptedByteStream.toByteArray();
+    return (encryptedBytes);
+  }
+
+  /**
+   * Used in AESGCM unit tests to decrypt data. Uses MARKER_STRING and MARKER_INT
+   *
+   * @param conf
+   *          The accumulo configuration
+   * @param encryptedBytes
+   *          The encrypted bytes
+   * @return 0 if data is incorrectly decrypted, 1 if decrypted data matches input
+   * @throws IOException
+   *           if DataInputStream fails
+   * @throws AEADBadTagException
+   *           if the encrypted stream has been modified
+   */
+  private static Integer testDecryption(AccumuloConfiguration conf, byte[] encryptedBytes)
throws IOException, AEADBadTagException {
+    CryptoModuleParameters params = CryptoModuleFactory.createParamsObjectFromAccumuloConfiguration(conf);
+    CryptoModule cryptoModule = CryptoModuleFactory.getCryptoModule(conf);
+    ByteArrayInputStream decryptedByteStream = new ByteArrayInputStream(encryptedBytes);
+    params.setEncryptedInputStream(decryptedByteStream);
+    params = cryptoModule.getDecryptingInputStream(params);
+    DataInputStream decryptedDataStream = new DataInputStream(params.getPlaintextInputStream());
+
+    String utf;
+    Integer in;
+    try {
+      utf = decryptedDataStream.readUTF();
+      in = decryptedDataStream.readInt();
+    } catch (IOException e) {
+      if (e.getCause().getClass().equals(AEADBadTagException.class)) {
+        throw new AEADBadTagException();
+      } else {
+        throw e;
+      }
+    }
+
+    decryptedDataStream.close();
+    if (utf.equals(MARKER_STRING) && in.equals(MARKER_INT)) {
+      return 1;
+    } else {
+      return 0;
+    }
+  }
+
 }
diff --git a/core/src/test/resources/crypto-on-accumulo-site.xml b/core/src/test/resources/crypto-on-accumulo-site.xml
index 6d9ef13697..953e26af5a 100644
--- a/core/src/test/resources/crypto-on-accumulo-site.xml
+++ b/core/src/test/resources/crypto-on-accumulo-site.xml
@@ -75,9 +75,13 @@
       <name>crypto.module.class</name>
       <value>org.apache.accumulo.core.security.crypto.DefaultCryptoModule</value>
     </property>
+    <property>
+      <name>crypto.security.provider</name>
+      <value>SunJCE</value>
+    </property>
     <property>
       <name>crypto.cipher.suite</name>
-      <value>AES/CFB/NoPadding</value>
+      <value>AES/GCM/NoPadding</value>
     </property>
     <property>
       <name>crypto.wal.cipher.suite</name>
@@ -127,7 +131,7 @@
     
     <property>
     	<name>crypto.default.key.strategy.cipher.suite</name>
-    	<value>AES/ECB/NoPadding</value>
+    	<value>AESWrap/ECB/NoPadding</value>
     </property>
 
 </configuration>
diff --git a/core/src/test/resources/crypto-on-no-key-encryption-accumulo-site.xml b/core/src/test/resources/crypto-on-no-key-encryption-accumulo-site.xml
index a82f9f9d73..f4776826fd 100644
--- a/core/src/test/resources/crypto-on-no-key-encryption-accumulo-site.xml
+++ b/core/src/test/resources/crypto-on-no-key-encryption-accumulo-site.xml
@@ -79,6 +79,10 @@
       <name>crypto.cipher.suite</name>
       <value>AES/CFB/NoPadding</value>
     </property>
+    <property>
+      <name>crypto.wal.cipher.suite</name>
+      <value>AES/CBC/NoPadding</value>
+    </property>
     <property>
       <name>crypto.cipher.key.algorithm.name</name>
       <value>AES</value>
diff --git a/server/tserver/src/main/java/org/apache/accumulo/tserver/log/DfsLogger.java b/server/tserver/src/main/java/org/apache/accumulo/tserver/log/DfsLogger.java
index d48907f7e6..5fe8d56a28 100644
--- a/server/tserver/src/main/java/org/apache/accumulo/tserver/log/DfsLogger.java
+++ b/server/tserver/src/main/java/org/apache/accumulo/tserver/log/DfsLogger.java
@@ -468,7 +468,8 @@ public synchronized void open(String address) throws IOException {
 
       CryptoModuleParameters params = CryptoModuleFactory.createParamsObjectFromAccumuloConfiguration(conf.getConfiguration());
       // Immediately update to the correct cipher. Doing this here keeps the CryptoModule
independent of the writers using it
-      if (params.getAllOptions().get(Property.CRYPTO_WAL_CIPHER_SUITE.getKey()) != null)
{
+      if (params.getAllOptions().get(Property.CRYPTO_WAL_CIPHER_SUITE.getKey()) != null
+          && !params.getAllOptions().get(Property.CRYPTO_WAL_CIPHER_SUITE.getKey()).equals(""))
{
         params.setCipherSuite(params.getAllOptions().get(Property.CRYPTO_WAL_CIPHER_SUITE.getKey()));
       }
 


 

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

Mime
View raw message