Return-Path: X-Original-To: apmail-hadoop-common-commits-archive@www.apache.org Delivered-To: apmail-hadoop-common-commits-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 835D5CC0A for ; Sat, 6 Dec 2014 02:21:16 +0000 (UTC) Received: (qmail 29735 invoked by uid 500); 6 Dec 2014 02:21:16 -0000 Delivered-To: apmail-hadoop-common-commits-archive@hadoop.apache.org Received: (qmail 29670 invoked by uid 500); 6 Dec 2014 02:21:16 -0000 Mailing-List: contact common-commits-help@hadoop.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: common-dev@hadoop.apache.org Delivered-To: mailing list common-commits@hadoop.apache.org Received: (qmail 29661 invoked by uid 99); 6 Dec 2014 02:21:16 -0000 Received: from tyr.zones.apache.org (HELO tyr.zones.apache.org) (140.211.11.114) by apache.org (qpsmtpd/0.29) with ESMTP; Sat, 06 Dec 2014 02:21:16 +0000 Received: by tyr.zones.apache.org (Postfix, from userid 65534) id 0819D9539FE; Sat, 6 Dec 2014 02:21:16 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: wang@apache.org To: common-commits@hadoop.apache.org Message-Id: X-Mailer: ASF-Git Admin Mailer Subject: hadoop git commit: HADOOP-11343. Overflow is not properly handled in caclulating final iv for AES CTR. Contributed by Jerry Chen. Date: Sat, 6 Dec 2014 02:21:15 +0000 (UTC) Repository: hadoop Updated Branches: refs/heads/branch-2 4cc0abe4f -> dabdd2d74 HADOOP-11343. Overflow is not properly handled in caclulating final iv for AES CTR. Contributed by Jerry Chen. (cherry picked from commit 0707e4eca906552c960e3b8c4e20d9913145eca6) Project: http://git-wip-us.apache.org/repos/asf/hadoop/repo Commit: http://git-wip-us.apache.org/repos/asf/hadoop/commit/dabdd2d7 Tree: http://git-wip-us.apache.org/repos/asf/hadoop/tree/dabdd2d7 Diff: http://git-wip-us.apache.org/repos/asf/hadoop/diff/dabdd2d7 Branch: refs/heads/branch-2 Commit: dabdd2d746d1e1194c124c5c7fe73fcc025e78d2 Parents: 4cc0abe Author: Andrew Wang Authored: Fri Dec 5 18:20:19 2014 -0800 Committer: Andrew Wang Committed: Fri Dec 5 18:20:23 2014 -0800 ---------------------------------------------------------------------- hadoop-common-project/hadoop-common/CHANGES.txt | 3 + .../apache/hadoop/crypto/AesCtrCryptoCodec.java | 27 ++++----- .../apache/hadoop/crypto/TestCryptoCodec.java | 64 ++++++++++++++++++++ 3 files changed, 79 insertions(+), 15 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/hadoop/blob/dabdd2d7/hadoop-common-project/hadoop-common/CHANGES.txt ---------------------------------------------------------------------- diff --git a/hadoop-common-project/hadoop-common/CHANGES.txt b/hadoop-common-project/hadoop-common/CHANGES.txt index e60d02c..8aad8eb 100644 --- a/hadoop-common-project/hadoop-common/CHANGES.txt +++ b/hadoop-common-project/hadoop-common/CHANGES.txt @@ -145,6 +145,9 @@ Release 2.7.0 - UNRELEASED HADOOP-11355. When accessing data in HDFS and the key has been deleted, a Null Pointer Exception is shown. (Arun Suresh via wang) + HADOOP-11343. Overflow is not properly handled in caclulating final iv for + AES CTR. (Jerry Chen via wang) + Release 2.6.0 - 2014-11-18 INCOMPATIBLE CHANGES http://git-wip-us.apache.org/repos/asf/hadoop/blob/dabdd2d7/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/crypto/AesCtrCryptoCodec.java ---------------------------------------------------------------------- diff --git a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/crypto/AesCtrCryptoCodec.java b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/crypto/AesCtrCryptoCodec.java index 8f8bc66..5e286b9 100644 --- a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/crypto/AesCtrCryptoCodec.java +++ b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/crypto/AesCtrCryptoCodec.java @@ -33,7 +33,6 @@ public abstract class AesCtrCryptoCodec extends CryptoCodec { * @see http://en.wikipedia.org/wiki/Advanced_Encryption_Standard */ private static final int AES_BLOCK_SIZE = SUITE.getAlgorithmBlockSize(); - private static final int CTR_OFFSET = 8; @Override public CipherSuite getCipherSuite() { @@ -48,20 +47,18 @@ public abstract class AesCtrCryptoCodec extends CryptoCodec { public void calculateIV(byte[] initIV, long counter, byte[] IV) { Preconditions.checkArgument(initIV.length == AES_BLOCK_SIZE); Preconditions.checkArgument(IV.length == AES_BLOCK_SIZE); - - System.arraycopy(initIV, 0, IV, 0, CTR_OFFSET); - long l = 0; - for (int i = 0; i < 8; i++) { - l = ((l << 8) | (initIV[CTR_OFFSET + i] & 0xff)); + + int i = IV.length; // IV length + int j = 0; // counter bytes index + int sum = 0; + while (i-- > 0) { + // (sum >>> Byte.SIZE) is the carry for addition + sum = (initIV[i] & 0xff) + (sum >>> Byte.SIZE); + if (j++ < 8) { // Big-endian, and long is 8 bytes length + sum += (byte) counter & 0xff; + counter >>>= 8; + } + IV[i] = (byte) sum; } - l += counter; - IV[CTR_OFFSET + 0] = (byte) (l >>> 56); - IV[CTR_OFFSET + 1] = (byte) (l >>> 48); - IV[CTR_OFFSET + 2] = (byte) (l >>> 40); - IV[CTR_OFFSET + 3] = (byte) (l >>> 32); - IV[CTR_OFFSET + 4] = (byte) (l >>> 24); - IV[CTR_OFFSET + 5] = (byte) (l >>> 16); - IV[CTR_OFFSET + 6] = (byte) (l >>> 8); - IV[CTR_OFFSET + 7] = (byte) (l); } } http://git-wip-us.apache.org/repos/asf/hadoop/blob/dabdd2d7/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/crypto/TestCryptoCodec.java ---------------------------------------------------------------------- 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 79987ce..08231f9 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 @@ -23,7 +23,9 @@ import static org.junit.Assert.assertTrue; import java.io.BufferedInputStream; import java.io.DataInputStream; import java.io.IOException; +import java.math.BigInteger; import java.security.GeneralSecurityException; +import java.security.SecureRandom; import java.util.Arrays; import java.util.HashMap; import java.util.Map; @@ -41,6 +43,8 @@ import org.junit.Assert; import org.junit.Assume; import org.junit.Test; +import com.google.common.primitives.Longs; + public class TestCryptoCodec { private static final Log LOG= LogFactory.getLog(TestCryptoCodec.class); private static final byte[] key = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, @@ -230,4 +234,64 @@ public class TestCryptoCodec { Assert.assertEquals(len, rand1.length); Assert.assertFalse(Arrays.equals(rand, rand1)); } + + /** + * Regression test for IV calculation, see HADOOP-11343 + */ + @Test(timeout=120000) + public void testCalculateIV() throws Exception { + JceAesCtrCryptoCodec codec = new JceAesCtrCryptoCodec(); + codec.setConf(conf); + + SecureRandom sr = new SecureRandom(); + byte[] initIV = new byte[16]; + byte[] IV = new byte[16]; + + long iterations = 1000; + long counter = 10000; + + // Overflow test, IV: 00 00 00 00 00 00 00 00 ff ff ff ff ff ff ff ff + for(int i = 0; i < 8; i++) { + initIV[8 + i] = (byte)0xff; + } + + for(long j = 0; j < counter; j++) { + assertIVCalculation(codec, initIV, j, IV); + } + + // Random IV and counter sequence test + for(long i = 0; i < iterations; i++) { + sr.nextBytes(initIV); + + for(long j = 0; j < counter; j++) { + assertIVCalculation(codec, initIV, j, IV); + } + } + + // Random IV and random counter test + for(long i = 0; i < iterations; i++) { + sr.nextBytes(initIV); + + for(long j = 0; j < counter; j++) { + long c = sr.nextLong(); + assertIVCalculation(codec, initIV, c, IV); + } + } + } + + private void assertIVCalculation(CryptoCodec codec, byte[] initIV, + long counter, byte[] IV) { + codec.calculateIV(initIV, counter, IV); + + BigInteger iv = new BigInteger(1, IV); + BigInteger ref = calculateRef(initIV, counter); + + assertTrue("Calculated IV don't match with the reference", iv.equals(ref)); + } + + private static BigInteger calculateRef(byte[] initIV, long counter) { + byte[] cb = Longs.toByteArray(counter); + BigInteger bi = new BigInteger(1, initIV); + return bi.add(new BigInteger(1, cb)); + } }