View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  package org.apache.hadoop.hbase.io.crypto;
19  
20  import static org.junit.Assert.assertEquals;
21  import static org.junit.Assert.assertTrue;
22  
23  import java.io.ByteArrayInputStream;
24  import java.io.ByteArrayOutputStream;
25  import java.security.Key;
26  
27  import javax.crypto.spec.SecretKeySpec;
28  
29  import org.apache.commons.logging.Log;
30  import org.apache.commons.logging.LogFactory;
31  import org.apache.hadoop.conf.Configuration;
32  import org.apache.hadoop.hbase.HBaseConfiguration;
33  import org.apache.hadoop.hbase.HConstants;
34  import org.apache.hadoop.hbase.testclassification.SmallTests;
35  import org.apache.hadoop.hbase.util.Bytes;
36  import org.junit.Test;
37  import org.junit.experimental.categories.Category;
38  
39  @Category(SmallTests.class)
40  public class TestEncryption {
41    private static final Log LOG = LogFactory.getLog(TestEncryption.class);
42  
43    @Test
44    public void testSmallBlocks() throws Exception {
45      byte[] key = new byte[16];
46      Bytes.random(key);
47      byte[] iv = new byte[16];
48      Bytes.random(iv);
49      for (int size: new int[] { 4, 8, 16, 32, 64, 128, 256, 512 }) {
50        checkTransformSymmetry(key, iv, getRandomBlock(size));
51      }
52    }
53  
54    @Test
55    public void testLargeBlocks() throws Exception {
56      byte[] key = new byte[16];
57      Bytes.random(key);
58      byte[] iv = new byte[16];
59      Bytes.random(iv);
60      for (int size: new int[] { 256 * 1024, 512 * 1024, 1024 * 1024 }) {
61        checkTransformSymmetry(key, iv, getRandomBlock(size));
62      }
63    }
64  
65    @Test
66    public void testOddSizedBlocks() throws Exception {
67      byte[] key = new byte[16];
68      Bytes.random(key);
69      byte[] iv = new byte[16];
70      Bytes.random(iv);
71      for (int size: new int[] { 3, 7, 11, 23, 47, 79, 119, 175 }) {
72        checkTransformSymmetry(key, iv, getRandomBlock(size));
73      }
74    }
75  
76    @Test
77    public void testTypicalHFileBlocks() throws Exception {
78      byte[] key = new byte[16];
79      Bytes.random(key);
80      byte[] iv = new byte[16];
81      Bytes.random(iv);
82      for (int size: new int[] { 4 * 1024, 8 * 1024, 64 * 1024, 128 * 1024 }) {
83        checkTransformSymmetry(key, iv, getRandomBlock(size));
84      }
85    }
86  
87    private void checkTransformSymmetry(byte[] keyBytes, byte[] iv, byte[] plaintext)
88        throws Exception {
89      LOG.info("checkTransformSymmetry: AES, plaintext length = " + plaintext.length);
90  
91      Configuration conf = HBaseConfiguration.create();
92      String algorithm =
93          conf.get(HConstants.CRYPTO_KEY_ALGORITHM_CONF_KEY, HConstants.CIPHER_AES);
94      Cipher aes = Encryption.getCipher(conf, algorithm);
95      Key key = new SecretKeySpec(keyBytes, algorithm);
96  
97      Encryptor e = aes.getEncryptor();
98      e.setKey(key);
99      e.setIv(iv);
100     e.reset();
101     ByteArrayOutputStream encOut = new ByteArrayOutputStream();
102     Encryption.encrypt(encOut, plaintext, 0, plaintext.length, e);
103     byte[] encrypted = encOut.toByteArray();
104 
105     Decryptor d = aes.getDecryptor();
106     d.setKey(key);
107     d.setIv(iv);
108     d.reset();
109     ByteArrayInputStream encIn = new ByteArrayInputStream(encrypted);
110     ByteArrayOutputStream decOut = new ByteArrayOutputStream();
111     Encryption.decrypt(decOut, encIn, plaintext.length, d);
112 
113     byte[] result = decOut.toByteArray();
114     assertEquals("Decrypted result has different length than plaintext",
115       result.length, plaintext.length);
116     assertTrue("Transformation was not symmetric",
117       Bytes.equals(result, plaintext));
118   }
119 
120   private byte[] getRandomBlock(int size) {
121     byte[] b = new byte[size];
122     Bytes.random(b);
123     return b;
124   }
125 }