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.classification.InterfaceAudience;
32 import org.apache.hadoop.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 IV_LENGTH = 16;
57
58 public static final String CIPHER_MODE_KEY = "hbase.crypto.algorithm.aes.mode";
59 public static final String CIPHER_PROVIDER_KEY = "hbase.crypto.algorithm.aes.provider";
60 public static final String RNG_ALGORITHM_KEY = "hbase.crypto.algorithm.rng";
61 public static final String RNG_PROVIDER_KEY = "hbase.crypto.algorithm.rng.provider";
62
63 private final String rngAlgorithm;
64 private final String cipherMode;
65 private final String cipherProvider;
66 private SecureRandom rng;
67
68 public AES(CipherProvider provider) {
69 super(provider);
70
71 cipherMode = provider.getConf().get(CIPHER_MODE_KEY, "AES/CTR/NoPadding");
72
73 cipherProvider = provider.getConf().get(CIPHER_PROVIDER_KEY);
74
75 rngAlgorithm = provider.getConf().get(RNG_ALGORITHM_KEY, "SHA1PRNG");
76
77 String rngProvider = provider.getConf().get(RNG_PROVIDER_KEY);
78 try {
79 if (rngProvider != null) {
80 rng = SecureRandom.getInstance(rngAlgorithm, rngProvider);
81 } else {
82 rng = SecureRandom.getInstance(rngAlgorithm);
83 }
84 } catch (GeneralSecurityException e) {
85 LOG.warn("Could not instantiate specified RNG, falling back to default", e);
86 rng = new SecureRandom();
87 }
88 }
89
90 @Override
91 public String getName() {
92 return "AES";
93 }
94
95 @Override
96 public int getKeyLength() {
97 return KEY_LENGTH;
98 }
99
100 @Override
101 public int getIvLength() {
102 return IV_LENGTH;
103 }
104
105 @Override
106 public Key getRandomKey() {
107 byte[] keyBytes = new byte[getKeyLength()];
108 rng.nextBytes(keyBytes);
109 return new SecretKeySpec(keyBytes, getName());
110 }
111
112 @Override
113 public Encryptor getEncryptor() {
114 return new AESEncryptor(getJCECipherInstance(), rng);
115 }
116
117 @Override
118 public Decryptor getDecryptor() {
119 return new AESDecryptor(getJCECipherInstance());
120 }
121
122 @Override
123 public OutputStream createEncryptionStream(OutputStream out, Context context, byte[] iv)
124 throws IOException {
125 Preconditions.checkNotNull(context);
126 Preconditions.checkState(context.getKey() != null, "Context does not have a key");
127 Preconditions.checkNotNull(iv);
128 Encryptor e = getEncryptor();
129 e.setKey(context.getKey());
130 e.setIv(iv);
131 return e.createEncryptionStream(out);
132 }
133
134 @Override
135 public OutputStream createEncryptionStream(OutputStream out, Encryptor e) throws IOException {
136 Preconditions.checkNotNull(e);
137 return e.createEncryptionStream(out);
138 }
139
140 @Override
141 public InputStream createDecryptionStream(InputStream in, Context context, byte[] iv)
142 throws IOException {
143 Preconditions.checkNotNull(context);
144 Preconditions.checkState(context.getKey() != null, "Context does not have a key");
145 Preconditions.checkNotNull(iv);
146 Decryptor d = getDecryptor();
147 d.setKey(context.getKey());
148 d.setIv(iv);
149 return d.createDecryptionStream(in);
150 }
151
152 @Override
153 public InputStream createDecryptionStream(InputStream in, Decryptor d) throws IOException {
154 Preconditions.checkNotNull(d);
155 return d.createDecryptionStream(in);
156 }
157
158 @VisibleForTesting
159 SecureRandom getRNG() {
160 return rng;
161 }
162
163 private javax.crypto.Cipher getJCECipherInstance() {
164 try {
165 if (cipherProvider != null) {
166 return javax.crypto.Cipher.getInstance(cipherMode, cipherProvider);
167 }
168 return javax.crypto.Cipher.getInstance(cipherMode);
169 } catch (GeneralSecurityException e) {
170 throw new RuntimeException(e);
171 }
172 }
173
174 }