001/** 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.apache.hadoop.hbase.security; 019 020import static org.junit.Assert.assertNotNull; 021import static org.junit.Assert.assertTrue; 022import static org.junit.Assert.fail; 023 024import java.security.Key; 025import java.security.KeyException; 026import java.security.SecureRandom; 027import javax.crypto.spec.SecretKeySpec; 028import org.apache.hadoop.conf.Configuration; 029import org.apache.hadoop.hbase.HBaseClassTestRule; 030import org.apache.hadoop.hbase.HConstants; 031import org.apache.hadoop.hbase.io.crypto.KeyProviderForTesting; 032import org.apache.hadoop.hbase.io.crypto.aes.AES; 033import org.apache.hadoop.hbase.testclassification.ClientTests; 034import org.apache.hadoop.hbase.testclassification.SmallTests; 035import org.apache.hadoop.hbase.util.Bytes; 036import org.junit.ClassRule; 037import org.junit.Test; 038import org.junit.experimental.categories.Category; 039 040@Category({ClientTests.class, SmallTests.class}) 041public class TestEncryptionUtil { 042 043 @ClassRule 044 public static final HBaseClassTestRule CLASS_RULE = 045 HBaseClassTestRule.forClass(TestEncryptionUtil.class); 046 047 // There does not seem to be a ready way to test either getKeyFromBytesOrMasterKey 048 // or createEncryptionContext, and the existing code under MobUtils appeared to be 049 // untested. Not ideal! 050 051 @Test 052 public void testKeyWrapping() throws Exception { 053 // set up the key provider for testing to resolve a key for our test subject 054 Configuration conf = new Configuration(); // we don't need HBaseConfiguration for this 055 conf.set(HConstants.CRYPTO_KEYPROVIDER_CONF_KEY, KeyProviderForTesting.class.getName()); 056 057 // generate a test key 058 byte[] keyBytes = new byte[AES.KEY_LENGTH]; 059 new SecureRandom().nextBytes(keyBytes); 060 String algorithm = 061 conf.get(HConstants.CRYPTO_KEY_ALGORITHM_CONF_KEY, HConstants.CIPHER_AES); 062 Key key = new SecretKeySpec(keyBytes, algorithm); 063 064 // wrap the test key 065 byte[] wrappedKeyBytes = EncryptionUtil.wrapKey(conf, "hbase", key); 066 assertNotNull(wrappedKeyBytes); 067 068 // unwrap 069 Key unwrappedKey = EncryptionUtil.unwrapKey(conf, "hbase", wrappedKeyBytes); 070 assertNotNull(unwrappedKey); 071 // only secretkeyspec supported for now 072 assertTrue(unwrappedKey instanceof SecretKeySpec); 073 // did we get back what we wrapped? 074 assertTrue("Unwrapped key bytes do not match original", 075 Bytes.equals(keyBytes, unwrappedKey.getEncoded())); 076 077 // unwrap with an incorrect key 078 try { 079 EncryptionUtil.unwrapKey(conf, "other", wrappedKeyBytes); 080 fail("Unwrap with incorrect key did not throw KeyException"); 081 } catch (KeyException e) { 082 // expected 083 } 084 } 085 086 @Test 087 public void testWALKeyWrapping() throws Exception { 088 // set up the key provider for testing to resolve a key for our test subject 089 Configuration conf = new Configuration(); // we don't need HBaseConfiguration for this 090 conf.set(HConstants.CRYPTO_KEYPROVIDER_CONF_KEY, KeyProviderForTesting.class.getName()); 091 092 // generate a test key 093 byte[] keyBytes = new byte[AES.KEY_LENGTH]; 094 new SecureRandom().nextBytes(keyBytes); 095 String algorithm = conf.get(HConstants.CRYPTO_WAL_ALGORITHM_CONF_KEY, HConstants.CIPHER_AES); 096 Key key = new SecretKeySpec(keyBytes, algorithm); 097 098 // wrap the test key 099 byte[] wrappedKeyBytes = EncryptionUtil.wrapKey(conf, "hbase", key); 100 assertNotNull(wrappedKeyBytes); 101 102 // unwrap 103 Key unwrappedKey = EncryptionUtil.unwrapWALKey(conf, "hbase", wrappedKeyBytes); 104 assertNotNull(unwrappedKey); 105 // only secretkeyspec supported for now 106 assertTrue(unwrappedKey instanceof SecretKeySpec); 107 // did we get back what we wrapped? 108 assertTrue("Unwrapped key bytes do not match original", 109 Bytes.equals(keyBytes, unwrappedKey.getEncoded())); 110 } 111 112 @Test(expected = KeyException.class) 113 public void testWALKeyWrappingWithIncorrectKey() throws Exception { 114 // set up the key provider for testing to resolve a key for our test subject 115 Configuration conf = new Configuration(); // we don't need HBaseConfiguration for this 116 conf.set(HConstants.CRYPTO_KEYPROVIDER_CONF_KEY, KeyProviderForTesting.class.getName()); 117 118 // generate a test key 119 byte[] keyBytes = new byte[AES.KEY_LENGTH]; 120 new SecureRandom().nextBytes(keyBytes); 121 String algorithm = conf.get(HConstants.CRYPTO_WAL_ALGORITHM_CONF_KEY, HConstants.CIPHER_AES); 122 Key key = new SecretKeySpec(keyBytes, algorithm); 123 124 // wrap the test key 125 byte[] wrappedKeyBytes = EncryptionUtil.wrapKey(conf, "hbase", key); 126 assertNotNull(wrappedKeyBytes); 127 128 // unwrap with an incorrect key 129 EncryptionUtil.unwrapWALKey(conf, "other", wrappedKeyBytes); 130 } 131}