From b69a48c988c147abf192e36c99e2d4aecc116339 Mon Sep 17 00:00:00 2001 From: Alejandro Abdelnur Date: Thu, 4 Sep 2014 09:22:00 -0700 Subject: [PATCH] HADOOP-11060. Create a CryptoCodec test that verifies interoperability between the JCE and OpenSSL implementations. (hitliuyi via tucu) --- .../hadoop-common/CHANGES.txt | 3 + .../apache/hadoop/crypto/TestCryptoCodec.java | 69 ++++++++++++++----- .../hadoop/crypto/TestCryptoStreams.java | 2 +- 3 files changed, 55 insertions(+), 19 deletions(-) diff --git a/hadoop-common-project/hadoop-common/CHANGES.txt b/hadoop-common-project/hadoop-common/CHANGES.txt index 9645cbad7f..f610c5dbe5 100644 --- a/hadoop-common-project/hadoop-common/CHANGES.txt +++ b/hadoop-common-project/hadoop-common/CHANGES.txt @@ -501,6 +501,9 @@ Release 2.6.0 - UNRELEASED HADOOP-11015. Http server/client utils to propagate and recreate Exceptions from server to client. (tucu) + HADOOP-11060. Create a CryptoCodec test that verifies interoperability + between the JCE and OpenSSL implementations. (hitliuyi via tucu) + OPTIMIZATIONS HADOOP-10838. Byte array native checksumming. (James Thomas via todd) diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/crypto/TestCryptoCodec.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/crypto/TestCryptoCodec.java index 49b5056a86..298f4ef8b0 100644 --- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/crypto/TestCryptoCodec.java +++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/crypto/TestCryptoCodec.java @@ -52,35 +52,40 @@ public class TestCryptoCodec { private Configuration conf = new Configuration(); private int count = 10000; private int seed = new Random().nextInt(); + private final String jceCodecClass = + "org.apache.hadoop.crypto.JceAesCtrCryptoCodec"; + private final String opensslCodecClass = + "org.apache.hadoop.crypto.OpensslAesCtrCryptoCodec"; @Test(timeout=120000) public void testJceAesCtrCryptoCodec() throws Exception { - cryptoCodecTest(conf, seed, 0, - "org.apache.hadoop.crypto.JceAesCtrCryptoCodec"); - cryptoCodecTest(conf, seed, count, - "org.apache.hadoop.crypto.JceAesCtrCryptoCodec"); + Assume.assumeTrue(NativeCodeLoader.buildSupportsOpenssl()); + Assert.assertEquals(null, OpensslCipher.getLoadingFailureReason()); + cryptoCodecTest(conf, seed, 0, jceCodecClass, jceCodecClass); + cryptoCodecTest(conf, seed, count, jceCodecClass, jceCodecClass); + cryptoCodecTest(conf, seed, count, jceCodecClass, opensslCodecClass); } - @Test(timeout=1200000) + @Test(timeout=120000) public void testOpensslAesCtrCryptoCodec() throws Exception { Assume.assumeTrue(NativeCodeLoader.buildSupportsOpenssl()); Assert.assertEquals(null, OpensslCipher.getLoadingFailureReason()); - cryptoCodecTest(conf, seed, 0, - "org.apache.hadoop.crypto.OpensslAesCtrCryptoCodec"); - cryptoCodecTest(conf, seed, count, - "org.apache.hadoop.crypto.OpensslAesCtrCryptoCodec"); + cryptoCodecTest(conf, seed, 0, opensslCodecClass, opensslCodecClass); + cryptoCodecTest(conf, seed, count, opensslCodecClass, opensslCodecClass); + cryptoCodecTest(conf, seed, count, opensslCodecClass, jceCodecClass); } private void cryptoCodecTest(Configuration conf, int seed, int count, - String codecClass) throws IOException, GeneralSecurityException { - CryptoCodec codec = null; + String encCodecClass, String decCodecClass) throws IOException, + GeneralSecurityException { + CryptoCodec encCodec = null; try { - codec = (CryptoCodec)ReflectionUtils.newInstance( - conf.getClassByName(codecClass), conf); + encCodec = (CryptoCodec)ReflectionUtils.newInstance( + conf.getClassByName(encCodecClass), conf); } catch (ClassNotFoundException cnfe) { throw new IOException("Illegal crypto codec!"); } - LOG.info("Created a Codec object of type: " + codecClass); + LOG.info("Created a Codec object of type: " + encCodecClass); // Generate data DataOutputBuffer data = new DataOutputBuffer(); @@ -98,18 +103,27 @@ private void cryptoCodecTest(Configuration conf, int seed, int count, // Encrypt data DataOutputBuffer encryptedDataBuffer = new DataOutputBuffer(); CryptoOutputStream out = new CryptoOutputStream(encryptedDataBuffer, - codec, bufferSize, key, iv); + encCodec, bufferSize, key, iv); out.write(data.getData(), 0, data.getLength()); out.flush(); out.close(); LOG.info("Finished encrypting data"); + CryptoCodec decCodec = null; + try { + decCodec = (CryptoCodec)ReflectionUtils.newInstance( + conf.getClassByName(decCodecClass), conf); + } catch (ClassNotFoundException cnfe) { + throw new IOException("Illegal crypto codec!"); + } + LOG.info("Created a Codec object of type: " + decCodecClass); + // Decrypt data DataInputBuffer decryptedDataBuffer = new DataInputBuffer(); decryptedDataBuffer.reset(encryptedDataBuffer.getData(), 0, encryptedDataBuffer.getLength()); CryptoInputStream in = new CryptoInputStream(decryptedDataBuffer, - codec, bufferSize, key, iv); + decCodec, bufferSize, key, iv); DataInputStream dataIn = new DataInputStream(new BufferedInputStream(in)); // Check @@ -146,7 +160,7 @@ private void cryptoCodecTest(Configuration conf, int seed, int count, decryptedDataBuffer.reset(encryptedDataBuffer.getData(), 0, encryptedDataBuffer.getLength()); in = new CryptoInputStream(decryptedDataBuffer, - codec, bufferSize, key, iv); + decCodec, bufferSize, key, iv); // Check originalIn = new DataInputStream(new BufferedInputStream(originalData)); @@ -156,11 +170,30 @@ private void cryptoCodecTest(Configuration conf, int seed, int count, assertEquals("Decrypted stream read by byte does not match", expected, in.read()); } while (expected != -1); + + // Seek to a certain position and decrypt + originalData.reset(data.getData(), 0, data.getLength()); + decryptedDataBuffer.reset(encryptedDataBuffer.getData(), 0, + encryptedDataBuffer.getLength()); + in = new CryptoInputStream(new TestCryptoStreams.FakeInputStream( + decryptedDataBuffer), decCodec, bufferSize, key, iv); + int seekPos = data.getLength() / 3; + in.seek(seekPos); + + // Check + TestCryptoStreams.FakeInputStream originalInput = + new TestCryptoStreams.FakeInputStream(originalData); + originalInput.seek(seekPos); + do { + expected = originalInput.read(); + assertEquals("Decrypted stream read by byte does not match", + expected, in.read()); + } while (expected != -1); LOG.info("SUCCESS! Completed checking " + count + " records"); // Check secure random generator - testSecureRandom(codec); + testSecureRandom(encCodec); } /** Test secure random generator */ diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/crypto/TestCryptoStreams.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/crypto/TestCryptoStreams.java index ebe025b0ea..a14f9a38d0 100644 --- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/crypto/TestCryptoStreams.java +++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/crypto/TestCryptoStreams.java @@ -159,7 +159,7 @@ private void checkStream() throws IOException { } } - private class FakeInputStream extends InputStream implements + public static class FakeInputStream extends InputStream implements Seekable, PositionedReadable, ByteBufferReadable, HasFileDescriptor, CanSetDropBehind, CanSetReadahead, HasEnhancedByteBufferAccess { private final byte[] oneByteBuf = new byte[1];