You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@accumulo.apache.org by ct...@apache.org on 2013/07/17 04:33:36 UTC

[34/50] [abbrv] git commit: ACCUMULO-998 applying Micheal Allen's updated patch for at-rest encryption

ACCUMULO-998 applying Micheal Allen's updated patch for at-rest encryption

git-svn-id: https://svn.apache.org/repos/asf/accumulo/trunk@1502316 13f79535-47bb-0310-9956-ffa450edef68


Project: http://git-wip-us.apache.org/repos/asf/accumulo/repo
Commit: http://git-wip-us.apache.org/repos/asf/accumulo/commit/65b5a3a3
Tree: http://git-wip-us.apache.org/repos/asf/accumulo/tree/65b5a3a3
Diff: http://git-wip-us.apache.org/repos/asf/accumulo/diff/65b5a3a3

Branch: refs/heads/ACCUMULO-1496
Commit: 65b5a3a3708dc96e09e95c00a0fbe72e60edf3ad
Parents: 3b624e1
Author: Eric C. Newton <ec...@apache.org>
Authored: Thu Jul 11 18:17:04 2013 +0000
Committer: Eric C. Newton <ec...@apache.org>
Committed: Thu Jul 11 18:17:04 2013 +0000

----------------------------------------------------------------------
 conf/examples/crypto/accumulo-site.xml          | 160 +++++
 conf/examples/crypto/readme.txt                 |   5 +
 .../org/apache/accumulo/core/conf/Property.java |  84 +--
 .../accumulo/core/conf/SiteConfiguration.java   |  11 +
 .../file/blockfile/impl/CachableBlockFile.java  |   2 +-
 .../accumulo/core/file/rfile/bcfile/BCFile.java | 383 ++++++++++-
 .../core/file/rfile/bcfile/Compression.java     |   4 +-
 .../core/security/crypto/CryptoModule.java      | 110 ++--
 .../security/crypto/CryptoModuleFactory.java    | 184 +++---
 .../security/crypto/CryptoModuleParameters.java | 629 ++++++++++++++++++
 .../security/crypto/DefaultCryptoModule.java    | 483 +++++++++-----
 .../crypto/DefaultCryptoModuleUtils.java        |   1 -
 .../DefaultSecretKeyEncryptionStrategy.java     | 326 ++++-----
 .../crypto/DiscardCloseOutputStream.java        |  39 ++
 .../crypto/SecretKeyEncryptionStrategy.java     |   7 +-
 .../accumulo/core/file/rfile/RFileTest.java     | 658 ++++++++++++++++++-
 .../core/security/crypto/CryptoTest.java        | 390 +++++++++++
 .../test/resources/crypto-off-accumulo-site.xml | 111 ++++
 .../test/resources/crypto-on-accumulo-site.xml  | 164 +++++
 ...rypto-on-no-key-encryption-accumulo-site.xml | 144 ++++
 pom.xml                                         |   2 +-
 .../server/tabletserver/log/DfsLogger.java      |  24 +-
 .../server/tabletserver/log/LogSorter.java      |  61 +-
 23 files changed, 3317 insertions(+), 665 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/accumulo/blob/65b5a3a3/conf/examples/crypto/accumulo-site.xml
----------------------------------------------------------------------
diff --git a/conf/examples/crypto/accumulo-site.xml b/conf/examples/crypto/accumulo-site.xml
new file mode 100644
index 0000000..77bf8db
--- /dev/null
+++ b/conf/examples/crypto/accumulo-site.xml
@@ -0,0 +1,160 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
+
+<configuration>
+	<!--
+  Put your site-specific accumulo configurations here.
+
+  The available configuration values along with their defaults
+  are documented in docs/config.html
+
+  Unless you are simply testing at your workstation, you will most
+  definitely need to change the three entries below.
+	-->
+
+    <property>
+      <name>instance.zookeeper.host</name>
+      <value>localhost:2181</value>
+      <description>comma separated list of zookeeper servers</description>
+    </property>
+
+    <property>
+      <name>logger.dir.walog</name>
+      <value>walogs</value>
+      <description>The directory used to store write-ahead logs on the local filesystem. It is possible to specify a comma-separated list of directories.</description>
+    </property>
+
+    <property>
+      <name>instance.secret</name>
+      <value>DEFAULT</value>
+      <description>A secret unique to a given instance that all servers must know in order to communicate with one another.
+                   Change it before initialization. To change it later use ./bin/accumulo org.apache.accumulo.server.util.ChangeSecret [oldpasswd] [newpasswd],
+                   and then update this file.
+      </description>
+    </property>
+
+    <property>
+      <name>tserver.memory.maps.max</name>
+      <value>80M</value>
+    </property>
+
+    <property>
+      <name>tserver.cache.data.size</name>
+      <value>7M</value>
+    </property>
+
+    <property>
+      <name>tserver.cache.index.size</name>
+      <value>20M</value>
+    </property>
+
+    <property>
+      <name>trace.password</name>
+      <!--
+        change this to the root user's password, and/or change the user below
+       -->
+      <value>password</value>
+    </property>
+
+    <property>
+      <name>trace.user</name>
+      <value>root</value>
+    </property>
+
+    <property>
+      <name>tserver.sort.buffer.size</name>
+      <value>50M</value>
+    </property>
+
+    <property>
+      <name>tserver.walog.max.size</name>
+      <value>100M</value>
+    </property>
+
+    <property>
+      <name>general.classpaths</name>
+      <value>
+    $ACCUMULO_HOME/server/target/classes/,
+    $ACCUMULO_HOME/core/target/classes/,
+    $ACCUMULO_HOME/start/target/classes/,
+    $ACCUMULO_HOME/fate/target/classes/,
+    $ACCUMULO_HOME/proxy/target/classes/,
+    $ACCUMULO_HOME/examples/target/classes/,
+	$ACCUMULO_HOME/lib/[^.].$ACCUMULO_VERSION.jar,
+	$ACCUMULO_HOME/lib/[^.].*.jar,
+	$ZOOKEEPER_HOME/zookeeper[^.].*.jar,
+	$HADOOP_CONF_DIR,
+	$HADOOP_PREFIX/[^.].*.jar,
+	$HADOOP_PREFIX/lib/[^.].*.jar,
+      </value>
+      <description>Classpaths that accumulo checks for updates and class files.
+      When using the Security Manager, please remove the ".../target/classes/" values.
+      </description>
+    </property>
+
+    <property>
+      <name>crypto.module.class</name>
+      <value>org.apache.accumulo.core.security.crypto.DefaultCryptoModule</value>
+    </property>
+    <property>
+      <name>crypto.cipher.suite</name>
+      <value>AES/CFB/PKCS5Padding</value>
+    </property>
+    <property>
+      <name>crypto.cipher.algorithm.name</name>
+      <value>AES</value>
+    </property>
+    <property>
+      <name>crypto.cipher.key.length</name>
+      <value>128</value>
+    </property>
+    <property>
+      <name>crypto.secure.rng</name>
+      <value>SHA1PRNG</value>
+    </property>
+    <property>
+      <name>crypto.secure.rng.provider</name>
+      <value>SUN</value>
+    </property>
+
+    <property>
+      <name>crypto.secret.key.encryption.strategy.class</name>
+      <value>org.apache.accumulo.core.security.crypto.DefaultSecretKeyEncryptionStrategy</value>
+    </property>
+
+    <property>
+        <name>crypto.default.key.strategy.cipher.suite</name>
+        <value>AES/ECB/NoPadding</value>
+    </property>
+<!--
+     These properties can be useful for situations where you are conducting unit tests without HDFS
+    running.
+-->
+
+<!--
+    <property>
+      <name>crypto.default.key.strategy.hdfs.uri</name>
+      <value>file:///</value>
+    </property>
+    <property>
+      <name>crypto.default.key.strategy.key.location</name>
+      <value>/tmp/test.secret.key</value>
+    </property>
+-->
+</configuration>

http://git-wip-us.apache.org/repos/asf/accumulo/blob/65b5a3a3/conf/examples/crypto/readme.txt
----------------------------------------------------------------------
diff --git a/conf/examples/crypto/readme.txt b/conf/examples/crypto/readme.txt
new file mode 100644
index 0000000..c638b6e
--- /dev/null
+++ b/conf/examples/crypto/readme.txt
@@ -0,0 +1,5 @@
+This accumulo-site.xml file demonstrates how to configure the basic encryption at rest feature.  
+
+The default configuration shown here is not entirely secure, as the master key for all encryption keys
+is stored alongside the encrypted files.  Placing that master key somewhere secure is an exercise
+left to the reader.

http://git-wip-us.apache.org/repos/asf/accumulo/blob/65b5a3a3/core/src/main/java/org/apache/accumulo/core/conf/Property.java
----------------------------------------------------------------------
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 8572a2e..ca86c9a 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
@@ -59,11 +59,20 @@ public enum Property {
       "The class Accumulo should use for its key encryption strategy."),
   @Experimental
   CRYPTO_DEFAULT_KEY_STRATEGY_HDFS_URI("crypto.default.key.strategy.hdfs.uri", "", PropertyType.STRING,
-      "The URL Accumulo should use to connect to DFS. If this is blank, Accumulo will obtain this information from the Hadoop configuration"),
+      "The path relative to the top level instance directory (instance.dfs.dir) where to store the key encryption key within HDFS."),
   @Experimental
-  CRYPTO_DEFAULT_KEY_STRATEGY_KEY_LOCATION("crypto.default.key.strategy.key.location", "/accumulo/crypto/secret/keyEncryptionKey", PropertyType.ABSOLUTEPATH,
-      "The absolute path of where to store the key encryption key within HDFS."),
-  
+  CRYPTO_DEFAULT_KEY_STRATEGY_KEY_LOCATION("crypto.default.key.strategy.key.location", "/crypto/secret/keyEncryptionKey", PropertyType.ABSOLUTEPATH,
+      "The path relative to the top level instance directory (instance.dfs.dir) where to store the key encryption key within HDFS."),
+  @Experimental
+  CRYPTO_DEFAULT_KEY_STRATEGY_CIPHER_SUITE("crypto.default.key.strategy.cipher.suite", "NullCipher", PropertyType.STRING,
+      "The cipher suite to use when encrypting session keys with a key encryption key.  This should be set to match the overall encryption algorithm  " +
+      "but with ECB mode and no padding unless you really know what you're doing and are sure you won't break internal file formats"),
+  @Experimental
+  CRYPTO_OVERRIDE_KEY_STRATEGY_WITH_CONFIGURED_STRATEGY("crypto.override.key.strategy.with.configured.strategy", "false", PropertyType.BOOLEAN,
+          "The default behavior is to record the key encryption strategy with the encrypted file, and continue to use that strategy for the life " +
+          "of that file.  Sometimes, you change your strategy and want to use the new strategy, not the old one.  (Most commonly, this will be " +
+          "because you have moved key material from one spot to another.)  If you want to override the recorded key strategy with the one in " +
+          "the configuration file, set this property to true."),
   // instance properties (must be the same for every node in an instance)
   INSTANCE_PREFIX("instance.", null, PropertyType.PREFIX,
       "Properties in this category must be consistent throughout a cloud. This is enforced and servers won't be able to communicate if these differ."),
@@ -86,7 +95,7 @@ public enum Property {
       "The authorizor class that accumulo will use to determine what labels a user has privilege to see"),
   INSTANCE_SECURITY_PERMISSION_HANDLER("instance.security.permissionHandler", "org.apache.accumulo.server.security.handler.ZKPermHandler",
       PropertyType.CLASSNAME, "The permission handler class that accumulo will use to determine if a user has privilege to perform an action"),
-  
+
   // general properties
   GENERAL_PREFIX("general.", null, PropertyType.PREFIX,
       "Properties in this category affect the behavior of accumulo overall, but do not have to be consistent throughout a cloud."),
@@ -103,7 +112,6 @@ public enum Property {
   GENERAL_MAX_MESSAGE_SIZE("tserver.server.message.size.max", "1G", PropertyType.MEMORY, "The maximum size of a message that can be sent to a tablet server."),
   GENERAL_VOLUME_CHOOSER("general.volume.chooser", "org.apache.accumulo.server.fs.RandomVolumeChooser", PropertyType.CLASSNAME, "The class that will be used to select which volume will be used to create new files."),
 
-  
   // properties that are specific to master server behavior
   MASTER_PREFIX("master.", null, PropertyType.PREFIX, "Properties in this category affect the behavior of the master server"),
   MASTER_CLIENTPORT("master.port.client", "9999", PropertyType.PORT, "The port used for handling client connections on the master"),
@@ -124,7 +132,7 @@ public enum Property {
       "A class that implements a mechansim to steal write access to a file"),
   MASTER_FATE_THREADPOOL_SIZE("master.fate.threadpool.size", "4", PropertyType.COUNT,
       "The number of threads used to run FAult-Tolerant Executions.  These are primarily table operations like merge."),
-  
+
   // properties that are specific to tablet server behavior
   TSERV_PREFIX("tserver.", null, PropertyType.PREFIX, "Properties in this category affect the behavior of the tablet servers"),
   TSERV_CLIENT_TIMEOUT("tserver.client.timeout", "3s", PropertyType.TIMEDURATION, "Time to wait for clients to continue scans before closing a session."),
@@ -212,14 +220,14 @@ public enum Property {
       "The number of threads for the distributed workq.  These threads are used for copying failed bulk files."),
   TSERV_WAL_SYNC("tserver.wal.sync", "true", PropertyType.BOOLEAN,
       "Use the SYNC_BLOCK create flag to sync WAL writes to disk. Prevents problems recovering from sudden system resets."),
-  
+
   // properties that are specific to logger server behavior
   LOGGER_PREFIX("logger.", null, PropertyType.PREFIX, "Properties in this category affect the behavior of the write-ahead logger servers"),
   LOGGER_DIR("logger.dir.walog", "walogs", PropertyType.PATH,
       "The property only needs to be set if upgrading from 1.4 which used to store write-ahead logs on the local filesystem. In 1.5 write-ahead logs are "
           + "stored in DFS.  When 1.5 is started for the first time it will copy any 1.4 write ahead logs into DFS.  It is possible to specify a "
           + "comma-separated list of directories."),
-  
+
   // accumulo garbage collector properties
   GC_PREFIX("gc.", null, PropertyType.PREFIX, "Properties in this category affect the behavior of the accumulo garbage collector."),
   GC_CYCLE_START("gc.cycle.start", "30s", PropertyType.TIMEDURATION, "Time to wait before attempting to garbage collect any old files."),
@@ -228,7 +236,7 @@ public enum Property {
   GC_PORT("gc.port.client", "50091", PropertyType.PORT, "The listening port for the garbage collector's monitor service"),
   GC_DELETE_THREADS("gc.threads.delete", "16", PropertyType.COUNT, "The number of threads used to delete files"),
   GC_TRASH_IGNORE("gc.trash.ignore", "false", PropertyType.BOOLEAN, "Do not use the Trash, even if it is configured"),
-  
+
   // properties that are specific to the monitor server behavior
   MONITOR_PREFIX("monitor.", null, PropertyType.PREFIX, "Properties in this category affect the behavior of the monitor web server."),
   MONITOR_PORT("monitor.port.client", "50095", PropertyType.PORT, "The listening port for the monitor's http service"),
@@ -237,6 +245,7 @@ public enum Property {
   MONITOR_BANNER_COLOR("monitor.banner.color", "#c4c4c4", PropertyType.STRING, "The color of the banner text displayed on the monitor page."),
   MONITOR_BANNER_BACKGROUND("monitor.banner.background", "#304065", PropertyType.STRING,
       "The background color of the banner text displayed on the monitor page."),
+
   @Experimental
   MONITOR_SSL_KEYSTORE("monitor.ssl.keyStore", "", PropertyType.PATH, "The keystore for enabling monitor SSL."),
   @Experimental
@@ -258,7 +267,7 @@ public enum Property {
   TRACE_TOKEN_PROPERTY_PREFIX("trace.token.property", null, PropertyType.PREFIX,
       "The prefix used to create a token for storing distributed traces.  For each propetry required by trace.token.type, place this prefix in front of it."),
   TRACE_TOKEN_TYPE("trace.token.type", PasswordToken.class.getName(), PropertyType.CLASSNAME, "An AuthenticationToken type supported by the authorizer"),
-  
+
   // per table properties
   TABLE_PREFIX("table.", null, PropertyType.PREFIX, "Properties in this category affect tablet server treatment of tablets, but can be configured "
       + "on a per-table basis. Setting these properties in the site file will override the default globally "
@@ -353,7 +362,7 @@ public enum Property {
   TABLE_INTERPRETER_CLASS("table.interepreter", DefaultScanInterpreter.class.getName(), PropertyType.STRING,
       "The ScanInterpreter class to apply on scan arguments in the shell"),
   TABLE_CLASSPATH("table.classpath.context", "", PropertyType.STRING, "Per table classpath context"),
-  
+
   // VFS ClassLoader properties
   VFS_CLASSLOADER_SYSTEM_CLASSPATH_PROPERTY(AccumuloVFSClassLoader.VFS_CLASSLOADER_SYSTEM_CLASSPATH_PROPERTY, "", PropertyType.STRING,
       "Configuration for a system level vfs classloader.  Accumulo jar can be configured here and loaded out of HDFS."),
@@ -376,6 +385,7 @@ public enum Property {
   
   ;
   
+
   private String key, defaultValue, description;
   private PropertyType type;
   static Logger log = Logger.getLogger(Property.class);
@@ -386,20 +396,20 @@ public enum Property {
     this.description = description;
     this.type = type;
   }
-  
+
   @Override
   public String toString() {
     return this.key;
   }
-  
+
   public String getKey() {
     return this.key;
   }
-  
+
   public String getRawDefaultValue() {
     return this.defaultValue;
   }
-  
+
   public String getDefaultValue() {
     if (isInterpolated()) {
       PropertiesConfiguration pconf = new PropertiesConfiguration();
@@ -414,19 +424,19 @@ public enum Property {
       return getRawDefaultValue();
     }
   }
-  
+
   public PropertyType getType() {
     return this.type;
   }
-  
+
   public String getDescription() {
     return this.description;
   }
-  
+
   private boolean isInterpolated() {
     return hasAnnotation(Interpolated.class) || hasPrefixWithAnnotation(getKey(), Interpolated.class);
   }
-  
+
   public boolean isExperimental() {
     return hasAnnotation(Experimental.class) || hasPrefixWithAnnotation(getKey(), Experimental.class);
   }
@@ -472,25 +482,25 @@ public enum Property {
     }
     return false;
   }
-  
+
   private static HashSet<String> validTableProperties = null;
   private static HashSet<String> validProperties = null;
   private static HashSet<String> validPrefixes = null;
-  
+
   private static boolean isKeyValidlyPrefixed(String key) {
     for (String prefix : validPrefixes) {
       if (key.startsWith(prefix))
         return true;
     }
-    
+
     return false;
   }
-  
+
   public synchronized static boolean isValidPropertyKey(String key) {
     if (validProperties == null) {
       validProperties = new HashSet<String>();
       validPrefixes = new HashSet<String>();
-      
+
       for (Property p : Property.values()) {
         if (p.getType().equals(PropertyType.PREFIX)) {
           validPrefixes.add(p.getKey());
@@ -499,10 +509,10 @@ public enum Property {
         }
       }
     }
-    
+
     return validProperties.contains(key) || isKeyValidlyPrefixed(key);
   }
-  
+
   public synchronized static boolean isValidTablePropertyKey(String key) {
     if (validTableProperties == null) {
       validTableProperties = new HashSet<String>();
@@ -512,36 +522,36 @@ public enum Property {
         }
       }
     }
-    
+
     return validTableProperties.contains(key) || key.startsWith(Property.TABLE_CONSTRAINT_PREFIX.getKey())
         || key.startsWith(Property.TABLE_ITERATOR_PREFIX.getKey()) || key.startsWith(Property.TABLE_LOCALITY_GROUP_PREFIX.getKey());
   }
-  
+
   private static final EnumSet<Property> fixedProperties = EnumSet.of(Property.TSERV_CLIENTPORT, Property.TSERV_NATIVEMAP_ENABLED,
       Property.TSERV_SCAN_MAX_OPENFILES, Property.MASTER_CLIENTPORT, Property.GC_PORT);
-  
+
   public static boolean isFixedZooPropertyKey(Property key) {
     return fixedProperties.contains(key);
   }
-  
+
   public static Set<Property> getFixedProperties() {
     return fixedProperties;
   }
-  
+
   public static boolean isValidZooPropertyKey(String key) {
     // white list prefixes
     return key.startsWith(Property.TABLE_PREFIX.getKey()) || key.startsWith(Property.TSERV_PREFIX.getKey()) || key.startsWith(Property.LOGGER_PREFIX.getKey())
         || key.startsWith(Property.MASTER_PREFIX.getKey()) || key.startsWith(Property.GC_PREFIX.getKey())
         || key.startsWith(Property.MONITOR_PREFIX.getKey() + "banner.") || key.startsWith(VFS_CONTEXT_CLASSPATH_PROPERTY.getKey());
   }
-  
+
   public static Property getPropertyByKey(String key) {
     for (Property prop : Property.values())
       if (prop.getKey().equals(key))
         return prop;
     return null;
   }
-  
+
   /**
    * @return true if this is a property whose value is expected to be a java class
    */
@@ -550,11 +560,11 @@ public enum Property {
         || (key.startsWith(Property.TABLE_ITERATOR_PREFIX.getKey()) && key.substring(Property.TABLE_ITERATOR_PREFIX.getKey().length()).split("\\.").length == 2)
         || key.equals(Property.TABLE_LOAD_BALANCER.getKey());
   }
-  
+
   public static <T> T createInstanceFromPropertyName(AccumuloConfiguration conf, Property property, Class<T> base, T defaultInstance) {
     String clazzName = conf.get(property);
     T instance = null;
-    
+
     try {
       Class<? extends T> clazz = AccumuloVFSClassLoader.loadClass(clazzName, base);
       instance = clazz.newInstance();
@@ -562,7 +572,7 @@ public enum Property {
     } catch (Exception e) {
       log.warn("Failed to load class ", e);
     }
-    
+
     if (instance == null) {
       log.info("Using " + defaultInstance.getClass().getName());
       instance = defaultInstance;

http://git-wip-us.apache.org/repos/asf/accumulo/blob/65b5a3a3/core/src/main/java/org/apache/accumulo/core/conf/SiteConfiguration.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/accumulo/core/conf/SiteConfiguration.java b/core/src/main/java/org/apache/accumulo/core/conf/SiteConfiguration.java
index b8e1337..a1e2572 100644
--- a/core/src/main/java/org/apache/accumulo/core/conf/SiteConfiguration.java
+++ b/core/src/main/java/org/apache/accumulo/core/conf/SiteConfiguration.java
@@ -90,6 +90,17 @@ public class SiteConfiguration extends AccumuloConfiguration {
     getXmlConfig().clear();
   }
   
+  
+  /**
+   * method here to support testing, do not call
+   */
+  public synchronized void clearAndNull() {
+    if (xmlConfig != null) {
+      xmlConfig.clear();
+      xmlConfig = null;
+    }
+  }
+  
   /**
    * method here to support testing, do not call
    */

http://git-wip-us.apache.org/repos/asf/accumulo/blob/65b5a3a3/core/src/main/java/org/apache/accumulo/core/file/blockfile/impl/CachableBlockFile.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/accumulo/core/file/blockfile/impl/CachableBlockFile.java b/core/src/main/java/org/apache/accumulo/core/file/blockfile/impl/CachableBlockFile.java
index d788f39..5e46215 100644
--- a/core/src/main/java/org/apache/accumulo/core/file/blockfile/impl/CachableBlockFile.java
+++ b/core/src/main/java/org/apache/accumulo/core/file/blockfile/impl/CachableBlockFile.java
@@ -130,7 +130,7 @@ public class CachableBlockFile {
     @Override
     public long getStartPos() throws IOException {
       return _ba.getStartPos();
-    }
+    }    
     
   }
   

http://git-wip-us.apache.org/repos/asf/accumulo/blob/65b5a3a3/core/src/main/java/org/apache/accumulo/core/file/rfile/bcfile/BCFile.java
----------------------------------------------------------------------
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 7277c65..35cd82e 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
@@ -28,9 +28,12 @@ import java.io.InputStream;
 import java.io.OutputStream;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.HashMap;
 import java.util.Map;
 import java.util.TreeMap;
 
+import org.apache.accumulo.core.conf.AccumuloConfiguration;
+import org.apache.accumulo.core.conf.Property;
 import org.apache.accumulo.core.file.blockfile.impl.CachableBlockFile;
 import org.apache.accumulo.core.file.blockfile.impl.CachableBlockFile.BlockRead;
 import org.apache.accumulo.core.file.rfile.bcfile.CompareUtils.Scalar;
@@ -38,6 +41,10 @@ import org.apache.accumulo.core.file.rfile.bcfile.CompareUtils.ScalarComparator;
 import org.apache.accumulo.core.file.rfile.bcfile.CompareUtils.ScalarLong;
 import org.apache.accumulo.core.file.rfile.bcfile.Compression.Algorithm;
 import org.apache.accumulo.core.file.rfile.bcfile.Utils.Version;
+import org.apache.accumulo.core.security.crypto.CryptoModule;
+import org.apache.accumulo.core.security.crypto.CryptoModuleFactory;
+import org.apache.accumulo.core.security.crypto.CryptoModuleParameters;
+import org.apache.accumulo.core.security.crypto.SecretKeyEncryptionStrategy;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.hadoop.conf.Configuration;
@@ -54,7 +61,8 @@ import org.apache.hadoop.io.compress.Decompressor;
 public final class BCFile {
   // the current version of BCFile impl, increment them (major or minor) made
   // enough changes
-  static final Version API_VERSION = new Version((short) 1, (short) 0);
+  static final Version API_VERSION = new Version((short) 2, (short) 0);
+  static final Version API_VERSION_1 = new Version((short) 1, (short) 0);
   static final Log LOG = LogFactory.getLog(BCFile.class);
   
   /**
@@ -70,6 +78,10 @@ public final class BCFile {
   static public class Writer implements Closeable {
     private final FSDataOutputStream out;
     private final Configuration conf;
+    private final CryptoModule cryptoModule;
+    private final Map<String,String> cryptoConf;
+    private BCFileCryptoModuleParameters cryptoParams;
+    private SecretKeyEncryptionStrategy secretKeyEncryptionStrategy;
     // the single meta block containing index of compressed data blocks
     final DataIndex dataIndex;
     // index for meta blocks
@@ -80,6 +92,7 @@ public final class BCFile {
     long errorCount = 0;
     // reusable buffers.
     private BytesWritable fsOutputBuffer;
+
     
     /**
      * Call-back interface to register a block after a block is closed.
@@ -106,6 +119,7 @@ public final class BCFile {
       private Compressor compressor; // !null only if using native
       // Hadoop compression
       private final FSDataOutputStream fsOut;
+      private final OutputStream cipherOut;
       private final long posStart;
       private final SimpleBufferedOutputStream fsBufferedOutput;
       private OutputStream out;
@@ -113,20 +127,60 @@ public final class BCFile {
       /**
        * @param compressionAlgo
        *          The compression algorithm to be used to for compression.
+       * @param cryptoModule the module to use to obtain cryptographic streams
+       * @param cryptoParams TODO
        * @throws IOException
        */
-      public WBlockState(Algorithm compressionAlgo, FSDataOutputStream fsOut, BytesWritable fsOutputBuffer, Configuration conf) throws IOException {
+      public WBlockState(Algorithm compressionAlgo, FSDataOutputStream fsOut, BytesWritable fsOutputBuffer, Configuration conf, CryptoModule cryptoModule, CryptoModuleParameters cryptoParams) throws IOException {
         this.compressAlgo = compressionAlgo;
         this.fsOut = fsOut;
         this.posStart = fsOut.getPos();
         
         fsOutputBuffer.setCapacity(TFile.getFSOutputBufferSize(conf));
-        
+
         this.fsBufferedOutput = new SimpleBufferedOutputStream(this.fsOut, fsOutputBuffer.getBytes());
+        
+        // *This* is very important.  Without this, when the crypto stream is closed (in order to flush its last bytes),
+        // the underlying RFile stream will *also* be closed, and that's undesirable as the cipher stream is closed for 
+        // every block written.
+        cryptoParams.setCloseUnderylingStreamAfterCryptoStreamClose(false);
+        
+        // *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);
+        
+        // Initialize the cipher including generating a new IV
+        cryptoParams = cryptoModule.initializeCipher(cryptoParams);
+        
+        // Write the init vector in plain text, uncompressed, to the output stream.  Due to the way the streams work out, there's no good way to write this compressed, but it's pretty small.
+        DataOutputStream tempDataOutputStream = new DataOutputStream(fsBufferedOutput);
+
+        // Init vector might be null if the underlying cipher does not require one (NullCipher being a good example)
+        if (cryptoParams.getInitializationVector() != null) {
+          tempDataOutputStream.writeInt(cryptoParams.getInitializationVector().length);
+          tempDataOutputStream.write(cryptoParams.getInitializationVector());
+        } else {
+          // Do nothing
+        }
+       
+        // Initialize the cipher stream and get the IV 
+        cryptoParams.setPlaintextOutputStream(tempDataOutputStream);
+        cryptoParams = cryptoModule.getEncryptingOutputStream(cryptoParams);
+        
+        if (cryptoParams.getEncryptedOutputStream() == tempDataOutputStream) {
+          this.cipherOut = fsBufferedOutput;
+        } else {        
+          this.cipherOut = cryptoParams.getEncryptedOutputStream();
+        }
+        
+        
         this.compressor = compressAlgo.getCompressor();
         
         try {
-          this.out = compressionAlgo.createCompressionStream(fsBufferedOutput, compressor, 0);
+          this.out = compressionAlgo.createCompressionStream(cipherOut, compressor, 0);
         } catch (IOException e) {
           compressAlgo.returnCompressor(compressor);
           throw e;
@@ -173,6 +227,18 @@ public final class BCFile {
         try {
           if (out != null) {
             out.flush();
+            
+            // If the cipherOut stream is different from the fsBufferedOutput stream, then we likely have
+            // an actual encrypted output stream that needs to be closed in order for it 
+            // to flush the final bytes to the output stream.  We should have set the flag to
+            // make sure that this close does *not* close the underlying stream, so calling
+            // close here should do the write thing.
+            
+            if (fsBufferedOutput != cipherOut) {
+              // Close the cipherOutputStream
+              cipherOut.close();
+            }
+            
             out = null;
           }
         } finally {
@@ -256,7 +322,7 @@ public final class BCFile {
           closed = true;
           blkInProgress = false;
         }
-      }
+      }     
     }
     
     /**
@@ -280,6 +346,29 @@ public final class BCFile {
       metaIndex = new MetaIndex();
       fsOutputBuffer = new BytesWritable();
       Magic.write(fout);
+      
+      // Set up crypto-related detail, including secret key generation and encryption
+      
+      @SuppressWarnings("deprecation")
+      AccumuloConfiguration accumuloConfiguration = AccumuloConfiguration.getSiteConfiguration();
+      this.cryptoConf = accumuloConfiguration.getAllPropertiesWithPrefix(Property.CRYPTO_PREFIX);
+
+      this.cryptoModule = CryptoModuleFactory.getCryptoModule(accumuloConfiguration);
+      Map<String,String> instanceProperties = accumuloConfiguration.getAllPropertiesWithPrefix(Property.INSTANCE_PREFIX);
+      if (instanceProperties != null) {
+        this.cryptoConf.putAll(instanceProperties);
+      }
+
+      this.cryptoParams = new BCFileCryptoModuleParameters();
+      CryptoModuleFactory.fillParamsObjectFromStringMap(cryptoParams, cryptoConf);
+      this.cryptoParams = (BCFileCryptoModuleParameters) cryptoModule.generateNewRandomSessionKey(cryptoParams);
+      
+      this.secretKeyEncryptionStrategy = CryptoModuleFactory.getSecretKeyEncryptionStrategy(accumuloConfiguration);      
+      this.cryptoParams = (BCFileCryptoModuleParameters) secretKeyEncryptionStrategy.encryptSecretKey(cryptoParams);
+      
+      
+      // secretKeyEncryptionStrategy.encryptSecretKey(cryptoParameters);
+      
     }
     
     /**
@@ -306,11 +395,21 @@ public final class BCFile {
           
           long offsetIndexMeta = out.getPos();
           metaIndex.write(out);
-          
-          // Meta Index and the trailing section are written out directly.
-          out.writeLong(offsetIndexMeta);
-          
-          API_VERSION.write(out);
+
+          if (cryptoParams.getAlgorithmName() == null || 
+              cryptoParams.getAlgorithmName().equals(Property.CRYPTO_CIPHER_SUITE.getDefaultValue())) {
+            out.writeLong(offsetIndexMeta);
+            API_VERSION_1.write(out);
+          } else {
+            long offsetCryptoParameters = out.getPos();
+            cryptoParams.write(out);
+            
+            // Meta Index, crypto params offsets and the trailing section are written out directly.
+            out.writeLong(offsetIndexMeta);
+            out.writeLong(offsetCryptoParameters);
+            API_VERSION.write(out);
+          }
+
           Magic.write(out);
           out.flush();
         }
@@ -333,7 +432,7 @@ public final class BCFile {
       }
       
       MetaBlockRegister mbr = new MetaBlockRegister(name, compressAlgo);
-      WBlockState wbs = new WBlockState(compressAlgo, out, fsOutputBuffer, conf);
+      WBlockState wbs = new WBlockState(compressAlgo, out, fsOutputBuffer, conf, cryptoModule, cryptoParams);
       BlockAppender ba = new BlockAppender(mbr, wbs);
       blkInProgress = true;
       metaBlkSeen = true;
@@ -391,7 +490,7 @@ public final class BCFile {
       
       DataBlockRegister dbr = new DataBlockRegister();
       
-      WBlockState wbs = new WBlockState(getDefaultCompressionAlgorithm(), out, fsOutputBuffer, conf);
+      WBlockState wbs = new WBlockState(getDefaultCompressionAlgorithm(), out, fsOutputBuffer, conf, cryptoModule, cryptoParams);
       BlockAppender ba = new BlockAppender(dbr, wbs);
       blkInProgress = true;
       return ba;
@@ -429,17 +528,67 @@ public final class BCFile {
     }
   }
   
+  private static class BCFileCryptoModuleParameters extends CryptoModuleParameters {
+
+    public void write(DataOutput out) throws IOException {
+      // Write out the context
+      out.writeInt(getAllOptions().size());
+      for (String key : getAllOptions().keySet()) {
+        out.writeUTF(key);
+        out.writeUTF(getAllOptions().get(key));
+      }
+      
+      // Write the opaque ID
+      out.writeUTF(getOpaqueKeyEncryptionKeyID());
+      
+      // Write the encrypted secret key
+      out.writeInt(getEncryptedKey().length);
+      out.write(getEncryptedKey());
+      
+    }
+    
+    public void read(DataInput in) throws IOException {
+      
+      Map<String,String> optionsFromFile = new HashMap<String,String>();
+      
+      
+      
+      int numContextEntries = in.readInt();
+      for (int i = 0; i < numContextEntries; i++) {
+        optionsFromFile.put(in.readUTF(), in.readUTF());
+      }
+      
+      CryptoModuleFactory.fillParamsObjectFromStringMap(this, optionsFromFile);
+      
+      // Read opaque key encryption ID
+      setOpaqueKeyEncryptionKeyID(in.readUTF());
+      
+      // Read encrypted secret key
+      int encryptedSecretKeyLength = in.readInt();
+      byte[] encryptedSecretKey = new byte[encryptedSecretKeyLength];
+      in.readFully(encryptedSecretKey);
+      setEncryptedKey(encryptedSecretKey);
+      
+    }
+
+    
+  }
+    
   /**
    * BCFile Reader, interface to read the file's data and meta blocks.
    */
   static public class Reader implements Closeable {
     private static final String META_NAME = "BCFile.metaindex";
+    private static final String CRYPTO_BLOCK_NAME = "BCFile.cryptoparams";
     private final FSDataInputStream in;
     private final Configuration conf;
     final DataIndex dataIndex;
     // Index for meta blocks
     final MetaIndex metaIndex;
     final Version version;
+    private BCFileCryptoModuleParameters cryptoParams;
+    private CryptoModule cryptoModule;
+    private SecretKeyEncryptionStrategy secretKeyEncryptionStrategy;
     
     /**
      * Intermediate class that maintain the state of a Readable Compression Block.
@@ -450,14 +599,38 @@ public final class BCFile {
       private final BlockRegion region;
       private final InputStream in;
       
-      public RBlockState(Algorithm compressionAlgo, FSDataInputStream fsin, BlockRegion region, Configuration conf) throws IOException {
+      public RBlockState(Algorithm compressionAlgo, FSDataInputStream fsin, BlockRegion region, Configuration conf, CryptoModule cryptoModule, Version bcFileVersion, CryptoModuleParameters cryptoParams) throws IOException {
         this.compressAlgo = compressionAlgo;
         this.region = region;
         this.decompressor = compressionAlgo.getDecompressor();
         
+        BoundedRangeFileInputStream boundedRangeFileInputStream = new BoundedRangeFileInputStream(fsin, this.region.getOffset(), this.region.getCompressedSize());
+        InputStream inputStreamToBeCompressed = boundedRangeFileInputStream;
+        
+        if (cryptoParams != null && cryptoModule != null) {
+          DataInputStream tempDataInputStream = new DataInputStream(boundedRangeFileInputStream);
+          // Read the init vector from the front of the stream before initializing the cipher stream
+          
+          int ivLength = tempDataInputStream.readInt();
+          byte[] initVector = new byte[ivLength];
+          tempDataInputStream.read(initVector);
+          
+          cryptoParams.setInitializationVector(initVector);
+          cryptoParams.setEncryptedInputStream(boundedRangeFileInputStream);
+          
+          
+          // These two flags mirror those in WBlockState, and are very necessary to set in order that the underlying stream be written and handled
+          // correctly.
+          cryptoParams.setCloseUnderylingStreamAfterCryptoStreamClose(false);
+          cryptoParams.setRecordParametersToStream(false);
+          
+          
+          cryptoParams = cryptoModule.getDecryptingInputStream(cryptoParams);
+          inputStreamToBeCompressed = cryptoParams.getPlaintextInputStream();
+        }
+        
         try {
-          this.in = compressAlgo.createDecompressionStream(new BoundedRangeFileInputStream(fsin, this.region.getOffset(), this.region.getCompressedSize()),
-              decompressor, TFile.getFSInputBufferSize(conf));
+          this.in = compressAlgo.createDecompressionStream(inputStreamToBeCompressed, decompressor, TFile.getFSInputBufferSize(conf));
         } catch (IOException e) {
           compressAlgo.returnDecompressor(decompressor);
           throw e;
@@ -567,23 +740,81 @@ public final class BCFile {
      * @throws IOException
      */
     public Reader(FSDataInputStream fin, long fileLength, Configuration conf) throws IOException {
+            
       this.in = fin;
       this.conf = conf;
       
-      // move the cursor to the beginning of the tail, containing: offset to the
-      // meta block index, version and magic
-      fin.seek(fileLength - Magic.size() - Version.size() - Long.SIZE / Byte.SIZE);
-      long offsetIndexMeta = fin.readLong();
+      
+      // Move the cursor to grab the version and the magic first
+      fin.seek(fileLength - Magic.size() - Version.size());
       version = new Version(fin);
       Magic.readAndVerify(fin);
-      
-      if (!version.compatibleWith(BCFile.API_VERSION)) {
+
+      // Do a version check
+      if (!version.compatibleWith(BCFile.API_VERSION) && !version.equals(BCFile.API_VERSION_1)) {
         throw new RuntimeException("Incompatible BCFile fileBCFileVersion.");
       }
       
+      // Read the right number offsets based on version
+      long offsetIndexMeta = 0;
+      long offsetCryptoParameters = 0;
+      
+      if (version.equals(API_VERSION_1)) {
+        fin.seek(fileLength - Magic.size() - Version.size() - ( Long.SIZE / Byte.SIZE ) );
+        offsetIndexMeta = fin.readLong();
+       
+      } else {
+        fin.seek(fileLength - Magic.size() - Version.size() - ( 2 * ( Long.SIZE / Byte.SIZE ) ));
+        offsetIndexMeta = fin.readLong();
+        offsetCryptoParameters = fin.readLong();
+      }
+      
+      
       // read meta index
       fin.seek(offsetIndexMeta);
       metaIndex = new MetaIndex(fin);
+
+      // If they exist, read the crypto parameters
+      if (!version.equals(BCFile.API_VERSION_1)) {
+         
+        @SuppressWarnings("deprecation")
+        AccumuloConfiguration accumuloConfiguration = AccumuloConfiguration.getSiteConfiguration();
+        
+        // read crypto parameters
+        fin.seek(offsetCryptoParameters);
+        cryptoParams = new BCFileCryptoModuleParameters();
+        cryptoParams.read(fin);
+        
+        this.cryptoModule = CryptoModuleFactory.getCryptoModule(cryptoParams.getAllOptions().get(Property.CRYPTO_MODULE_CLASS.getKey()));
+        
+        // TODO: Do I need this?  Hmmm, maybe I do.
+        if (accumuloConfiguration.getBoolean(Property.CRYPTO_OVERRIDE_KEY_STRATEGY_WITH_CONFIGURED_STRATEGY)) {
+          Map<String,String> cryptoConfFromAccumuloConf = accumuloConfiguration.getAllPropertiesWithPrefix(Property.CRYPTO_PREFIX);
+          Map<String,String> instanceConf = accumuloConfiguration.getAllPropertiesWithPrefix(Property.INSTANCE_PREFIX);
+          
+          cryptoConfFromAccumuloConf.putAll(instanceConf);
+          
+          for (String name : cryptoParams.getAllOptions().keySet()) {
+            if (!name.equals(Property.CRYPTO_SECRET_KEY_ENCRYPTION_STRATEGY_CLASS.getKey())) {
+              cryptoConfFromAccumuloConf.put(name, cryptoParams.getAllOptions().get(name));
+            } else {
+              cryptoParams.setKeyEncryptionStrategyClass(cryptoConfFromAccumuloConf.get(Property.CRYPTO_SECRET_KEY_ENCRYPTION_STRATEGY_CLASS.getKey()));
+            }
+          }
+          
+          cryptoParams.setAllOptions(cryptoConfFromAccumuloConf);
+        }
+        
+        this.secretKeyEncryptionStrategy = CryptoModuleFactory.getSecretKeyEncryptionStrategy(cryptoParams.getKeyEncryptionStrategyClass());
+  
+        // This call should put the decrypted session key within the cryptoParameters object
+        cryptoParams = (BCFileCryptoModuleParameters) secretKeyEncryptionStrategy.decryptSecretKey(cryptoParams);
+        
+        
+        //secretKeyEncryptionStrategy.decryptSecretKey(cryptoParameters);
+      } else {
+        LOG.trace("Found a version 1 file to read.");
+      }
       
       // read data:BCFile.index, the data block index
       BlockReader blockR = getMetaBlock(DataIndex.BLOCK_NAME);
@@ -600,22 +831,98 @@ public final class BCFile {
       
       BlockRead cachedMetaIndex = cache.getCachedMetaBlock(META_NAME);
       BlockRead cachedDataIndex = cache.getCachedMetaBlock(DataIndex.BLOCK_NAME);
+      BlockRead cachedCryptoParams = cache.getCachedMetaBlock(CRYPTO_BLOCK_NAME);
       
-      if (cachedMetaIndex == null || cachedDataIndex == null) {
+      if (cachedMetaIndex == null || cachedDataIndex == null || cachedCryptoParams == null) {
         // move the cursor to the beginning of the tail, containing: offset to the
         // meta block index, version and magic
-        fin.seek(fileLength - Magic.size() - Version.size() - Long.SIZE / Byte.SIZE);
-        long offsetIndexMeta = fin.readLong();
+        // Move the cursor to grab the version and the magic first
+        fin.seek(fileLength - Magic.size() - Version.size());
         version = new Version(fin);
         Magic.readAndVerify(fin);
-        
-        if (!version.compatibleWith(BCFile.API_VERSION)) {
+
+        // Do a version check
+        if (!version.compatibleWith(BCFile.API_VERSION) && !version.equals(BCFile.API_VERSION_1)) {
           throw new RuntimeException("Incompatible BCFile fileBCFileVersion.");
         }
         
+        // Read the right number offsets based on version
+        long offsetIndexMeta = 0;
+        long offsetCryptoParameters = 0;
+        
+        if (version.equals(API_VERSION_1)) {
+          fin.seek(fileLength - Magic.size() - Version.size() - ( Long.SIZE / Byte.SIZE ) );
+          offsetIndexMeta = fin.readLong();
+         
+        } else {
+          fin.seek(fileLength - Magic.size() - Version.size() - ( 2 * ( Long.SIZE / Byte.SIZE ) ));
+          offsetIndexMeta = fin.readLong();
+          offsetCryptoParameters = fin.readLong();
+        }
+           
         // read meta index
         fin.seek(offsetIndexMeta);
         metaIndex = new MetaIndex(fin);
+        
+        // If they exist, read the crypto parameters
+        if (!version.equals(BCFile.API_VERSION_1) && cachedCryptoParams == null) {
+          
+          @SuppressWarnings("deprecation")
+          AccumuloConfiguration accumuloConfiguration = AccumuloConfiguration.getSiteConfiguration();
+
+          
+          // read crypto parameters
+          fin.seek(offsetCryptoParameters);
+          cryptoParams = new BCFileCryptoModuleParameters();
+          cryptoParams.read(fin);
+          
+          
+          if (accumuloConfiguration.getBoolean(Property.CRYPTO_OVERRIDE_KEY_STRATEGY_WITH_CONFIGURED_STRATEGY)) {
+            Map<String,String> cryptoConfFromAccumuloConf = accumuloConfiguration.getAllPropertiesWithPrefix(Property.CRYPTO_PREFIX);
+            Map<String,String> instanceConf = accumuloConfiguration.getAllPropertiesWithPrefix(Property.INSTANCE_PREFIX);
+            
+            cryptoConfFromAccumuloConf.putAll(instanceConf);
+            
+            for (String name : cryptoParams.getAllOptions().keySet()) {
+              if (!name.equals(Property.CRYPTO_SECRET_KEY_ENCRYPTION_STRATEGY_CLASS.getKey())) {
+                cryptoConfFromAccumuloConf.put(name, cryptoParams.getAllOptions().get(name));
+              } else {
+                cryptoParams.setKeyEncryptionStrategyClass(cryptoConfFromAccumuloConf.get(Property.CRYPTO_SECRET_KEY_ENCRYPTION_STRATEGY_CLASS.getKey()));
+              }
+            }
+            
+            cryptoParams.setAllOptions(cryptoConfFromAccumuloConf);
+          }
+          
+          
+          ByteArrayOutputStream baos = new ByteArrayOutputStream();
+          DataOutputStream dos = new DataOutputStream(baos);
+          cryptoParams.write(dos);
+          dos.close();
+          cache.cacheMetaBlock(CRYPTO_BLOCK_NAME, baos.toByteArray());
+          
+          this.cryptoModule = CryptoModuleFactory.getCryptoModule(cryptoParams.getAllOptions().get(Property.CRYPTO_MODULE_CLASS.getKey()));
+          this.secretKeyEncryptionStrategy = CryptoModuleFactory.getSecretKeyEncryptionStrategy(cryptoParams.getKeyEncryptionStrategyClass());
+    
+          // This call should put the decrypted session key within the cryptoParameters object
+          // secretKeyEncryptionStrategy.decryptSecretKey(cryptoParameters);
+          
+          cryptoParams = (BCFileCryptoModuleParameters) secretKeyEncryptionStrategy.decryptSecretKey(cryptoParams);
+          
+        } else if (cachedCryptoParams != null) {
+          cryptoParams = new BCFileCryptoModuleParameters();
+          cryptoParams.read(cachedCryptoParams);
+          
+          this.cryptoModule = CryptoModuleFactory.getCryptoModule(cryptoParams.getAllOptions().get(Property.CRYPTO_MODULE_CLASS.getKey()));
+          this.secretKeyEncryptionStrategy = CryptoModuleFactory.getSecretKeyEncryptionStrategy(cryptoParams.getKeyEncryptionStrategyClass());
+    
+          // This call should put the decrypted session key within the cryptoParameters object
+          // secretKeyEncryptionStrategy.decryptSecretKey(cryptoParameters);
+          
+          cryptoParams = (BCFileCryptoModuleParameters) secretKeyEncryptionStrategy.decryptSecretKey(cryptoParams);
+            
+        }
+        
         if (cachedMetaIndex == null) {
           ByteArrayOutputStream baos = new ByteArrayOutputStream();
           DataOutputStream dos = new DataOutputStream(baos);
@@ -630,14 +937,32 @@ public final class BCFile {
           cachedDataIndex = cache.cacheMetaBlock(DataIndex.BLOCK_NAME, blockR);
         }
         
-        dataIndex = new DataIndex(cachedDataIndex);
+        
+        try {
+          dataIndex = new DataIndex(cachedDataIndex);
+        } catch (IOException e) {
+          LOG.error("Got IOException when trying to create DataIndex block");
+          throw e;
+        }
         cachedDataIndex.close();
         
       } else {
-        // Logger.getLogger(Reader.class).debug("Read bcfile !METADATA from cache");
+        // We have cached versions of the metaIndex, dataIndex and cryptoParams objects.
+        // Use them to fill out this reader's members.
         version = null;
+        
         metaIndex = new MetaIndex(cachedMetaIndex);
         dataIndex = new DataIndex(cachedDataIndex);
+        cryptoParams = new BCFileCryptoModuleParameters();
+        cryptoParams.read(cachedCryptoParams);
+        
+        this.cryptoModule = CryptoModuleFactory.getCryptoModule(cryptoParams.getAllOptions().get(Property.CRYPTO_MODULE_CLASS.getKey()));
+        this.secretKeyEncryptionStrategy = CryptoModuleFactory.getSecretKeyEncryptionStrategy(cryptoParams.getKeyEncryptionStrategyClass());
+  
+        // This call should put the decrypted session key within the cryptoParameters object
+        cryptoParams = (BCFileCryptoModuleParameters) secretKeyEncryptionStrategy.decryptSecretKey(cryptoParams);
+
+        
       }
     }
     
@@ -727,7 +1052,7 @@ public final class BCFile {
     }
     
     private BlockReader createReader(Algorithm compressAlgo, BlockRegion region) throws IOException {
-      RBlockState rbs = new RBlockState(compressAlgo, in, region, conf);
+      RBlockState rbs = new RBlockState(compressAlgo, in, region, conf, cryptoModule, version, cryptoParams);
       return new BlockReader(rbs);
     }
     

http://git-wip-us.apache.org/repos/asf/accumulo/blob/65b5a3a3/core/src/main/java/org/apache/accumulo/core/file/rfile/bcfile/Compression.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/accumulo/core/file/rfile/bcfile/Compression.java b/core/src/main/java/org/apache/accumulo/core/file/rfile/bcfile/Compression.java
index 912824c..e89bb40 100644
--- a/core/src/main/java/org/apache/accumulo/core/file/rfile/bcfile/Compression.java
+++ b/core/src/main/java/org/apache/accumulo/core/file/rfile/bcfile/Compression.java
@@ -39,7 +39,7 @@ import org.apache.hadoop.util.ReflectionUtils;
 /**
  * Compression related stuff.
  */
-final class Compression {
+public final class Compression {
   static final Log LOG = LogFactory.getLog(Compression.class);
   
   /**
@@ -71,7 +71,7 @@ final class Compression {
   /**
    * Compression algorithms.
    */
-  static enum Algorithm {
+  public static enum Algorithm {
     LZO(TFile.COMPRESSION_LZO) {
       private transient boolean checked = false;
       private static final String defaultClazz = "org.apache.hadoop.io.compress.LzoCodec";

http://git-wip-us.apache.org/repos/asf/accumulo/blob/65b5a3a3/core/src/main/java/org/apache/accumulo/core/security/crypto/CryptoModule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/accumulo/core/security/crypto/CryptoModule.java b/core/src/main/java/org/apache/accumulo/core/security/crypto/CryptoModule.java
index fca7d22..01f7888 100644
--- a/core/src/main/java/org/apache/accumulo/core/security/crypto/CryptoModule.java
+++ b/core/src/main/java/org/apache/accumulo/core/security/crypto/CryptoModule.java
@@ -19,92 +19,80 @@ package org.apache.accumulo.core.security.crypto;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
-import java.util.Map;
+
+import javax.crypto.Cipher;
+import javax.crypto.CipherInputStream;
+import javax.crypto.CipherOutputStream;
 
 /**
  * Classes that obey this interface may be used to provide encrypting and decrypting streams to the rest of Accumulo. Classes that obey this interface may be
  * configured as the crypto module by setting the property crypto.module.class in the accumulo-site.xml file.
  * 
- * Note that this first iteration of this API is considered deprecated because we anticipate it changing in non-backwards compatible ways as we explore the
- * requirements for encryption in Accumulo. So, your mileage is gonna vary a lot as we go forward.
  * 
  */
-@Deprecated
 public interface CryptoModule {
   
-  public enum CryptoInitProperty {
-    ALGORITHM_NAME("algorithm.name"), CIPHER_SUITE("cipher.suite"), INITIALIZATION_VECTOR("initialization.vector"), PLAINTEXT_SESSION_KEY(
-        "plaintext.session.key");
-    
-    private CryptoInitProperty(String name) {
-      key = name;
-    }
-    
-    private String key;
-    
-    public String getKey() {
-      return key;
-    }
-  }
-  
   /**
-   * Wraps an OutputStream in an encrypting OutputStream. The given map contains the settings for the cryptographic algorithm to use. <b>Callers of this method
-   * should expect that the given OutputStream will be written to before cryptographic writes occur.</b> These writes contain the cryptographic information used
-   * to encrypt the following bytes (these data include the initialization vector, encrypted session key, and so on). If writing arbitrarily to the underlying
-   * stream is not desirable, users should call the other flavor of getEncryptingOutputStream which accepts these data as parameters.
+   * Takes a {@link CryptoModuleParameters} object containing an {@link OutputStream} to wrap within a {@link CipherOutputStream}. The various other parts of the
+   * {@link CryptoModuleParameters} object specify the details about the type of encryption to use. Callers should pay special attention to the
+   * {@link CryptoModuleParameters#getRecordParametersToStream()} and {@link CryptoModuleParameters#getCloseUnderylingStreamAfterCryptoStreamClose()} flags
+   * within the {@link CryptoModuleParameters} object, as they control whether or not this method will write to the given {@link OutputStream} in
+   * {@link CryptoModuleParameters#getPlaintextOutputStream()}.
+   * 
+   * <p>
+   * 
+   * This method returns a {@link CryptoModuleParameters} object. Implementers of this interface maintain a contract that the returned object is <i>the same</i>
+   * as the one passed in, always. Return values are enclosed within that object, as some other calls will typically return more than one value.
    * 
-   * @param out
-   *          the OutputStream to wrap
-   * @param cryptoOpts
-   *          the cryptographic parameters to use; specific string names to look for will depend on the various implementations
-   * @return an OutputStream that wraps the given parameter
+   * @param params
+   *          the {@link CryptoModuleParameters} object that specifies how to set up the encrypted stream.
+   * @return the same {@link CryptoModuleParameters} object with the {@link CryptoModuleParameters#getEncryptedOutputStream()} set to a stream that is not null.
+   *         That stream may be exactly the same stream as {@link CryptoModuleParameters#getPlaintextInputStream()} if the params object specifies no cryptography.
    * @throws IOException
    */
-  public OutputStream getEncryptingOutputStream(OutputStream out, Map<String,String> cryptoOpts) throws IOException;
+  public CryptoModuleParameters getEncryptingOutputStream(CryptoModuleParameters params) throws IOException;
+  
+  
   
   /**
-   * Wraps an InputStream and returns a decrypting input stream. The given map contains the settings for the intended cryptographic operations, but implementors
-   * should take care to ensure that the crypto from the given input stream matches their expectations about what they will use to decrypt it, as the parameters
-   * may have changed. Also, care should be taken around transitioning between non-encrypting and encrypting streams; implementors should handle the case where
-   * the given input stream is <b>not</b> encrypted at all.
+   * Takes a {@link CryptoModuleParameters} object containing an {@link InputStream} to wrap within a {@link CipherInputStream}. The various other parts of the
+   * {@link CryptoModuleParameters} object specify the details about the type of encryption to use. Callers should pay special attention to the
+   * {@link CryptoModuleParameters#getRecordParametersToStream()} and {@link CryptoModuleParameters#getCloseUnderylingStreamAfterCryptoStreamClose()} flags
+   * within the {@link CryptoModuleParameters} object, as they control whether or not this method will read from the given {@link InputStream} in
+   * {@link CryptoModuleParameters#getEncryptedInputStream()}.
    * 
-   * It is expected that this version of getDecryptingInputStream is called in conjunction with the getEncryptingOutputStream from above. It should expect its
-   * input streams to contain the data written by getEncryptingOutputStream.
+   * <p>
    * 
-   * @param in
-   *          the InputStream to wrap
-   * @param cryptoOpts
-   *          the cryptographic parameters to use; specific string names to look for will depend on the various implementations
-   * @return an InputStream that wraps the given parameter
+   * This method returns a {@link CryptoModuleParameters} object. Implementers of this interface maintain a contract that the returned object is <i>the same</i>
+   * as the one passed in, always. Return values are enclosed within that object, as some other calls will typically return more than one value.
+   * 
+   * @param params
+   *          the {@link CryptoModuleParameters} object that specifies how to set up the encrypted stream.
+   * @return the same {@link CryptoModuleParameters} object with the {@link CryptoModuleParameters#getPlaintextInputStream()} set to a stream that is not null.
+   *         That stream may be exactly the same stream as {@link CryptoModuleParameters#getEncryptedInputStream()} if the params object specifies no cryptography.
    * @throws IOException
    */
-  public InputStream getDecryptingInputStream(InputStream in, Map<String,String> cryptoOpts) throws IOException;
+  public CryptoModuleParameters getDecryptingInputStream(CryptoModuleParameters params) throws IOException;
+
   
   /**
-   * Wraps an OutputStream in an encrypting OutputStream. The given map contains the settings for the cryptographic algorithm to use. The cryptoInitParams map
-   * contains all the cryptographic details to construct a key (or keys), initialization vectors, etc. and use them to properly initialize the stream for
-   * writing. These initialization parameters must be persisted elsewhere, along with the cryptographic configuration (algorithm, mode, etc.), so that they may
-   * be read in at the time of reading the encrypted content.
+   * Generates a random session key and sets it into the {@link CryptoModuleParameters#getPlaintextKey()} property.  Saves callers from 
+   * having to set up their own secure random provider.  Also will set the {@link CryptoModuleParameters#getSecureRandom()} property if it
+   * has not already been set by some other function.
    * 
-   * @param out
-   *          the OutputStream to wrap
-   * @param conf
-   *          the cryptographic algorithm configuration
-   * @param cryptoInitParams
-   *          the initialization parameters for the algorithm, usually including initialization vector and session key
-   * @return a wrapped output stream
+   * @param params a {@link CryptoModuleParameters} object contained a correctly instantiated set of properties.
+   * @return the same {@link CryptoModuleParameters} object with the plaintext key set
    */
-  public OutputStream getEncryptingOutputStream(OutputStream out, Map<String,String> conf, Map<CryptoModule.CryptoInitProperty,Object> cryptoInitParams);
+  public CryptoModuleParameters generateNewRandomSessionKey(CryptoModuleParameters params);
   
   /**
-   * Wraps an InputStream and returns a decrypting input stream. The given map contains the settings for the intended cryptographic operations, but implementors
-   * should take care to ensure that the crypto from the given input stream matches their expectations about what they will use to decrypt it, as the parameters
-   * may have changed. Also, care should be taken around transitioning between non-encrypting and encrypting streams; implementors should handle the case where
-   * the given input stream is <b>not</b> encrypted at all.
+   * Generates a {@link Cipher} object based on the parameters in the given {@link CryptoModuleParameters} object and places it into the
+   * {@link CryptoModuleParameters#getCipher()} property. Callers may choose to use this method if they want to get the initialization
+   * vector from the cipher before proceeding to create wrapped streams.  
    * 
-   * The cryptoInitParams contains all necessary information to properly initialize the given cipher, usually including things like initialization vector and
-   * secret key.
+   * @param params a {@link CryptoModuleParameters} object contained a correctly instantiated set of properties.
+   * @return the same {@link CryptoModuleParameters} object with the cipher set.
    */
-  public InputStream getDecryptingInputStream(InputStream in, Map<String,String> cryptoOpts, Map<CryptoModule.CryptoInitProperty,Object> cryptoInitParams)
-      throws IOException;
+  public CryptoModuleParameters initializeCipher(CryptoModuleParameters params);
+ 
 }

http://git-wip-us.apache.org/repos/asf/accumulo/blob/65b5a3a3/core/src/main/java/org/apache/accumulo/core/security/crypto/CryptoModuleFactory.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/accumulo/core/security/crypto/CryptoModuleFactory.java b/core/src/main/java/org/apache/accumulo/core/security/crypto/CryptoModuleFactory.java
index 2f03e02..40f2c1e 100644
--- a/core/src/main/java/org/apache/accumulo/core/security/crypto/CryptoModuleFactory.java
+++ b/core/src/main/java/org/apache/accumulo/core/security/crypto/CryptoModuleFactory.java
@@ -17,8 +17,6 @@
 package org.apache.accumulo.core.security.crypto;
 
 import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
 import java.util.Map;
 
 import org.apache.accumulo.core.conf.AccumuloConfiguration;
@@ -29,9 +27,8 @@ import org.apache.log4j.Logger;
 /**
  * This factory module exists to assist other classes in loading crypto modules.
  * 
- * @deprecated This feature is experimental and may go away in future versions.
+ * 
  */
-@Deprecated
 public class CryptoModuleFactory {
   
   private static Logger log = Logger.getLogger(CryptoModuleFactory.class);
@@ -50,9 +47,14 @@ public class CryptoModuleFactory {
   
   @SuppressWarnings({"rawtypes"})
   public static CryptoModule getCryptoModule(String cryptoModuleClassname) {
-    log.debug(String.format("About to instantiate crypto module %s", cryptoModuleClassname));
     
-    if (cryptoModuleClassname.equals("NullCryptoModule")) {
+    if (cryptoModuleClassname != null) {
+      cryptoModuleClassname = cryptoModuleClassname.trim();
+    }
+    
+    log.trace(String.format("About to instantiate crypto module %s", cryptoModuleClassname));
+    
+    if (cryptoModuleClassname == null || cryptoModuleClassname.equals("NullCryptoModule")) {
       return new NullCryptoModule();
     }
     
@@ -61,7 +63,7 @@ public class CryptoModuleFactory {
     try {
       cryptoModuleClazz = AccumuloVFSClassLoader.loadClass(cryptoModuleClassname);
     } catch (ClassNotFoundException e1) {
-      log.warn(String.format("Could not find configured crypto module \"%s\".  NO ENCRYPTION WILL BE USED.", cryptoModuleClassname));
+      log.warn(String.format("Could not find configured crypto module \"%s\".  No encryption will be used.", cryptoModuleClassname));
       return new NullCryptoModule();
     }
     
@@ -77,21 +79,21 @@ public class CryptoModuleFactory {
     }
     
     if (!implementsCryptoModule) {
-      log.warn("Configured Accumulo crypto module \"%s\" does not implement the CryptoModule interface. NO ENCRYPTION WILL BE USED.");
+      log.warn("Configured Accumulo crypto module \"%s\" does not implement the CryptoModule interface. No encryption will be used.");
       return new NullCryptoModule();
     } else {
       try {
         cryptoModule = (CryptoModule) cryptoModuleClazz.newInstance();
         
-        log.debug("Successfully instantiated crypto module");
+        log.trace("Successfully instantiated crypto module");
         
       } catch (InstantiationException e) {
-        log.warn(String.format("Got instantiation exception %s when instantiating crypto module \"%s\".  NO ENCRYPTION WILL BE USED.", e.getCause().getClass()
+        log.warn(String.format("Got instantiation exception %s when instantiating crypto module \"%s\".  No encryption will be used.", e.getCause().getClass()
             .getCanonicalName(), cryptoModuleClassname));
         log.warn(e.getCause());
         return new NullCryptoModule();
       } catch (IllegalAccessException e) {
-        log.warn(String.format("Got illegal access exception when trying to instantiate crypto module \"%s\".  NO ENCRYPTION WILL BE USED.",
+        log.warn(String.format("Got illegal access exception when trying to instantiate crypto module \"%s\".  No encryption will be used.",
             cryptoModuleClassname));
         log.warn(e);
         return new NullCryptoModule();
@@ -107,6 +109,11 @@ public class CryptoModuleFactory {
   
   @SuppressWarnings("rawtypes")
   public static SecretKeyEncryptionStrategy getSecretKeyEncryptionStrategy(String className) {
+    
+    if (className != null) {
+      className = className.trim();
+    }
+    
     if (className == null || className.equals("NullSecretKeyEncryptionStrategy")) {
       return new NullSecretKeyEncryptionStrategy();
     }
@@ -116,7 +123,7 @@ public class CryptoModuleFactory {
     try {
       keyEncryptionStrategyClazz = AccumuloVFSClassLoader.loadClass(className);
     } catch (ClassNotFoundException e1) {
-      log.warn(String.format("Could not find configured secret key encryption strategy \"%s\".  NO ENCRYPTION WILL BE USED.", className));
+      log.warn(String.format("Could not find configured secret key encryption strategy \"%s\".  No encryption will be used.", className));
       return new NullSecretKeyEncryptionStrategy();
     }
     
@@ -132,21 +139,21 @@ public class CryptoModuleFactory {
     }
     
     if (!implementsSecretKeyStrategy) {
-      log.warn("Configured Accumulo secret key encryption strategy \"%s\" does not implement the SecretKeyEncryptionStrategy interface. NO ENCRYPTION WILL BE USED.");
+      log.warn("Configured Accumulo secret key encryption strategy \"%s\" does not implement the SecretKeyEncryptionStrategy interface. No encryption will be used.");
       return new NullSecretKeyEncryptionStrategy();
     } else {
       try {
         strategy = (SecretKeyEncryptionStrategy) keyEncryptionStrategyClazz.newInstance();
         
-        log.debug("Successfully instantiated secret key encryption strategy");
+        log.trace("Successfully instantiated secret key encryption strategy");
         
       } catch (InstantiationException e) {
-        log.warn(String.format("Got instantiation exception %s when instantiating secret key encryption strategy \"%s\".  NO ENCRYPTION WILL BE USED.", e
+        log.warn(String.format("Got instantiation exception %s when instantiating secret key encryption strategy \"%s\".  No encryption will be used.", e
             .getCause().getClass().getCanonicalName(), className));
         log.warn(e.getCause());
         return new NullSecretKeyEncryptionStrategy();
       } catch (IllegalAccessException e) {
-        log.warn(String.format("Got illegal access exception when trying to instantiate secret key encryption strategy \"%s\".  NO ENCRYPTION WILL BE USED.",
+        log.warn(String.format("Got illegal access exception when trying to instantiate secret key encryption strategy \"%s\".  No encryption will be used.",
             className));
         log.warn(e);
         return new NullSecretKeyEncryptionStrategy();
@@ -156,99 +163,96 @@ public class CryptoModuleFactory {
     return strategy;
   }
   
-  private static class NullSecretKeyEncryptionStrategy implements SecretKeyEncryptionStrategy {
-    
-    @Override
-    public SecretKeyEncryptionStrategyContext encryptSecretKey(SecretKeyEncryptionStrategyContext context) {
-      context.setEncryptedSecretKey(context.getPlaintextSecretKey());
-      context.setOpaqueKeyEncryptionKeyID("");
-      
-      return context;
-    }
+  static class NullSecretKeyEncryptionStrategy implements SecretKeyEncryptionStrategy {
     
     @Override
-    public SecretKeyEncryptionStrategyContext decryptSecretKey(SecretKeyEncryptionStrategyContext context) {
-      context.setPlaintextSecretKey(context.getEncryptedSecretKey());
+    public CryptoModuleParameters encryptSecretKey(CryptoModuleParameters params) {
+      params.setEncryptedKey(params.getPlaintextKey());
+      params.setOpaqueKeyEncryptionKeyID("");
       
-      return context;
+      return params;
     }
-    
+
     @Override
-    public SecretKeyEncryptionStrategyContext getNewContext() {
-      return new SecretKeyEncryptionStrategyContext() {
-        
-        @Override
-        public byte[] getPlaintextSecretKey() {
-          return plaintextSecretKey;
-        }
-        
-        @Override
-        public void setPlaintextSecretKey(byte[] plaintextSecretKey) {
-          this.plaintextSecretKey = plaintextSecretKey;
-        }
-        
-        @Override
-        public byte[] getEncryptedSecretKey() {
-          return encryptedSecretKey;
-        }
-        
-        @Override
-        public void setEncryptedSecretKey(byte[] encryptedSecretKey) {
-          this.encryptedSecretKey = encryptedSecretKey;
-        }
-        
-        @Override
-        public String getOpaqueKeyEncryptionKeyID() {
-          return opaqueKeyEncryptionKeyID;
-        }
-        
-        @Override
-        public void setOpaqueKeyEncryptionKeyID(String opaqueKeyEncryptionKeyID) {
-          this.opaqueKeyEncryptionKeyID = opaqueKeyEncryptionKeyID;
-        }
-        
-        @Override
-        public Map<String,String> getContext() {
-          return context;
-        }
-        
-        @Override
-        public void setContext(Map<String,String> context) {
-          this.context = context;
-        }
-        
-        private byte[] plaintextSecretKey;
-        private byte[] encryptedSecretKey;
-        private String opaqueKeyEncryptionKeyID;
-        private Map<String,String> context;
-      };
+    public CryptoModuleParameters decryptSecretKey(CryptoModuleParameters params) {
+      params.setPlaintextKey(params.getEncryptedKey());
+      return params;
     }
     
   }
   
-  private static class NullCryptoModule implements CryptoModule {
+  static class NullCryptoModule implements CryptoModule {
     
     @Override
-    public OutputStream getEncryptingOutputStream(OutputStream out, Map<String,String> cryptoOpts) throws IOException {
-      return out;
+    public CryptoModuleParameters getEncryptingOutputStream(CryptoModuleParameters params) throws IOException {
+      params.setEncryptedOutputStream(params.getPlaintextOutputStream());
+      return params;
     }
-    
+
     @Override
-    public InputStream getDecryptingInputStream(InputStream in, Map<String,String> cryptoOpts) throws IOException {
-      return in;
+    public CryptoModuleParameters getDecryptingInputStream(CryptoModuleParameters params) throws IOException {
+      params.setPlaintextInputStream(params.getEncryptedInputStream());
+      return params;
     }
-    
+
     @Override
-    public OutputStream getEncryptingOutputStream(OutputStream out, Map<String,String> conf, Map<CryptoInitProperty,Object> cryptoInitParams) {
-      return out;
+    public CryptoModuleParameters generateNewRandomSessionKey(CryptoModuleParameters params) {
+      params.setPlaintextKey(new byte[0]);
+      return params;
     }
-    
+
     @Override
-    public InputStream getDecryptingInputStream(InputStream in, Map<String,String> cryptoOpts, Map<CryptoInitProperty,Object> cryptoInitParams)
-        throws IOException {
-      return in;
+    public CryptoModuleParameters initializeCipher(CryptoModuleParameters params) {
+      return params;
+    }
+
+  }
+  
+  public static String[] parseCipherTransform(String cipherTransform) {
+    if (cipherTransform == null) {
+      return new String[3];
     }
     
+    return cipherTransform.split("/");
   }
+
+  
+  public static CryptoModuleParameters createParamsObjectFromAccumuloConfiguration(AccumuloConfiguration conf) {
+    
+    // Get all the options from the configuration
+    Map<String,String> cryptoOpts = conf.getAllPropertiesWithPrefix(Property.CRYPTO_PREFIX);
+    cryptoOpts.putAll(conf.getAllPropertiesWithPrefix(Property.INSTANCE_PREFIX));
+    CryptoModuleParameters params = new CryptoModuleParameters();
+
+    return fillParamsObjectFromStringMap(params, cryptoOpts);
+  }
+
+  public static CryptoModuleParameters fillParamsObjectFromStringMap(CryptoModuleParameters params, Map<String,String> cryptoOpts) {
+
+    // Parse the cipher suite for the mode and padding options
+    String[] cipherTransformParts = parseCipherTransform(cryptoOpts.get(Property.CRYPTO_CIPHER_SUITE.getKey()));
+    
+    // If no encryption has been specified, then we abort here.
+    if (cipherTransformParts[0] == null || cipherTransformParts[0].equals("NullCipher")) {
+      params.setAllOptions(cryptoOpts);
+      params.setAlgorithmName("NullCipher");
+      return params;
+    }
+    
+    params.setAllOptions(cryptoOpts);
+    
+    // 
+    params.setAlgorithmName(cryptoOpts.get(Property.CRYPTO_CIPHER_ALGORITHM_NAME.getKey()));
+    params.setEncryptionMode(cipherTransformParts[1]);
+    params.setKeyEncryptionStrategyClass(cryptoOpts.get(Property.CRYPTO_SECRET_KEY_ENCRYPTION_STRATEGY_CLASS.getKey()));
+    params.setKeyLength(Integer.parseInt(cryptoOpts.get(Property.CRYPTO_CIPHER_KEY_LENGTH.getKey())));
+    params.setOverrideStreamsSecretKeyEncryptionStrategy(Boolean.parseBoolean(cryptoOpts.get(Property.CRYPTO_OVERRIDE_KEY_STRATEGY_WITH_CONFIGURED_STRATEGY.getKey())));
+    params.setPadding(cipherTransformParts[2]);
+    params.setRandomNumberGenerator(cryptoOpts.get(Property.CRYPTO_SECURE_RNG.getKey()));
+    params.setRandomNumberGeneratorProvider(cryptoOpts.get(Property.CRYPTO_SECURE_RNG_PROVIDER.getKey()));
+
+    return params;
+  }
+
   
 }