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.classification.InterfaceAudience;
31 import org.apache.hadoop.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
73 public static byte[] wrapKey(Configuration conf, String subject, Key key)
74 throws IOException {
75
76 Cipher cipher = Encryption.getCipher(conf, "AES");
77 if (cipher == null) {
78 throw new RuntimeException("Cipher 'AES' not available");
79 }
80 EncryptionProtos.WrappedKey.Builder builder = EncryptionProtos.WrappedKey.newBuilder();
81 builder.setAlgorithm(key.getAlgorithm());
82 byte[] iv = null;
83 if (cipher.getIvLength() > 0) {
84 iv = new byte[cipher.getIvLength()];
85 RNG.nextBytes(iv);
86 builder.setIv(ByteStringer.wrap(iv));
87 }
88 byte[] keyBytes = key.getEncoded();
89 builder.setLength(keyBytes.length);
90 builder.setHash(ByteStringer.wrap(Encryption.hash128(keyBytes)));
91 ByteArrayOutputStream out = new ByteArrayOutputStream();
92 Encryption.encryptWithSubjectKey(out, new ByteArrayInputStream(keyBytes), subject,
93 conf, cipher, iv);
94 builder.setData(ByteStringer.wrap(out.toByteArray()));
95
96 out.reset();
97 builder.build().writeDelimitedTo(out);
98 return out.toByteArray();
99 }
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 Cipher cipher = Encryption.getCipher(conf, "AES");
117 if (cipher == null) {
118 throw new RuntimeException("Algorithm 'AES' not available");
119 }
120 ByteArrayOutputStream out = new ByteArrayOutputStream();
121 byte[] iv = wrappedKey.hasIv() ? wrappedKey.getIv().toByteArray() : null;
122 Encryption.decryptWithSubjectKey(out, wrappedKey.getData().newInput(),
123 wrappedKey.getLength(), subject, conf, cipher, iv);
124 byte[] keyBytes = out.toByteArray();
125 if (wrappedKey.hasHash()) {
126 if (!Bytes.equals(wrappedKey.getHash().toByteArray(), Encryption.hash128(keyBytes))) {
127 throw new KeyException("Key was not successfully unwrapped");
128 }
129 }
130 return new SecretKeySpec(keyBytes, wrappedKey.getAlgorithm());
131 }
132
133 }