· 7 years ago · Mar 28, 2018, 10:16 AM
1package uk.tommyt.kafka.krypto;
2
3import org.bouncycastle.jce.provider.BouncyCastleProvider;
4
5import javax.crypto.BadPaddingException;
6import javax.crypto.Cipher;
7import javax.crypto.IllegalBlockSizeException;
8import javax.crypto.KeyGenerator;
9import javax.crypto.NoSuchPaddingException;
10import javax.crypto.SecretKey;
11import javax.crypto.spec.IvParameterSpec;
12import javax.crypto.spec.SecretKeySpec;
13import java.security.InvalidAlgorithmParameterException;
14import java.security.InvalidKeyException;
15import java.security.NoSuchAlgorithmException;
16import java.security.SecureRandom;
17import java.security.Security;
18
19public class AesUniqueIv {
20 private static final String CIPHER = "AES/GCM/NoPadding";
21 private static final String KEY_TYPE = "AES";
22 private static final int AES_BITS = 256;
23 private static final int IV_BYTES = 16;
24 private final SecureRandom secureRandom = new SecureRandom();
25 private SecretKey secretKey;
26 private Cipher cipher;
27
28 static {
29 Security.addProvider(new BouncyCastleProvider());
30 }
31
32 /**
33 * Encryptor with random key
34 */
35 public AesUniqueIv() throws NoSuchAlgorithmException, NoSuchPaddingException {
36 this(newKey());
37 }
38
39 /**
40 * Encryptor with provided key
41 */
42 public AesUniqueIv(byte[] key) throws NoSuchAlgorithmException, NoSuchPaddingException {
43 this(new SecretKeySpec(key, KEY_TYPE));
44 }
45
46 private AesUniqueIv(SecretKey key) throws NoSuchPaddingException, NoSuchAlgorithmException {
47 this.secretKey = key;
48 cipher = Cipher.getInstance(CIPHER);
49 }
50
51 public byte[] getKey() {
52 return secretKey.getEncoded();
53 }
54
55 public byte[] encrypt(byte[] message) throws InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
56 IvParameterSpec iv = newIvParameterSpec();
57 cipher.init(Cipher.ENCRYPT_MODE, secretKey, iv);
58 byte[] encrypted = cipher.doFinal(message);
59 byte[] encryptedWithIv = new byte[IV_BYTES + encrypted.length];
60 System.arraycopy(iv.getIV(), 0, encryptedWithIv, 0, iv.getIV().length);
61 System.arraycopy(encrypted, 0, encryptedWithIv, IV_BYTES, encrypted.length);
62 return encryptedWithIv;
63 }
64
65 public byte[] decrypt(byte[] message) throws InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
66 byte[] iv = new byte[IV_BYTES];
67 byte[] encrypted = new byte[message.length - IV_BYTES];
68 System.arraycopy(message, 0, iv, 0, IV_BYTES);
69 System.arraycopy(message, IV_BYTES, encrypted, 0, message.length - IV_BYTES);
70 cipher.init(Cipher.DECRYPT_MODE, secretKey, new IvParameterSpec(iv));
71 return cipher.doFinal(encrypted);
72 }
73
74 private static SecretKey newKey() throws NoSuchAlgorithmException {
75 KeyGenerator keyGenerator = KeyGenerator.getInstance(KEY_TYPE);
76 keyGenerator.init(AES_BITS);
77 return keyGenerator.generateKey();
78 }
79
80 private IvParameterSpec newIvParameterSpec() {
81 byte[] iv = new byte[IV_BYTES];
82 secureRandom.nextBytes(iv);
83 return new IvParameterSpec(iv);
84 }
85}