HBASE-11446 Reduce the frequency of RNG calls in SecureWALCellCodec#EncryptedKvEncoder

This commit is contained in:
Andrew Purtell 2014-07-04 10:45:19 -07:00
parent 360df59c0d
commit 2416d798fa
7 changed files with 61 additions and 13 deletions

View File

@ -42,6 +42,12 @@ public interface Decryptor {
*/ */
public int getIvLength(); public int getIvLength();
/**
* Get the cipher's internal block size
* @return the cipher's internal block size
*/
public int getBlockSize();
/** /**
* Set the initialization vector * Set the initialization vector
* @param iv * @param iv

View File

@ -537,8 +537,14 @@ public final class Encryption {
} }
public static void incrementIv(byte[] iv) { public static void incrementIv(byte[] iv) {
incrementIv(iv, 1);
}
public static void incrementIv(byte[] iv, int v) {
int length = iv.length; int length = iv.length;
boolean carry = true; boolean carry = true;
// TODO: Optimize for v > 1, e.g. 16, 32
do {
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
if (carry) { if (carry) {
iv[i] = (byte) ((iv[i] + 1) & 0xFF); iv[i] = (byte) ((iv[i] + 1) & 0xFF);
@ -547,6 +553,8 @@ public final class Encryption {
break; break;
} }
} }
v--;
} while (v > 0);
} }
} }

View File

@ -42,6 +42,12 @@ public interface Encryptor {
*/ */
public int getIvLength(); public int getIvLength();
/**
* Get the cipher's internal block size
* @return the cipher's internal block size
*/
public int getBlockSize();
/** /**
* Get the initialization vector * Get the initialization vector
*/ */
@ -63,5 +69,4 @@ public interface Encryptor {
* Reset state, reinitialize with the key and iv * Reset state, reinitialize with the key and iv
*/ */
void reset(); void reset();
} }

View File

@ -53,6 +53,7 @@ public class AES extends Cipher {
public static final int KEY_LENGTH = 16; public static final int KEY_LENGTH = 16;
public static final int KEY_LENGTH_BITS = KEY_LENGTH * 8; public static final int KEY_LENGTH_BITS = KEY_LENGTH * 8;
public static final int BLOCK_SIZE = 16;
public static final int IV_LENGTH = 16; public static final int IV_LENGTH = 16;
public static final String CIPHER_MODE_KEY = "hbase.crypto.algorithm.aes.mode"; public static final String CIPHER_MODE_KEY = "hbase.crypto.algorithm.aes.mode";

View File

@ -58,6 +58,11 @@ public class AESDecryptor implements Decryptor {
return AES.IV_LENGTH; return AES.IV_LENGTH;
} }
@Override
public int getBlockSize() {
return AES.BLOCK_SIZE;
}
@Override @Override
public void setIv(byte[] iv) { public void setIv(byte[] iv) {
Preconditions.checkNotNull(iv, "IV cannot be null"); Preconditions.checkNotNull(iv, "IV cannot be null");

View File

@ -60,6 +60,11 @@ public class AESEncryptor implements Encryptor {
return AES.IV_LENGTH; return AES.IV_LENGTH;
} }
@Override
public int getBlockSize() {
return AES.BLOCK_SIZE;
}
@Override @Override
public byte[] getIv() { public byte[] getIv() {
return iv; return iv;

View File

@ -31,6 +31,7 @@ import org.apache.hadoop.hbase.Cell;
import org.apache.hadoop.hbase.KeyValue; import org.apache.hadoop.hbase.KeyValue;
import org.apache.hadoop.hbase.codec.KeyValueCodec; import org.apache.hadoop.hbase.codec.KeyValueCodec;
import org.apache.hadoop.hbase.io.crypto.Decryptor; import org.apache.hadoop.hbase.io.crypto.Decryptor;
import org.apache.hadoop.hbase.io.crypto.Encryption;
import org.apache.hadoop.hbase.io.crypto.Encryptor; import org.apache.hadoop.hbase.io.crypto.Encryptor;
import org.apache.hadoop.hbase.io.util.StreamUtils; import org.apache.hadoop.hbase.io.util.StreamUtils;
import org.apache.hadoop.hbase.util.Bytes; import org.apache.hadoop.hbase.util.Bytes;
@ -40,8 +41,6 @@ import org.apache.hadoop.hbase.util.Bytes;
*/ */
public class SecureWALCellCodec extends WALCellCodec { public class SecureWALCellCodec extends WALCellCodec {
private static final SecureRandom RNG = new SecureRandom();
private Encryptor encryptor; private Encryptor encryptor;
private Decryptor decryptor; private Decryptor decryptor;
@ -139,7 +138,24 @@ public class SecureWALCellCodec extends WALCellCodec {
static class EncryptedKvEncoder extends KeyValueCodec.KeyValueEncoder { static class EncryptedKvEncoder extends KeyValueCodec.KeyValueEncoder {
private Encryptor encryptor; private Encryptor encryptor;
private byte[] iv; private final ThreadLocal<byte[]> iv = new ThreadLocal<byte[]>() {
@Override
protected byte[] initialValue() {
byte[] iv = new byte[encryptor.getIvLength()];
new SecureRandom().nextBytes(iv);
return iv;
}
};
protected byte[] nextIv() {
byte[] b = iv.get(), ret = new byte[b.length];
System.arraycopy(b, 0, ret, 0, b.length);
return ret;
}
protected void incrementIv(int v) {
Encryption.incrementIv(iv.get(), 1 + (v / encryptor.getBlockSize()));
}
public EncryptedKvEncoder(OutputStream os) { public EncryptedKvEncoder(OutputStream os) {
super(os); super(os);
@ -148,7 +164,6 @@ public class SecureWALCellCodec extends WALCellCodec {
public EncryptedKvEncoder(OutputStream os, Encryptor encryptor) { public EncryptedKvEncoder(OutputStream os, Encryptor encryptor) {
super(os); super(os);
this.encryptor = encryptor; this.encryptor = encryptor;
iv = new byte[encryptor.getIvLength()];
} }
@Override @Override
@ -159,7 +174,7 @@ public class SecureWALCellCodec extends WALCellCodec {
byte[] kvBuffer = kv.getBuffer(); byte[] kvBuffer = kv.getBuffer();
int offset = kv.getOffset(); int offset = kv.getOffset();
RNG.nextBytes(iv); byte[] iv = nextIv();
encryptor.setIv(iv); encryptor.setIv(iv);
encryptor.reset(); encryptor.reset();
@ -196,6 +211,9 @@ public class SecureWALCellCodec extends WALCellCodec {
StreamUtils.writeRawVInt32(out, baos.size()); StreamUtils.writeRawVInt32(out, baos.size());
baos.writeTo(out); baos.writeTo(out);
// Increment IV given the final payload length
incrementIv(baos.size());
} }
} }