You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@knox.apache.org by lm...@apache.org on 2017/05/20 16:36:12 UTC
knox git commit: KNOX-944 - Make PBE Hashing,
Iteration Count and Salt Configurable and Manageable
Repository: knox
Updated Branches:
refs/heads/master 551505640 -> d0726a227
KNOX-944 - Make PBE Hashing, Iteration Count and Salt Configurable and Manageable
Project: http://git-wip-us.apache.org/repos/asf/knox/repo
Commit: http://git-wip-us.apache.org/repos/asf/knox/commit/d0726a22
Tree: http://git-wip-us.apache.org/repos/asf/knox/tree/d0726a22
Diff: http://git-wip-us.apache.org/repos/asf/knox/diff/d0726a22
Branch: refs/heads/master
Commit: d0726a227d4f10e57489554b8adf8406e6d96920
Parents: 5515056
Author: Larry McCay <lm...@hortonworks.com>
Authored: Sat May 20 12:26:32 2017 -0400
Committer: Larry McCay <lm...@hortonworks.com>
Committed: Sat May 20 12:35:45 2017 -0400
----------------------------------------------------------------------
.../gateway/config/impl/GatewayConfigImpl.java | 35 ++++
.../security/impl/DefaultCryptoService.java | 14 +-
.../security/impl/DefaultMasterService.java | 2 +-
.../services/security/CryptoServiceTest.java | 75 ++++++--
.../hadoop/gateway/config/GatewayConfig.java | 42 +++++
.../services/security/MasterService.java | 2 -
.../services/security/impl/AESEncryptor.java | 152 ---------------
.../security/impl/CMFMasterService.java | 15 +-
.../security/impl/ConfigurableEncryptor.java | 188 +++++++++++++++++++
.../hadoop/gateway/GatewayTestConfig.java | 29 +++
.../hadoop/gateway/GatewayTestConfig.java | 30 +++
11 files changed, 408 insertions(+), 176 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/knox/blob/d0726a22/gateway-server/src/main/java/org/apache/hadoop/gateway/config/impl/GatewayConfigImpl.java
----------------------------------------------------------------------
diff --git a/gateway-server/src/main/java/org/apache/hadoop/gateway/config/impl/GatewayConfigImpl.java b/gateway-server/src/main/java/org/apache/hadoop/gateway/config/impl/GatewayConfigImpl.java
index 3952d7b..368787a 100644
--- a/gateway-server/src/main/java/org/apache/hadoop/gateway/config/impl/GatewayConfigImpl.java
+++ b/gateway-server/src/main/java/org/apache/hadoop/gateway/config/impl/GatewayConfigImpl.java
@@ -192,6 +192,12 @@ public class GatewayConfigImpl extends Configuration implements GatewayConfig {
public static final String COOKIE_SCOPING_ENABLED = GATEWAY_CONFIG_FILE_PREFIX + ".scope.cookies.feature.enabled";
public static final boolean DEFAULT_COOKIE_SCOPING_FEATURE_ENABLED = false;
+ private static final String CRYPTO_ALGORITHM = GATEWAY_CONFIG_FILE_PREFIX + ".crypto.algorithm";
+ private static final String CRYPTO_PBE_ALGORITHM = GATEWAY_CONFIG_FILE_PREFIX + ".crypto.pbe.algorithm";
+ private static final String CRYPTO_TRANSFORMATION = GATEWAY_CONFIG_FILE_PREFIX + ".crypto.transformation";
+ private static final String CRYPTO_SALTSIZE = GATEWAY_CONFIG_FILE_PREFIX + ".crypto.salt.size";
+ private static final String CRYPTO_ITERATION_COUNT = GATEWAY_CONFIG_FILE_PREFIX + ".crypto.iteration.count";
+ private static final String CRYPTO_KEY_LENGTH = GATEWAY_CONFIG_FILE_PREFIX + ".crypto.key.length";
private static List<String> DEFAULT_GLOBAL_RULES_SERVICES;
@@ -824,4 +830,33 @@ public class GatewayConfigImpl extends Configuration implements GatewayConfig {
return value;
}
+ @Override
+ public String getAlgorithm() {
+ return getVar(CRYPTO_ALGORITHM, null);
+ }
+
+ @Override
+ public String getPBEAlgorithm() {
+ return getVar(CRYPTO_PBE_ALGORITHM, null);
+ }
+
+ @Override
+ public String getTransformation() {
+ return getVar(CRYPTO_TRANSFORMATION, null);
+ }
+
+ @Override
+ public String getSaltSize() {
+ return getVar(CRYPTO_SALTSIZE, null);
+ }
+
+ @Override
+ public String getIterationCount() {
+ return getVar(CRYPTO_ITERATION_COUNT, null);
+ }
+
+ @Override
+ public String getKeyLength() {
+ return getVar(CRYPTO_KEY_LENGTH, null);
+ }
}
http://git-wip-us.apache.org/repos/asf/knox/blob/d0726a22/gateway-server/src/main/java/org/apache/hadoop/gateway/services/security/impl/DefaultCryptoService.java
----------------------------------------------------------------------
diff --git a/gateway-server/src/main/java/org/apache/hadoop/gateway/services/security/impl/DefaultCryptoService.java b/gateway-server/src/main/java/org/apache/hadoop/gateway/services/security/impl/DefaultCryptoService.java
index b8348dc..b6ef5a3 100644
--- a/gateway-server/src/main/java/org/apache/hadoop/gateway/services/security/impl/DefaultCryptoService.java
+++ b/gateway-server/src/main/java/org/apache/hadoop/gateway/services/security/impl/DefaultCryptoService.java
@@ -43,7 +43,9 @@ public class DefaultCryptoService implements CryptoService {
private AliasService as = null;
private KeystoreService ks = null;
- private HashMap<String,AESEncryptor> encryptorCache = new HashMap<>();
+ private HashMap<String,ConfigurableEncryptor> encryptorCache =
+ new HashMap<String,ConfigurableEncryptor>();
+ private GatewayConfig config = null;
public void setKeystoreService(KeystoreService ks) {
this.ks = ks;
@@ -56,7 +58,8 @@ public class DefaultCryptoService implements CryptoService {
@Override
public void init(GatewayConfig config, Map<String, String> options)
throws ServiceLifecycleException {
- if (as == null) {
+ this.config = config;
+ if (as == null) {
throw new ServiceLifecycleException("Alias service is not set");
}
}
@@ -188,11 +191,12 @@ public class DefaultCryptoService implements CryptoService {
// The assumption here is that lock contention will be less of a performance issue than the cost of object creation.
// We have seen via profiling that AESEncryptor instantiation is very expensive.
- private final AESEncryptor getEncryptor( final String clusterName, final char[] password ) {
+ private final ConfigurableEncryptor getEncryptor( final String clusterName, final char[] password ) {
synchronized( encryptorCache ) {
- AESEncryptor encryptor = encryptorCache.get( clusterName );
+ ConfigurableEncryptor encryptor = encryptorCache.get( clusterName );
if( encryptor == null ) {
- encryptor = new AESEncryptor( String.valueOf( password ) );
+ encryptor = new ConfigurableEncryptor( String.valueOf( password ) );
+ encryptor.init(config);
encryptorCache.put( clusterName, encryptor );
}
return encryptor;
http://git-wip-us.apache.org/repos/asf/knox/blob/d0726a22/gateway-server/src/main/java/org/apache/hadoop/gateway/services/security/impl/DefaultMasterService.java
----------------------------------------------------------------------
diff --git a/gateway-server/src/main/java/org/apache/hadoop/gateway/services/security/impl/DefaultMasterService.java b/gateway-server/src/main/java/org/apache/hadoop/gateway/services/security/impl/DefaultMasterService.java
index 47368d0..ece8445 100644
--- a/gateway-server/src/main/java/org/apache/hadoop/gateway/services/security/impl/DefaultMasterService.java
+++ b/gateway-server/src/main/java/org/apache/hadoop/gateway/services/security/impl/DefaultMasterService.java
@@ -43,7 +43,7 @@ public class DefaultMasterService extends CMFMasterService implements MasterServ
boolean persisting = options.get( "persist-master").equals("true");
String securityDir = config.getGatewaySecurityDir();
String filename = "master";
- setupMasterSecret(securityDir, filename, persisting);
+ setupMasterSecret(securityDir, filename, persisting, config);
}
}
http://git-wip-us.apache.org/repos/asf/knox/blob/d0726a22/gateway-server/src/test/java/org/apache/hadoop/gateway/services/security/CryptoServiceTest.java
----------------------------------------------------------------------
diff --git a/gateway-server/src/test/java/org/apache/hadoop/gateway/services/security/CryptoServiceTest.java b/gateway-server/src/test/java/org/apache/hadoop/gateway/services/security/CryptoServiceTest.java
index bcd5ec2..57e2abc 100644
--- a/gateway-server/src/test/java/org/apache/hadoop/gateway/services/security/CryptoServiceTest.java
+++ b/gateway-server/src/test/java/org/apache/hadoop/gateway/services/security/CryptoServiceTest.java
@@ -19,15 +19,17 @@ package org.apache.hadoop.gateway.services.security;
import org.apache.hadoop.gateway.config.GatewayConfig;
import org.apache.hadoop.gateway.services.ServiceLifecycleException;
-import org.apache.hadoop.gateway.services.security.impl.AESEncryptor;
+import org.apache.hadoop.gateway.services.security.impl.ConfigurableEncryptor;
import org.apache.hadoop.gateway.services.security.impl.DefaultCryptoService;
import org.apache.hadoop.test.category.ManualTests;
import org.apache.hadoop.test.category.MediumTests;
+import org.easymock.EasyMock;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import java.security.cert.Certificate;
+import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -113,42 +115,91 @@ public class CryptoServiceTest {
cs = new DefaultCryptoService();
((DefaultCryptoService)cs).setAliasService(as);
}
-
+
@Test
- public void testAESEncryptor() throws Exception {
+ public void testCryptoServiceAES() throws Exception {
+ GatewayConfig config = EasyMock.createNiceMock( GatewayConfig.class );
+ EasyMock.expect(config.getAlgorithm()).andReturn("AES");
+ EasyMock.expect(config.getPBEAlgorithm()).andReturn("PBKDF2WithHmacSHA1");
+ EasyMock.expect(config.getSaltSize()).andReturn("16");
+ EasyMock.expect(config.getIterationCount()).andReturn("65536");
+ EasyMock.expect(config.getKeyLength()).andReturn("128");
+ EasyMock.expect(config.getTransformation()).andReturn("AES/CBC/PKCS5Padding");
+ EasyMock.replay(config);
+
// password to create key - same Encryptor
String queryString = "url=http://localhost:50070/api/v1/blahblah";
- AESEncryptor aes0 = new AESEncryptor("password");
+ ConfigurableEncryptor aes0 = new ConfigurableEncryptor("password");
+ aes0.init(config);
+ cs.init(config, new HashMap<String,String>());
EncryptionResult result0 = cs.encryptForCluster("Test", "encrypt_url", queryString.getBytes("UTF8"));
- byte[] decrypted0 = aes0.decrypt(result0.salt, result0.iv, result0.cipher);
+ byte[] decrypted0 = cs.decryptForCluster("Test", "encrypt_url", result0.cipher, result0.iv, result0.salt);
assertEquals(queryString, new String(decrypted0, "UTF8"));
assertEquals(queryString.getBytes("UTF8").length, decrypted0.length);
assertEquals(queryString.getBytes("UTF8").length, new String(decrypted0, "UTF8").toCharArray().length);
-
+ }
+
+ @Test
+ public void testCryptoServiceDES() throws Exception {
+ GatewayConfig config = EasyMock.createNiceMock( GatewayConfig.class );
+ EasyMock.expect(config.getAlgorithm()).andReturn("DES");
+ EasyMock.expect(config.getPBEAlgorithm()).andReturn("PBKDF2WithHmacSHA1");
+ EasyMock.expect(config.getSaltSize()).andReturn("16");
+ EasyMock.expect(config.getIterationCount()).andReturn("65536");
+ EasyMock.expect(config.getKeyLength()).andReturn("128");
+ EasyMock.expect(config.getTransformation()).andReturn("DES");
+ EasyMock.replay(config);
+
// password to create key - same Encryptor
- AESEncryptor aes = new AESEncryptor("Test");
+ String queryString = "url=http://localhost:50070/api/v1/blahblah";
+ ConfigurableEncryptor aes0 = new ConfigurableEncryptor("password");
+ aes0.init(config);
+ cs.init(config, new HashMap<String,String>());
+ EncryptionResult result0 = cs.encryptForCluster("Test", "encrypt_url", queryString.getBytes("UTF8"));
+ byte[] decrypted0 = cs.decryptForCluster("Test", "encrypt_url", result0.cipher, result0.iv, result0.salt);
+ assertEquals(queryString, new String(decrypted0, "UTF8"));
+ assertEquals(queryString.getBytes("UTF8").length, decrypted0.length);
+ assertEquals(queryString.getBytes("UTF8").length, new String(decrypted0, "UTF8").toCharArray().length);
+ }
+
+ @Test
+ public void testConfigurableEncryptor() throws Exception {
+ GatewayConfig config = EasyMock.createNiceMock( GatewayConfig.class );
+ EasyMock.expect(config.getAlgorithm()).andReturn("AES");
+ EasyMock.expect(config.getPBEAlgorithm()).andReturn("PBKDF2WithHmacSHA1");
+ EasyMock.expect(config.getSaltSize()).andReturn("16");
+ EasyMock.expect(config.getIterationCount()).andReturn("65536");
+ EasyMock.expect(config.getKeyLength()).andReturn("128");
+ EasyMock.expect(config.getTransformation()).andReturn("AES/CBC/PKCS5Padding");
+ EasyMock.replay(config);
+
+ // password to create key - same Encryptor
+ ConfigurableEncryptor aes = new ConfigurableEncryptor("Test");
+ aes.init(config);
EncryptionResult result = aes.encrypt("larry".getBytes("UTF8"));
byte[] decrypted = aes.decrypt(result.salt, result.iv, result.cipher);
assertEquals(new String(decrypted, "UTF8"), "larry");
// password to create key - different Encryptor
- AESEncryptor aes2 = new AESEncryptor("Test");
+ ConfigurableEncryptor aes2 = new ConfigurableEncryptor("Test");
+ aes2.init(config);
decrypted = aes2.decrypt(result.salt, result.iv, result.cipher);
assertEquals(new String(decrypted, "UTF8"), "larry");
-
// password to create key resolved from alias - same Encryptor
- AESEncryptor aes3 = new AESEncryptor(new String(as.getPasswordFromAliasForCluster("test", "encrypt_url")));
+ ConfigurableEncryptor aes3 = new ConfigurableEncryptor(new String(as.getPasswordFromAliasForCluster("test", "encrypt_url")));
+ aes3.init(config);
result = aes3.encrypt("larry".getBytes("UTF8"));
decrypted = aes3.decrypt(result.salt, result.iv, result.cipher);
assertEquals(new String(decrypted, "UTF8"), "larry");
// password to create key resolved from alias - different Encryptor
- AESEncryptor aes4 = new AESEncryptor(new String(as.getPasswordFromAliasForCluster("test", "encrypt_url")));
+ ConfigurableEncryptor aes4 = new ConfigurableEncryptor(new String(as.getPasswordFromAliasForCluster("test", "encrypt_url")));
+ aes4.init(config);
decrypted = aes4.decrypt(result.salt, result.iv, result.cipher);
assertEquals(new String(decrypted, "UTF8"), "larry");
}
-
+
@Test
//@Ignore
public void testEncryptionOfQueryStrings() throws Exception {
http://git-wip-us.apache.org/repos/asf/knox/blob/d0726a22/gateway-spi/src/main/java/org/apache/hadoop/gateway/config/GatewayConfig.java
----------------------------------------------------------------------
diff --git a/gateway-spi/src/main/java/org/apache/hadoop/gateway/config/GatewayConfig.java b/gateway-spi/src/main/java/org/apache/hadoop/gateway/config/GatewayConfig.java
index 9d8e044..af03bbd 100644
--- a/gateway-spi/src/main/java/org/apache/hadoop/gateway/config/GatewayConfig.java
+++ b/gateway-spi/src/main/java/org/apache/hadoop/gateway/config/GatewayConfig.java
@@ -236,4 +236,46 @@ public interface GatewayConfig {
*/
String getHeaderNameForRemoteAddress();
+ /**
+ * Configured Algorithm name to be used by the CryptoService
+ * and MasterService implementations
+ * @return
+ */
+ String getAlgorithm();
+
+ /**
+ * Configured Algorithm name to be used by the CryptoService
+ * for password based encryption
+ * @return
+ */
+ String getPBEAlgorithm();
+
+ /**
+ * Configured Transformation name to be used by the CryptoService
+ * and MasterService implementations
+ * @return
+ */
+ String getTransformation();
+
+ /**
+ * Configured SaltSize to be used by the CryptoService
+ * and MasterService implementations
+ * @return
+ */
+ String getSaltSize();
+
+ /**
+ * Configured IterationCount to be used by the CryptoService
+ * and MasterService implementations
+ * @return
+ */
+ String getIterationCount();
+
+ /**
+ * Configured KeyLength to be used by the CryptoService
+ * and MasterService implementations
+ * @return
+ */
+ String getKeyLength();
+
}
http://git-wip-us.apache.org/repos/asf/knox/blob/d0726a22/gateway-spi/src/main/java/org/apache/hadoop/gateway/services/security/MasterService.java
----------------------------------------------------------------------
diff --git a/gateway-spi/src/main/java/org/apache/hadoop/gateway/services/security/MasterService.java b/gateway-spi/src/main/java/org/apache/hadoop/gateway/services/security/MasterService.java
index 6d42dfe..ff84565 100644
--- a/gateway-spi/src/main/java/org/apache/hadoop/gateway/services/security/MasterService.java
+++ b/gateway-spi/src/main/java/org/apache/hadoop/gateway/services/security/MasterService.java
@@ -18,7 +18,5 @@
package org.apache.hadoop.gateway.services.security;
public interface MasterService {
-
public abstract char[] getMasterSecret();
-
}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/knox/blob/d0726a22/gateway-spi/src/main/java/org/apache/hadoop/gateway/services/security/impl/AESEncryptor.java
----------------------------------------------------------------------
diff --git a/gateway-spi/src/main/java/org/apache/hadoop/gateway/services/security/impl/AESEncryptor.java b/gateway-spi/src/main/java/org/apache/hadoop/gateway/services/security/impl/AESEncryptor.java
deleted file mode 100644
index f6ff910..0000000
--- a/gateway-spi/src/main/java/org/apache/hadoop/gateway/services/security/impl/AESEncryptor.java
+++ /dev/null
@@ -1,152 +0,0 @@
-/**
- * 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.
- */
-package org.apache.hadoop.gateway.services.security.impl;
-
-import java.security.InvalidAlgorithmParameterException;
-import java.security.InvalidKeyException;
-import java.security.NoSuchAlgorithmException;
-import java.security.SecureRandom;
-import java.security.spec.InvalidKeySpecException;
-import java.security.spec.InvalidParameterSpecException;
-import java.security.spec.KeySpec;
-
-import javax.crypto.Cipher;
-import javax.crypto.NoSuchPaddingException;
-import javax.crypto.SecretKey;
-import javax.crypto.SecretKeyFactory;
-import javax.crypto.spec.IvParameterSpec;
-import javax.crypto.spec.PBEKeySpec;
-import javax.crypto.spec.SecretKeySpec;
-
-import org.apache.hadoop.gateway.i18n.GatewaySpiMessages;
-import org.apache.hadoop.gateway.i18n.messages.MessagesFactory;
-import org.apache.hadoop.gateway.services.security.EncryptionResult;
-
-public class AESEncryptor {
- private static final GatewaySpiMessages LOG = MessagesFactory.get( GatewaySpiMessages.class );
-
- private static final int ITERATION_COUNT = 65536;
- private static final int KEY_LENGTH = 128;
-
- private Cipher ecipher;
- private Cipher dcipher;
- private SecretKey secret;
- private byte[] salt = null;
- private char[] passPhrase = null;
-
- public AESEncryptor(String passPhrase) {
- try {
- this.passPhrase = passPhrase.toCharArray();
- salt = new byte[8];
- SecureRandom rnd = new SecureRandom();
- rnd.nextBytes(salt);
-
- SecretKey tmp = getKeyFromPassword(passPhrase);
- secret = new SecretKeySpec (tmp.getEncoded(), "AES");
-
- ecipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
- ecipher.init(Cipher.ENCRYPT_MODE, secret);
-
- dcipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
- byte[] iv = ecipher.getParameters().getParameterSpec(IvParameterSpec.class).getIV();
- dcipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(iv));
- } catch (NoSuchAlgorithmException e) {
- LOG.failedToEncryptPassphrase( e );
- } catch (NoSuchPaddingException e) {
- LOG.failedToEncryptPassphrase( e );
- } catch (InvalidKeyException e) {
- LOG.failedToEncryptPassphrase( e );
- } catch (InvalidParameterSpecException e) {
- LOG.failedToEncryptPassphrase( e );
- } catch (InvalidAlgorithmParameterException e) {
- LOG.failedToEncryptPassphrase( e );
- }
- }
-
- AESEncryptor(SecretKey secret) {
- try {
- this.secret = new SecretKeySpec (secret.getEncoded(), "AES");
-
- ecipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
- ecipher.init(Cipher.ENCRYPT_MODE, secret);
-
- dcipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
- byte[] iv = ecipher.getParameters().getParameterSpec(IvParameterSpec.class).getIV();
- dcipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(iv));
- } catch (NoSuchAlgorithmException e) {
- LOG.failedToEncryptPassphrase( e );
- } catch (NoSuchPaddingException e) {
- LOG.failedToEncryptPassphrase( e );
- } catch (InvalidKeyException e) {
- LOG.failedToEncryptPassphrase( e );
- } catch (InvalidParameterSpecException e) {
- LOG.failedToEncryptPassphrase( e );
- } catch (InvalidAlgorithmParameterException e) {
- LOG.failedToEncryptPassphrase( e );
- }
- }
-
- public SecretKey getKeyFromPassword(String passPhrase) {
- return getKeyFromPassword(passPhrase, salt);
- }
-
- public SecretKey getKeyFromPassword(String passPhrase, byte[] salt) {
- SecretKeyFactory factory;
- SecretKey key = null;
- try {
- factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
- KeySpec spec = new PBEKeySpec(passPhrase.toCharArray(), salt, ITERATION_COUNT, KEY_LENGTH);
- key = factory.generateSecret(spec);
- } catch (NoSuchAlgorithmException e) {
- LOG.failedToGenerateKeyFromPassword( e );
- } catch (InvalidKeySpecException e) {
- LOG.failedToGenerateKeyFromPassword( e );
- }
-
- return key;
- }
-
- public EncryptionResult encrypt(String encrypt) throws Exception {
- byte[] bytes = encrypt.getBytes("UTF8");
- EncryptionResult atom = encrypt(bytes);
- return atom;
- }
-
- public EncryptionResult encrypt(byte[] plain) throws Exception {
- EncryptionResult atom = new EncryptionResult(salt, ecipher.getParameters().getParameterSpec(IvParameterSpec.class).getIV(), ecipher.doFinal(plain));
- return atom;
- }
-
- public String decrypt(String salt, String iv, String cipher) throws Exception {
- byte[] decrypted = decrypt(salt.getBytes("UTF8"), iv.getBytes("UTF8"), cipher.getBytes("UTF8"));
- return new String(decrypted, "UTF8");
- }
-
- public byte[] decrypt(byte[] salt, byte[] iv, byte[] encrypt) throws Exception {
- SecretKey tmp = getKeyFromPassword(new String(passPhrase), salt);
- secret = new SecretKeySpec(tmp.getEncoded(), "AES");
-
- dcipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(iv));
- return dcipher.doFinal(encrypt);
- }
-
- public byte[] decrypt(byte[] encrypt) throws Exception {
- dcipher.init(Cipher.DECRYPT_MODE, secret);
- return dcipher.doFinal(encrypt);
- }
-}
http://git-wip-us.apache.org/repos/asf/knox/blob/d0726a22/gateway-spi/src/main/java/org/apache/hadoop/gateway/services/security/impl/CMFMasterService.java
----------------------------------------------------------------------
diff --git a/gateway-spi/src/main/java/org/apache/hadoop/gateway/services/security/impl/CMFMasterService.java b/gateway-spi/src/main/java/org/apache/hadoop/gateway/services/security/impl/CMFMasterService.java
index 7960787..5a37f9b 100644
--- a/gateway-spi/src/main/java/org/apache/hadoop/gateway/services/security/impl/CMFMasterService.java
+++ b/gateway-spi/src/main/java/org/apache/hadoop/gateway/services/security/impl/CMFMasterService.java
@@ -20,6 +20,7 @@ package org.apache.hadoop.gateway.services.security.impl;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.io.FileUtils;
import org.apache.commons.net.ntp.TimeStamp;
+import org.apache.hadoop.gateway.config.GatewayConfig;
import org.apache.hadoop.gateway.i18n.GatewaySpiMessages;
import org.apache.hadoop.gateway.i18n.messages.MessagesFactory;
import org.apache.hadoop.gateway.services.ServiceLifecycleException;
@@ -39,7 +40,7 @@ public class CMFMasterService {
private static final String MASTER_PERSISTENCE_TAG = "#1.0# " + TimeStamp.getCurrentTime().toDateString();
protected char[] master = null;
protected String serviceName = null;
- private AESEncryptor aes = new AESEncryptor(MASTER_PASSPHRASE);
+ private ConfigurableEncryptor encryptor = new ConfigurableEncryptor(MASTER_PASSPHRASE);
public CMFMasterService(String serviceName) {
super();
@@ -50,6 +51,13 @@ public class CMFMasterService {
return this.master;
}
+ public void setupMasterSecret(String securityDir, String filename,
+ boolean persisting, GatewayConfig config)
+ throws ServiceLifecycleException {
+ encryptor.init(config);
+ setupMasterSecret(securityDir, filename, persisting);
+ }
+
protected void setupMasterSecret(String securityDir, boolean persisting) throws ServiceLifecycleException {
setupMasterSecret(securityDir, serviceName + "-master", persisting);
}
@@ -60,7 +68,6 @@ public class CMFMasterService {
try {
initializeFromMaster(masterFile);
} catch (Exception e) {
- // TODO Auto-generated catch block
throw new ServiceLifecycleException("Unable to load the persisted master secret.", e);
}
}
@@ -146,7 +153,7 @@ public class CMFMasterService {
private EncryptionResult encryptMaster(char[] master) {
// TODO Auto-generated method stub
try {
- return aes.encrypt(new String(master));
+ return encryptor.encrypt(new String(master));
} catch (Exception e) {
LOG.failedToEncryptMasterSecret(e);
}
@@ -160,7 +167,7 @@ public class CMFMasterService {
LOG.loadingFromPersistentMaster( tag );
String line = new String(Base64.decodeBase64(lines.get(1)));
String[] parts = line.split("::");
- this.master = new String(aes.decrypt(Base64.decodeBase64(parts[0]), Base64.decodeBase64(parts[1]), Base64.decodeBase64(parts[2])), "UTF8").toCharArray();
+ this.master = new String(encryptor.decrypt(Base64.decodeBase64(parts[0]), Base64.decodeBase64(parts[1]), Base64.decodeBase64(parts[2])), "UTF8").toCharArray();
} catch (IOException e) {
LOG.failedToInitializeFromPersistentMaster(masterFile.getName(), e);
throw e;
http://git-wip-us.apache.org/repos/asf/knox/blob/d0726a22/gateway-spi/src/main/java/org/apache/hadoop/gateway/services/security/impl/ConfigurableEncryptor.java
----------------------------------------------------------------------
diff --git a/gateway-spi/src/main/java/org/apache/hadoop/gateway/services/security/impl/ConfigurableEncryptor.java b/gateway-spi/src/main/java/org/apache/hadoop/gateway/services/security/impl/ConfigurableEncryptor.java
new file mode 100644
index 0000000..49be71d
--- /dev/null
+++ b/gateway-spi/src/main/java/org/apache/hadoop/gateway/services/security/impl/ConfigurableEncryptor.java
@@ -0,0 +1,188 @@
+/**
+ * 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.
+ */
+package org.apache.hadoop.gateway.services.security.impl;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.InvalidParameterSpecException;
+import java.security.spec.KeySpec;
+
+import javax.crypto.Cipher;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.SecretKey;
+import javax.crypto.SecretKeyFactory;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.PBEKeySpec;
+import javax.crypto.spec.SecretKeySpec;
+
+import org.apache.hadoop.gateway.config.GatewayConfig;
+import org.apache.hadoop.gateway.i18n.GatewaySpiMessages;
+import org.apache.hadoop.gateway.i18n.messages.MessagesFactory;
+import org.apache.hadoop.gateway.services.security.EncryptionResult;
+
+public class ConfigurableEncryptor {
+ private static final GatewaySpiMessages LOG = MessagesFactory.get( GatewaySpiMessages.class );
+
+ private static final int ITERATION_COUNT = 65536;
+ private static final int KEY_LENGTH = 128;
+
+ private Cipher ecipher;
+ private Cipher dcipher;
+ private SecretKey secret;
+ private byte[] salt = null;
+ private char[] passPhrase = null;
+ private String alg = "AES";
+ private String pbeAlg = "PBKDF2WithHmacSHA1";
+ private String transformation = "AES/CBC/PKCS5Padding";
+ private int saltSize = 8;
+ private int iterationCount = ITERATION_COUNT;
+ private int keyLength = KEY_LENGTH;
+
+ public ConfigurableEncryptor(String passPhrase) {
+ try {
+ this.passPhrase = passPhrase.toCharArray();
+ salt = new byte[saltSize];
+ SecureRandom rnd = new SecureRandom();
+ rnd.nextBytes(salt);
+
+ SecretKey tmp = getKeyFromPassword(passPhrase);
+ secret = new SecretKeySpec (tmp.getEncoded(), alg);
+
+ ecipher = Cipher.getInstance(transformation);
+ ecipher.init(Cipher.ENCRYPT_MODE, secret);
+
+ dcipher = Cipher.getInstance(transformation);
+ byte[] iv = ecipher.getParameters().getParameterSpec(IvParameterSpec.class).getIV();
+ dcipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(iv));
+ } catch (NoSuchAlgorithmException e) {
+ LOG.failedToEncryptPassphrase( e );
+ } catch (NoSuchPaddingException e) {
+ LOG.failedToEncryptPassphrase( e );
+ } catch (InvalidKeyException e) {
+ LOG.failedToEncryptPassphrase( e );
+ } catch (InvalidParameterSpecException e) {
+ LOG.failedToEncryptPassphrase( e );
+ } catch (InvalidAlgorithmParameterException e) {
+ LOG.failedToEncryptPassphrase( e );
+ }
+ }
+
+ ConfigurableEncryptor(SecretKey secret) {
+ try {
+ this.secret = new SecretKeySpec (secret.getEncoded(), alg);
+
+ ecipher = Cipher.getInstance(transformation);
+ ecipher.init(Cipher.ENCRYPT_MODE, secret);
+
+ dcipher = Cipher.getInstance(transformation);
+ byte[] iv = ecipher.getParameters().getParameterSpec(IvParameterSpec.class).getIV();
+ dcipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(iv));
+ } catch (NoSuchAlgorithmException e) {
+ LOG.failedToEncryptPassphrase( e );
+ } catch (NoSuchPaddingException e) {
+ LOG.failedToEncryptPassphrase( e );
+ } catch (InvalidKeyException e) {
+ LOG.failedToEncryptPassphrase( e );
+ } catch (InvalidParameterSpecException e) {
+ LOG.failedToEncryptPassphrase( e );
+ } catch (InvalidAlgorithmParameterException e) {
+ LOG.failedToEncryptPassphrase( e );
+ }
+ }
+
+ public void init(GatewayConfig config) {
+ if (config != null) {
+ String alg = config.getAlgorithm();
+ if (alg != null) {
+ this.alg = alg;
+ }
+ String pbeAlg = config.getPBEAlgorithm();
+ if (pbeAlg != null) {
+ this.pbeAlg = pbeAlg;
+ }
+ String transformation = config.getTransformation();
+ if (transformation != null) {
+ this.transformation = transformation;
+ }
+ String saltSize = config.getSaltSize();
+ if (saltSize != null) {
+ this.saltSize = Integer.parseInt(saltSize);
+ }
+ String iterationCount = config.getIterationCount();
+ if (iterationCount != null) {
+ this.iterationCount = Integer.parseInt(iterationCount);
+ }
+ String keyLength = config.getKeyLength();
+ if (keyLength != null) {
+ this.keyLength = Integer.parseInt(keyLength);
+ }
+ }
+ }
+
+ public SecretKey getKeyFromPassword(String passPhrase) {
+ return getKeyFromPassword(passPhrase, salt);
+ }
+
+ public SecretKey getKeyFromPassword(String passPhrase, byte[] salt) {
+ SecretKeyFactory factory;
+ SecretKey key = null;
+ try {
+ factory = SecretKeyFactory.getInstance(pbeAlg);
+ KeySpec spec = new PBEKeySpec(passPhrase.toCharArray(), salt, iterationCount, keyLength);
+ key = factory.generateSecret(spec);
+ } catch (NoSuchAlgorithmException e) {
+ LOG.failedToGenerateKeyFromPassword( e );
+ } catch (InvalidKeySpecException e) {
+ LOG.failedToGenerateKeyFromPassword( e );
+ }
+
+ return key;
+ }
+
+ public EncryptionResult encrypt(String encrypt) throws Exception {
+ byte[] bytes = encrypt.getBytes("UTF8");
+ EncryptionResult atom = encrypt(bytes);
+ return atom;
+ }
+
+ public EncryptionResult encrypt(byte[] plain) throws Exception {
+ EncryptionResult atom = new EncryptionResult(salt, ecipher.getParameters().getParameterSpec(IvParameterSpec.class).getIV(), ecipher.doFinal(plain));
+ return atom;
+ }
+
+ public String decrypt(String salt, String iv, String cipher) throws Exception {
+ byte[] decrypted = decrypt(salt.getBytes("UTF8"), iv.getBytes("UTF8"), cipher.getBytes("UTF8"));
+ return new String(decrypted, "UTF8");
+ }
+
+ public byte[] decrypt(byte[] salt, byte[] iv, byte[] encrypt) throws Exception {
+ SecretKey tmp = getKeyFromPassword(new String(passPhrase), salt);
+ secret = new SecretKeySpec(tmp.getEncoded(), alg);
+
+ dcipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(iv));
+ return dcipher.doFinal(encrypt);
+ }
+
+ public byte[] decrypt(byte[] encrypt) throws Exception {
+ dcipher.init(Cipher.DECRYPT_MODE, secret);
+ return dcipher.doFinal(encrypt);
+ }
+}
http://git-wip-us.apache.org/repos/asf/knox/blob/d0726a22/gateway-test-release-utils/src/main/java/org/apache/hadoop/gateway/GatewayTestConfig.java
----------------------------------------------------------------------
diff --git a/gateway-test-release-utils/src/main/java/org/apache/hadoop/gateway/GatewayTestConfig.java b/gateway-test-release-utils/src/main/java/org/apache/hadoop/gateway/GatewayTestConfig.java
index c079531..f41046b 100644
--- a/gateway-test-release-utils/src/main/java/org/apache/hadoop/gateway/GatewayTestConfig.java
+++ b/gateway-test-release-utils/src/main/java/org/apache/hadoop/gateway/GatewayTestConfig.java
@@ -478,4 +478,33 @@ public class GatewayTestConfig extends Configuration implements GatewayConfig {
return "X-Forwarded-For";
}
+ @Override
+ public String getAlgorithm() {
+ return null;
+ }
+
+ @Override
+ public String getPBEAlgorithm() {
+ return null;
+ }
+
+ @Override
+ public String getTransformation() {
+ return null;
+ }
+
+ @Override
+ public String getSaltSize() {
+ return null;
+ }
+
+ @Override
+ public String getIterationCount() {
+ return null;
+ }
+
+ @Override
+ public String getKeyLength() {
+ return null;
+ }
}
http://git-wip-us.apache.org/repos/asf/knox/blob/d0726a22/gateway-test/src/test/java/org/apache/hadoop/gateway/GatewayTestConfig.java
----------------------------------------------------------------------
diff --git a/gateway-test/src/test/java/org/apache/hadoop/gateway/GatewayTestConfig.java b/gateway-test/src/test/java/org/apache/hadoop/gateway/GatewayTestConfig.java
index e96dde2..580d875 100644
--- a/gateway-test/src/test/java/org/apache/hadoop/gateway/GatewayTestConfig.java
+++ b/gateway-test/src/test/java/org/apache/hadoop/gateway/GatewayTestConfig.java
@@ -535,4 +535,34 @@ public class GatewayTestConfig extends Configuration implements GatewayConfig {
public String getHeaderNameForRemoteAddress() {
return "X-Forwarded-For";
}
+
+ @Override
+ public String getAlgorithm() {
+ return null;
+ }
+
+ @Override
+ public String getPBEAlgorithm() {
+ return null;
+ }
+
+ @Override
+ public String getTransformation() {
+ return null;
+ }
+
+ @Override
+ public String getSaltSize() {
+ return null;
+ }
+
+ @Override
+ public String getIterationCount() {
+ return null;
+ }
+
+ @Override
+ public String getKeyLength() {
+ return null;
+ }
}