1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.hadoop.hbase.io.crypto.aes;
19
20 import java.io.IOException;
21 import java.io.InputStream;
22 import java.io.OutputStream;
23 import java.security.GeneralSecurityException;
24 import java.security.Key;
25 import java.security.SecureRandom;
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.hbase.classification.InterfaceAudience;
32 import org.apache.hadoop.hbase.classification.InterfaceStability;
33 import org.apache.hadoop.hbase.io.crypto.Cipher;
34 import org.apache.hadoop.hbase.io.crypto.CipherProvider;
35 import org.apache.hadoop.hbase.io.crypto.Context;
36 import org.apache.hadoop.hbase.io.crypto.Decryptor;
37 import org.apache.hadoop.hbase.io.crypto.Encryptor;
38
39 import com.google.common.annotations.VisibleForTesting;
40 import com.google.common.base.Preconditions;
41
42
43
44
45
46
47
48 @InterfaceAudience.Private
49 @InterfaceStability.Evolving
50 public class AES extends Cipher {
51
52 private static final Log LOG = LogFactory.getLog(AES.class);
53
54 public static final int KEY_LENGTH = 16;
55 public static final int KEY_LENGTH_BITS = KEY_LENGTH * 8;
56 public static final int BLOCK_SIZE = 16;
57 public static final int IV_LENGTH = 16;
58
59 public static final String CIPHER_MODE_KEY = "hbase.crypto.algorithm.aes.mode";
60 public static final String CIPHER_PROVIDER_KEY = "hbase.crypto.algorithm.aes.provider";
61 public static final String RNG_ALGORITHM_KEY = "hbase.crypto.algorithm.rng";
62 public static final String RNG_PROVIDER_KEY = "hbase.crypto.algorithm.rng.provider";
63
64 private final String rngAlgorithm;
65 private final String cipherMode;
66 private final String cipherProvider;
67 private SecureRandom rng;
68
69 public AES(CipherProvider provider) {
70 super(provider);
71
72 cipherMode = provider.getConf().get(CIPHER_MODE_KEY, "AES/CTR/NoPadding");
73
74 cipherProvider = provider.getConf().get(CIPHER_PROVIDER_KEY);
75
76 rngAlgorithm = provider.getConf().get(RNG_ALGORITHM_KEY, "SHA1PRNG");
77
78 String rngProvider = provider.getConf().get(RNG_PROVIDER_KEY);
79 try {
80 if (rngProvider != null) {
81 rng = SecureRandom.getInstance(rngAlgorithm, rngProvider);
82 } else {
83 rng = SecureRandom.getInstance(rngAlgorithm);
84 }
85 } catch (GeneralSecurityException e) {
86 LOG.warn("Could not instantiate specified RNG, falling back to default", e);
87 rng = new SecureRandom();
88 }
89 }
90
91 @Override
92 public String getName() {
93 return "AES";
94 }
95
96 @Override
97 public int getKeyLength() {
98 return KEY_LENGTH;
99 }
100
101 @Override
102 public int getIvLength() {
103 return IV_LENGTH;
104 }
105
106 @Override
107 public Key getRandomKey() {
108 byte[] keyBytes = new byte[getKeyLength()];
109 rng.nextBytes(keyBytes);
110 return new SecretKeySpec(keyBytes, getName());
111 }
112
113 @Override
114 public Encryptor getEncryptor() {
115 return new AESEncryptor(getJCECipherInstance(), rng);
116 }
117
118 @Override
119 public Decryptor getDecryptor() {
120 return new AESDecryptor(getJCECipherInstance());
121 }
122
123 @Override
124 public OutputStream createEncryptionStream(OutputStream out, Context context, byte[] iv)
125 throws IOException {
126 Preconditions.checkNotNull(context);
127 Preconditions.checkState(context.getKey() != null, "Context does not have a key");
128 Preconditions.checkNotNull(iv);
129 Encryptor e = getEncryptor();
130 e.setKey(context.getKey());
131 e.setIv(iv);
132 return e.createEncryptionStream(out);
133 }
134
135 @Override
136 public OutputStream createEncryptionStream(OutputStream out, Encryptor e) throws IOException {
137 Preconditions.checkNotNull(e);
138 return e.createEncryptionStream(out);
139 }
140
141 @Override
142 public InputStream createDecryptionStream(InputStream in, Context context, byte[] iv)
143 throws IOException {
144 Preconditions.checkNotNull(context);
145 Preconditions.checkState(context.getKey() != null, "Context does not have a key");
146 Preconditions.checkNotNull(iv);
147 Decryptor d = getDecryptor();
148 d.setKey(context.getKey());
149 d.setIv(iv);
150 return d.createDecryptionStream(in);
151 }
152
153 @Override
154 public InputStream createDecryptionStream(InputStream in, Decryptor d) throws IOException {
155 Preconditions.checkNotNull(d);
156 return d.createDecryptionStream(in);
157 }
158
159 @VisibleForTesting
160 SecureRandom getRNG() {
161 return rng;
162 }
163
164 private javax.crypto.Cipher getJCECipherInstance() {
165 try {
166 if (cipherProvider != null) {
167 return javax.crypto.Cipher.getInstance(cipherMode, cipherProvider);
168 }
169 return javax.crypto.Cipher.getInstance(cipherMode);
170 } catch (GeneralSecurityException e) {
171 throw new RuntimeException(e);
172 }
173 }
174
175 }