1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.hadoop.hbase.regionserver.wal;
20
21 import java.io.IOException;
22 import java.security.Key;
23 import java.security.SecureRandom;
24
25 import javax.crypto.spec.SecretKeySpec;
26
27 import org.apache.hadoop.conf.Configuration;
28 import org.apache.hadoop.hbase.util.ByteStringer;
29 import org.apache.hadoop.hbase.util.EncryptionTest;
30 import org.apache.commons.logging.Log;
31 import org.apache.commons.logging.LogFactory;
32 import org.apache.hadoop.hbase.classification.InterfaceAudience;
33 import org.apache.hadoop.hbase.HBaseInterfaceAudience;
34 import org.apache.hadoop.hbase.HConstants;
35 import org.apache.hadoop.hbase.io.crypto.Cipher;
36 import org.apache.hadoop.hbase.io.crypto.Encryption;
37 import org.apache.hadoop.hbase.io.crypto.Encryptor;
38 import org.apache.hadoop.hbase.protobuf.generated.WALProtos.WALHeader;
39 import org.apache.hadoop.hbase.security.EncryptionUtil;
40 import org.apache.hadoop.hbase.security.User;
41
42 @InterfaceAudience.LimitedPrivate(HBaseInterfaceAudience.CONFIG)
43 public class SecureProtobufLogWriter extends ProtobufLogWriter {
44
45 private static final Log LOG = LogFactory.getLog(SecureProtobufLogWriter.class);
46 private static final String DEFAULT_CIPHER = "AES";
47
48 private Encryptor encryptor = null;
49
50 @Override
51 protected WALHeader buildWALHeader(Configuration conf, WALHeader.Builder builder)
52 throws IOException {
53 builder.setWriterClsName(SecureProtobufLogWriter.class.getSimpleName());
54 if (conf.getBoolean(HConstants.ENABLE_WAL_ENCRYPTION, false)) {
55 EncryptionTest.testKeyProvider(conf);
56 EncryptionTest.testCipherProvider(conf);
57
58
59 final String cipherName = conf.get(HConstants.CRYPTO_WAL_ALGORITHM_CONF_KEY, DEFAULT_CIPHER);
60 Cipher cipher = Encryption.getCipher(conf, cipherName);
61 if (cipher == null) {
62 throw new RuntimeException("Cipher '" + cipherName + "' is not available");
63 }
64
65
66 SecureRandom rng = new SecureRandom();
67 byte[] keyBytes = new byte[cipher.getKeyLength()];
68 rng.nextBytes(keyBytes);
69 Key key = new SecretKeySpec(keyBytes, cipher.getName());
70 builder.setEncryptionKey(ByteStringer.wrap(EncryptionUtil.wrapKey(conf,
71 conf.get(HConstants.CRYPTO_WAL_KEY_NAME_CONF_KEY,
72 conf.get(HConstants.CRYPTO_MASTERKEY_NAME_CONF_KEY,
73 User.getCurrent().getShortName())),
74 key)));
75
76
77 encryptor = cipher.getEncryptor();
78 encryptor.setKey(key);
79
80 if (LOG.isTraceEnabled()) {
81 LOG.trace("Initialized secure protobuf WAL: cipher=" + cipher.getName());
82 }
83 }
84 builder.setCellCodecClsName(SecureWALCellCodec.class.getName());
85 return super.buildWALHeader(conf, builder);
86 }
87
88 @Override
89 protected void initAfterHeader(boolean doCompress) throws IOException {
90 if (conf.getBoolean(HConstants.ENABLE_WAL_ENCRYPTION, false) && encryptor != null) {
91 WALCellCodec codec = SecureWALCellCodec.getCodec(this.conf, encryptor);
92 this.cellEncoder = codec.getEncoder(this.output);
93
94 this.compressionContext = null;
95 } else {
96 super.initAfterHeader(doCompress);
97 }
98 }
99
100 }