HADOOP-10429. KeyStores should have methods to generate the materials themselves, KeyShell should use them. (tucu)
git-svn-id: https://svn.apache.org/repos/asf/hadoop/common/trunk@1586105 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
98a98ea0c5
commit
9a1f15532f
|
@ -132,6 +132,9 @@ Trunk (Unreleased)
|
|||
|
||||
HADOOP-10427. KeyProvider implementations should be thread safe. (tucu)
|
||||
|
||||
HADOOP-10429. KeyStores should have methods to generate the materials
|
||||
themselves, KeyShell should use them. (tucu)
|
||||
|
||||
BUG FIXES
|
||||
|
||||
HADOOP-9451. Fault single-layer config if node group topology is enabled.
|
||||
|
|
|
@ -24,6 +24,7 @@ import java.io.IOException;
|
|||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.net.URI;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
|
@ -34,6 +35,8 @@ import org.apache.hadoop.classification.InterfaceStability;
|
|||
import org.apache.hadoop.conf.Configuration;
|
||||
import org.apache.hadoop.fs.Path;
|
||||
|
||||
import javax.crypto.KeyGenerator;
|
||||
|
||||
/**
|
||||
* A provider of secret key material for Hadoop applications. Provides an
|
||||
* abstraction to separate key storage from users of encryption. It
|
||||
|
@ -316,6 +319,56 @@ public abstract class KeyProvider {
|
|||
public abstract KeyVersion createKey(String name, byte[] material,
|
||||
Options options) throws IOException;
|
||||
|
||||
/**
|
||||
* Get the algorithm from the cipher.
|
||||
*
|
||||
* @return the algorithm name
|
||||
*/
|
||||
private String getAlgorithm(String cipher) {
|
||||
int slash = cipher.indexOf('/');
|
||||
if (slash == -1) {
|
||||
return cipher;
|
||||
} else {
|
||||
return cipher.substring(0, slash);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a key material.
|
||||
*
|
||||
* @param size length of the key.
|
||||
* @param algorithm algorithm to use for generating the key.
|
||||
* @return the generated key.
|
||||
* @throws NoSuchAlgorithmException
|
||||
*/
|
||||
protected byte[] generateKey(int size, String algorithm)
|
||||
throws NoSuchAlgorithmException {
|
||||
algorithm = getAlgorithm(algorithm);
|
||||
KeyGenerator keyGenerator = KeyGenerator.getInstance(algorithm);
|
||||
keyGenerator.init(size);
|
||||
byte[] key = keyGenerator.generateKey().getEncoded();
|
||||
return key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new key generating the material for it.
|
||||
* The given key must not already exist.
|
||||
* <p/>
|
||||
* This implementation generates the key material and calls the
|
||||
* {@link #createKey(String, byte[], Options)} method.
|
||||
*
|
||||
* @param name the base name of the key
|
||||
* @param options the options for the new key.
|
||||
* @return the version name of the first version of the key.
|
||||
* @throws IOException
|
||||
* @throws NoSuchAlgorithmException
|
||||
*/
|
||||
public KeyVersion createKey(String name, Options options)
|
||||
throws NoSuchAlgorithmException, IOException {
|
||||
byte[] material = generateKey(options.getBitLength(), options.getCipher());
|
||||
return createKey(name, material, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the given key.
|
||||
* @param name the name of the key to delete
|
||||
|
@ -334,6 +387,23 @@ public abstract class KeyProvider {
|
|||
byte[] material
|
||||
) throws IOException;
|
||||
|
||||
/**
|
||||
* Roll a new version of the given key generating the material for it.
|
||||
* <p/>
|
||||
* This implementation generates the key material and calls the
|
||||
* {@link #rollNewVersion(String, byte[])} method.
|
||||
*
|
||||
* @param name the basename of the key
|
||||
* @return the name of the new version of the key
|
||||
* @throws IOException
|
||||
*/
|
||||
public KeyVersion rollNewVersion(String name) throws NoSuchAlgorithmException,
|
||||
IOException {
|
||||
Metadata meta = getMetadata(name);
|
||||
byte[] material = generateKey(meta.getBitLength(), meta.getCipher());
|
||||
return rollNewVersion(name, material);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that any changes to the keys are written to persistent store.
|
||||
* @throws IOException
|
||||
|
|
|
@ -185,16 +185,6 @@ public class KeyShell extends Configured implements Tool {
|
|||
return provider;
|
||||
}
|
||||
|
||||
protected byte[] generateKey(int size, String algorithm)
|
||||
throws NoSuchAlgorithmException {
|
||||
out.println("Generating key using size: " + size + " and algorithm: "
|
||||
+ algorithm);
|
||||
KeyGenerator keyGenerator = KeyGenerator.getInstance(algorithm);
|
||||
keyGenerator.init(size);
|
||||
byte[] key = keyGenerator.generateKey().getEncoded();
|
||||
return key;
|
||||
}
|
||||
|
||||
protected void printProviderWritten() {
|
||||
out.println(provider.getClass().getName() + " has been updated.");
|
||||
}
|
||||
|
@ -289,9 +279,7 @@ public class KeyShell extends Configured implements Tool {
|
|||
out.println("Rolling key version from KeyProvider: "
|
||||
+ provider.toString() + " for key name: " + keyName);
|
||||
try {
|
||||
byte[] material = null;
|
||||
material = generateKey(md.getBitLength(), md.getAlgorithm());
|
||||
provider.rollNewVersion(keyName, material);
|
||||
provider.rollNewVersion(keyName);
|
||||
out.println(keyName + " has been successfully rolled.");
|
||||
provider.flush();
|
||||
printProviderWritten();
|
||||
|
@ -423,9 +411,7 @@ public class KeyShell extends Configured implements Tool {
|
|||
warnIfTransientProvider();
|
||||
try {
|
||||
Options options = KeyProvider.options(getConf());
|
||||
String alg = getAlgorithm(options.getCipher());
|
||||
byte[] material = generateKey(options.getBitLength(), alg);
|
||||
provider.createKey(keyName, material, options);
|
||||
provider.createKey(keyName, options);
|
||||
out.println(keyName + " has been successfully created.");
|
||||
provider.flush();
|
||||
printProviderWritten();
|
||||
|
@ -441,19 +427,6 @@ public class KeyShell extends Configured implements Tool {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the algorithm from the cipher.
|
||||
* @return the algorithm name
|
||||
*/
|
||||
public String getAlgorithm(String cipher) {
|
||||
int slash = cipher.indexOf('/');
|
||||
if (slash == - 1) {
|
||||
return cipher;
|
||||
} else {
|
||||
return cipher.substring(0, slash);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUsage() {
|
||||
return USAGE + ":\n\n" + DESC;
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
*/
|
||||
package org.apache.hadoop.crypto.key;
|
||||
|
||||
import junit.framework.Assert;
|
||||
import org.apache.hadoop.conf.Configuration;
|
||||
|
||||
import org.apache.hadoop.fs.Path;
|
||||
|
@ -24,9 +25,11 @@ import org.junit.Test;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
@ -34,6 +37,8 @@ import static org.junit.Assert.assertArrayEquals;
|
|||
|
||||
public class TestKeyProvider {
|
||||
|
||||
private static final String CIPHER = "AES";
|
||||
|
||||
@Test
|
||||
public void testBuildVersionName() throws Exception {
|
||||
assertEquals("/a/b@3", KeyProvider.buildVersionName("/a/b", 3));
|
||||
|
@ -109,4 +114,82 @@ public class TestKeyProvider {
|
|||
assertEquals(new Path("user:///"),
|
||||
KeyProvider.unnestUri(new URI("outer://user/")));
|
||||
}
|
||||
|
||||
private static class MyKeyProvider extends KeyProvider {
|
||||
private String algorithm;
|
||||
private int size;
|
||||
private byte[] material;
|
||||
|
||||
@Override
|
||||
public KeyVersion getKeyVersion(String versionName)
|
||||
throws IOException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getKeys() throws IOException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<KeyVersion> getKeyVersions(String name)
|
||||
throws IOException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Metadata getMetadata(String name) throws IOException {
|
||||
return new Metadata(CIPHER, 128, new Date(), 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeyVersion createKey(String name, byte[] material,
|
||||
Options options) throws IOException {
|
||||
this.material = material;
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteKey(String name) throws IOException {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeyVersion rollNewVersion(String name, byte[] material)
|
||||
throws IOException {
|
||||
this.material = material;
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flush() throws IOException {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected byte[] generateKey(int size, String algorithm)
|
||||
throws NoSuchAlgorithmException {
|
||||
this.size = size;
|
||||
this.algorithm = algorithm;
|
||||
return super.generateKey(size, algorithm);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMaterialGeneration() throws Exception {
|
||||
MyKeyProvider kp = new MyKeyProvider();
|
||||
KeyProvider.Options options = new KeyProvider.Options(new Configuration());
|
||||
options.setCipher(CIPHER);
|
||||
options.setBitLength(128);
|
||||
kp.createKey("hello", options);
|
||||
Assert.assertEquals(128, kp.size);
|
||||
Assert.assertEquals(CIPHER, kp.algorithm);
|
||||
Assert.assertNotNull(kp.material);
|
||||
|
||||
kp = new MyKeyProvider();
|
||||
kp.rollNewVersion("hello");
|
||||
Assert.assertEquals(128, kp.size);
|
||||
Assert.assertEquals(CIPHER, kp.algorithm);
|
||||
Assert.assertNotNull(kp.material);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue