1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.hadoop.hbase.security;
19
20 import java.io.ByteArrayInputStream;
21 import java.io.ByteArrayOutputStream;
22 import java.io.IOException;
23 import java.security.Key;
24 import java.security.KeyException;
25 import java.security.SecureRandom;
26
27 import javax.crypto.spec.SecretKeySpec;
28
29 import org.apache.hadoop.hbase.util.ByteStringer;
30 import org.apache.hadoop.hbase.classification.InterfaceAudience;
31 import org.apache.hadoop.hbase.classification.InterfaceStability;
32 import org.apache.hadoop.conf.Configuration;
33 import org.apache.hadoop.hbase.HConstants;
34 import org.apache.hadoop.hbase.io.crypto.Cipher;
35 import org.apache.hadoop.hbase.io.crypto.Encryption;
36 import org.apache.hadoop.hbase.protobuf.generated.EncryptionProtos;
37 import org.apache.hadoop.hbase.util.Bytes;
38
39
40
41
42 @InterfaceAudience.Private
43 @InterfaceStability.Evolving
44 public class EncryptionUtil {
45
46 static private final SecureRandom RNG = new SecureRandom();
47
48
49
50
51
52
53
54
55
56
57 public static byte[] wrapKey(Configuration conf, byte[] key, String algorithm)
58 throws IOException {
59 return wrapKey(conf,
60 conf.get(HConstants.CRYPTO_MASTERKEY_NAME_CONF_KEY, User.getCurrent().getShortName()),
61 new SecretKeySpec(key, algorithm));
62 }
63
64
65
66
67
68
69
70
71
72 public static byte[] wrapKey(Configuration conf, String subject, Key key)
73 throws IOException {
74
75 String algorithm =
76 conf.get(HConstants.CRYPTO_KEY_ALGORITHM_CONF_KEY, HConstants.CIPHER_AES);
77 Cipher cipher = Encryption.getCipher(conf, algorithm);
78 if (cipher == null) {
79 throw new RuntimeException("Cipher '" + algorithm + "' not available");
80 }
81 EncryptionProtos.WrappedKey.Builder builder = EncryptionProtos.WrappedKey.newBuilder();
82 builder.setAlgorithm(key.getAlgorithm());
83 byte[] iv = null;
84 if (cipher.getIvLength() > 0) {
85 iv = new byte[cipher.getIvLength()];
86 RNG.nextBytes(iv);
87 builder.setIv(ByteStringer.wrap(iv));
88 }
89 byte[] keyBytes = key.getEncoded();
90 builder.setLength(keyBytes.length);
91 builder.setHash(ByteStringer.wrap(Encryption.hash128(keyBytes)));
92 ByteArrayOutputStream out = new ByteArrayOutputStream();
93 Encryption.encryptWithSubjectKey(out, new ByteArrayInputStream(keyBytes), subject,
94 conf, cipher, iv);
95 builder.setData(ByteStringer.wrap(out.toByteArray()));
96
97 out.reset();
98 builder.build().writeDelimitedTo(out);
99 return out.toByteArray();
100 }
101
102
103
104
105
106
107
108
109
110
111
112 public static Key unwrapKey(Configuration conf, String subject, byte[] value)
113 throws IOException, KeyException {
114 EncryptionProtos.WrappedKey wrappedKey = EncryptionProtos.WrappedKey.PARSER
115 .parseDelimitedFrom(new ByteArrayInputStream(value));
116 String algorithm = conf.get(HConstants.CRYPTO_KEY_ALGORITHM_CONF_KEY,
117 HConstants.CIPHER_AES);
118 Cipher cipher = Encryption.getCipher(conf, algorithm);
119 if (cipher == null) {
120 throw new RuntimeException("Cipher '" + algorithm + "' not available");
121 }
122 return getUnwrapKey(conf, subject, wrappedKey, cipher);
123 }
124
125 private static Key getUnwrapKey(Configuration conf, String subject,
126 EncryptionProtos.WrappedKey wrappedKey, Cipher cipher) throws IOException, KeyException {
127 ByteArrayOutputStream out = new ByteArrayOutputStream();
128 byte[] iv = wrappedKey.hasIv() ? wrappedKey.getIv().toByteArray() : null;
129 Encryption.decryptWithSubjectKey(out, wrappedKey.getData().newInput(),
130 wrappedKey.getLength(), subject, conf, cipher, iv);
131 byte[] keyBytes = out.toByteArray();
132 if (wrappedKey.hasHash()) {
133 if (!Bytes.equals(wrappedKey.getHash().toByteArray(), Encryption.hash128(keyBytes))) {
134 throw new KeyException("Key was not successfully unwrapped");
135 }
136 }
137 return new SecretKeySpec(keyBytes, wrappedKey.getAlgorithm());
138 }
139
140
141
142
143
144
145
146
147
148
149
150 public static Key unwrapWALKey(Configuration conf, String subject, byte[] value)
151 throws IOException, KeyException {
152 EncryptionProtos.WrappedKey wrappedKey =
153 EncryptionProtos.WrappedKey.PARSER.parseDelimitedFrom(new ByteArrayInputStream(value));
154 String algorithm = conf.get(HConstants.CRYPTO_WAL_ALGORITHM_CONF_KEY, HConstants.CIPHER_AES);
155 Cipher cipher = Encryption.getCipher(conf, algorithm);
156 if (cipher == null) {
157 throw new RuntimeException("Cipher '" + algorithm + "' not available");
158 }
159 return getUnwrapKey(conf, subject, wrappedKey, cipher);
160 }
161
162 }