HADOOP-10735. Fall back AesCtrCryptoCodec implementation from OpenSSL to JCE if non native support. (yliu)

git-svn-id: https://svn.apache.org/repos/asf/hadoop/common/branches/fs-encryption@1610887 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Yi Liu 2014-07-16 00:36:30 +00:00
parent 56c0bd4d37
commit beb0c19cde
7 changed files with 100 additions and 8 deletions

View File

@ -37,6 +37,9 @@ fs-encryption (Unreleased)
HADOOP-10803. Update OpensslCipher#getInstance to accept CipherSuite#name
format. (Yi Liu)
HADOOP-10735. Fall back AesCtrCryptoCodec implementation from OpenSSL to
JCE if non native support. (Yi Liu)
OPTIMIZATIONS
BUG FIXES

View File

@ -72,4 +72,14 @@ public String toString() {
builder.append("}");
return builder.toString();
}
public static void checkName(String name) {
CipherSuite[] suites = CipherSuite.values();
for (CipherSuite suite : suites) {
if (suite.getName().equals(name)) {
return;
}
}
throw new IllegalArgumentException("Invalid cipher suite name: " + name);
}
}

View File

@ -18,13 +18,23 @@
package org.apache.hadoop.crypto;
import java.security.GeneralSecurityException;
import java.util.List;
import org.apache.hadoop.classification.InterfaceAudience;
import org.apache.hadoop.classification.InterfaceStability;
import org.apache.hadoop.conf.Configurable;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.util.ReflectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.base.Splitter;
import com.google.common.collect.Lists;
import static org.apache.hadoop.fs.CommonConfigurationKeysPublic.HADOOP_SECURITY_CRYPTO_CODEC_CLASS_KEY;
import static org.apache.hadoop.fs.CommonConfigurationKeysPublic.HADOOP_SECURITY_CRYPTO_CODEC_CLASS_DEFAULT;
import static org.apache.hadoop.fs.CommonConfigurationKeysPublic.HADOOP_SECURITY_CRYPTO_CIPHER_SUITE_KEY;
import static org.apache.hadoop.fs.CommonConfigurationKeysPublic.HADOOP_SECURITY_CRYPTO_CIPHER_SUITE_DEFAULT;
/**
* Crypto codec class, encapsulates encryptor/decryptor pair.
@ -32,12 +42,57 @@
@InterfaceAudience.Private
@InterfaceStability.Evolving
public abstract class CryptoCodec implements Configurable {
public static Logger LOG = LoggerFactory.getLogger(CryptoCodec.class);
public static CryptoCodec getInstance(Configuration conf) {
final Class<? extends CryptoCodec> klass = conf.getClass(
HADOOP_SECURITY_CRYPTO_CODEC_CLASS_KEY, JceAesCtrCryptoCodec.class,
CryptoCodec.class);
return ReflectionUtils.newInstance(klass, conf);
List<Class<? extends CryptoCodec>> klasses = getCodecClasses(conf);
String name = conf.get(HADOOP_SECURITY_CRYPTO_CIPHER_SUITE_KEY,
HADOOP_SECURITY_CRYPTO_CIPHER_SUITE_DEFAULT);
CipherSuite.checkName(name);
CryptoCodec codec = null;
for (Class<? extends CryptoCodec> klass : klasses) {
try {
CryptoCodec c = ReflectionUtils.newInstance(klass, conf);
if (c.getCipherSuite().getName().equalsIgnoreCase(name)) {
if (codec == null) {
LOG.debug("Using crypto codec {}.", klass.getName());
codec = c;
}
} else {
LOG.warn("Crypto codec {} doesn't meet the cipher suite {}.",
klass.getName(), name);
}
} catch (Exception e) {
LOG.warn("Crypto codec {} is not available.", klass.getName());
}
}
if (codec != null) {
return codec;
}
throw new RuntimeException("No available crypto codec which meets " +
"the cipher suite " + name + ".");
}
private static List<Class<? extends CryptoCodec>> getCodecClasses(
Configuration conf) {
List<Class<? extends CryptoCodec>> result = Lists.newArrayList();
String codecString = conf.get(HADOOP_SECURITY_CRYPTO_CODEC_CLASS_KEY,
HADOOP_SECURITY_CRYPTO_CODEC_CLASS_DEFAULT);
for (String c : Splitter.on(',').trimResults().omitEmptyStrings().
split(codecString)) {
try {
Class<?> cls = conf.getClassByName(c);
result.add(cls.asSubclass(CryptoCodec.class));
} catch (ClassCastException e) {
LOG.warn("Class " + c + " is not a CryptoCodec.");
} catch (ClassNotFoundException e) {
LOG.warn("Crypto codec " + c + " not found.");
}
}
return result;
}
/**

View File

@ -47,6 +47,9 @@ public class OpensslAesCtrCryptoCodec extends AesCtrCryptoCodec {
private Random random;
public OpensslAesCtrCryptoCodec() {
if (!OpensslCipher.isNativeCodeLoaded()) {
throw new RuntimeException("Failed to load OpenSSL Cipher.");
}
}
@Override

View File

@ -285,6 +285,14 @@ public class CommonConfigurationKeysPublic {
/** See <a href="{@docRoot}/../core-default.html">core-default.xml</a> */
public static final String HADOOP_SECURITY_CRYPTO_CODEC_CLASS_KEY =
"hadoop.security.crypto.codec.class";
public static final String HADOOP_SECURITY_CRYPTO_CODEC_CLASS_DEFAULT =
"org.apache.hadoop.crypto.OpensslAesCtrCryptoCodec," +
"org.apache.hadoop.crypto.JceAesCtrCryptoCodec";
/** See <a href="{@docRoot}/../core-default.html">core-default.xml</a> */
public static final String HADOOP_SECURITY_CRYPTO_CIPHER_SUITE_KEY =
"hadoop.security.crypto.cipher.suite";
public static final String HADOOP_SECURITY_CRYPTO_CIPHER_SUITE_DEFAULT =
"AES/CTR/NoPadding";
/** See <a href="{@docRoot}/../core-default.html">core-default.xml</a> */
public static final String HADOOP_SECURITY_CRYPTO_JCE_PROVIDER_KEY =
"hadoop.security.crypto.jce.provider";
@ -302,8 +310,10 @@ public class CommonConfigurationKeysPublic {
/** Defalt value for HADOOP_SECURITY_JAVA_SECURE_RANDOM_ALGORITHM_KEY */
public static final String HADOOP_SECURITY_JAVA_SECURE_RANDOM_ALGORITHM_DEFAULT =
"SHA1PRNG";
/** See <a href="{@docRoot}/../core-default.html">core-default.xml</a> */
public static final String HADOOP_SECURITY_SECURE_RANDOM_IMPL_KEY =
"hadoop.security.secure.random.impl";
/** See <a href="{@docRoot}/../core-default.html">core-default.xml</a> */
public static final String HADOOP_SECURITY_SECURE_RANDOM_DEVICE_FILE_PATH_KEY =
"hadoop.security.random.device.file.path";
public static final String HADOOP_SECURITY_SECURE_RANDOM_DEVICE_FILE_PATH_DEFAULT =

View File

@ -1453,10 +1453,20 @@ for ldap providers in the same way as above does.
<property>
<name>hadoop.security.crypto.codec.class</name>
<value></value>
<value>org.apache.hadoop.crypto.OpensslAesCtrCryptoCodec,
org.apache.hadoop.crypto.JceAesCtrCryptoCodec</value>
<description>
The default implementation of CryptoCodec which is used for encryption
and decryption.
Comma list of CryptoCodec implementations which are used for encryption
and decryption. The first implementation will be used if avaiable, others
are fallbacks.
</description>
</property>
<property>
<name>hadoop.security.crypto.cipher.suite</name>
<value>AES/CTR/NoPadding</value>
<description>
Cipher suite for crypto codec.
</description>
</property>

View File

@ -29,7 +29,8 @@ public class TestCryptoStreamsWithOpensslAesCtrCryptoCodec
public static void init() throws Exception {
Configuration conf = new Configuration();
conf.set(HADOOP_SECURITY_CRYPTO_CODEC_CLASS_KEY,
OpensslAesCtrCryptoCodec.class.getName());
OpensslAesCtrCryptoCodec.class.getName() + "," +
JceAesCtrCryptoCodec.class.getName());
codec = CryptoCodec.getInstance(conf);
}
}