· 7 years ago · Dec 10, 2018, 06:10 AM
1import android.util.Base64;
2
3import java.io.UnsupportedEncodingException;
4import java.security.GeneralSecurityException;
5import java.security.SecureRandom;
6import java.security.spec.KeySpec;
7
8import javax.crypto.Cipher;
9import javax.crypto.SecretKey;
10import javax.crypto.SecretKeyFactory;
11import javax.crypto.spec.IvParameterSpec;
12import javax.crypto.spec.PBEKeySpec;
13import javax.crypto.spec.SecretKeySpec;
14
15public class AESHelper {
16 private static final int ITERATION_COUNT = 1000;
17 private static final int KEY_LENGTH = 256;
18 private static final String PBKDF2_DERIVATION_ALGORITHM = "PBKDF2WithHmacSHA1";
19 private static final String CIPHER_ALGORITHM = "AES/CBC/PKCS5Padding";
20 private static final int PKCS5_SALT_LENGTH = 32;
21 private static final String DELIMITER = "]";
22 private static final SecureRandom random = new SecureRandom();
23
24 public static String encrypt(String plaintext, String password) {
25 byte[] salt = generateSalt();
26 SecretKey key = deriveKey(password, salt);
27
28 try {
29 Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
30 byte[] iv = generateIv(cipher.getBlockSize());
31 IvParameterSpec ivParams = new IvParameterSpec(iv);
32 cipher.init(Cipher.ENCRYPT_MODE, key, ivParams);
33 byte[] cipherText = cipher.doFinal(plaintext.getBytes("UTF-8"));
34
35 if(salt != null) {
36 return String.format("%s%s%s%s%s",
37 toBase64(salt),
38 DELIMITER,
39 toBase64(iv),
40 DELIMITER,
41 toBase64(cipherText));
42 }
43
44 return String.format("%s%s%s",
45 toBase64(iv),
46 DELIMITER,
47 toBase64(cipherText));
48 } catch (GeneralSecurityException e) {
49 throw new RuntimeException(e);
50 } catch (UnsupportedEncodingException e) {
51 throw new RuntimeException(e);
52 }
53 }
54
55 public static String decrypt(String ciphertext, String password) {
56 String[] fields = ciphertext.split(DELIMITER);
57 if(fields.length != 3) {
58 throw new IllegalArgumentException("Invalid encypted text format");
59 }
60 byte[] salt = fromBase64(fields[0]);
61 byte[] iv = fromBase64(fields[1]);
62 byte[] cipherBytes = fromBase64(fields[2]);
63 SecretKey key = deriveKey(password, salt);
64
65 try {
66 Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
67 IvParameterSpec ivParams = new IvParameterSpec(iv);
68 cipher.init(Cipher.DECRYPT_MODE, key, ivParams);
69 byte[] plaintext = cipher.doFinal(cipherBytes);
70 return new String(plaintext, "UTF-8");
71 } catch (GeneralSecurityException e) {
72 throw new RuntimeException(e);
73 } catch (UnsupportedEncodingException e) {
74 throw new RuntimeException(e);
75 }
76 }
77
78 private static byte[] generateSalt() {
79 byte[] b = new byte[PKCS5_SALT_LENGTH];
80 random.nextBytes(b);
81 return b;
82 }
83
84 private static byte[] generateIv(int length) {
85 byte[] b = new byte[length];
86 random.nextBytes(b);
87 return b;
88 }
89
90 private static SecretKey deriveKey(String password, byte[] salt) {
91 try {
92 KeySpec keySpec = new PBEKeySpec(password.toCharArray(), salt, ITERATION_COUNT, KEY_LENGTH);
93 SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(PBKDF2_DERIVATION_ALGORITHM);
94 byte[] keyBytes = keyFactory.generateSecret(keySpec).getEncoded();
95 return new SecretKeySpec(keyBytes, "AES");
96 } catch (GeneralSecurityException e) {
97 throw new RuntimeException(e);
98 }
99 }
100
101 private static String toBase64(byte[] bytes) {
102 return Base64.encodeToString(bytes, Base64.NO_WRAP);
103 }
104
105 private static byte[] fromBase64(String base64) {
106 return Base64.decode(base64, Base64.NO_WRAP);
107 }
108}