· 7 years ago · Jun 26, 2018, 01:16 AM
1package ffmpegplayer.hb.com.chatlib.utils;
2
3import android.util.Base64;
4import android.util.Log;
5
6import java.io.UnsupportedEncodingException;
7import java.security.GeneralSecurityException;
8import java.security.Key;
9import java.security.NoSuchAlgorithmException;
10import java.security.SecureRandom;
11import java.security.spec.InvalidKeySpecException;
12
13import javax.crypto.Cipher;
14import javax.crypto.SecretKeyFactory;
15import javax.crypto.spec.IvParameterSpec;
16import javax.crypto.spec.PBEKeySpec;
17import javax.crypto.spec.SecretKeySpec;
18
19import ffmpegplayer.hb.com.chatlib.BuildConfig;
20
21/**
22 * Utility class to encrypt / decrypt text.
23 */
24public class AESEncryption {
25 private static final String AES_MODE = "AES/CBC/PKCS5Padding";
26 // private static final String encryptionKey = "Zp@ss560^)";
27 private static final int ENCRYPTION_KEY_LENGTH = 32;
28 private static final int IV_LENGTH_BYTES = 16;
29 private static final int SALT_LENGTH_BYTES = 8;
30
31 private static SecretKeySpec getSecretKey(byte[] key) throws Exception {
32 return new SecretKeySpec(key, "AES");
33 }
34
35 /**
36 * generate secure random encryption key
37 *
38 * @return
39 */
40 public static String generateAESKey() {
41 String encryptionKey = null;
42 try {
43 encryptionKey = new String(randomBytes(ENCRYPTION_KEY_LENGTH), "UTF8");
44
45 if (BuildConfig.DEBUG) {
46 Log.e("encryptionKey", encryptionKey);
47 }
48
49 } catch (UnsupportedEncodingException e) {
50 e.printStackTrace();
51 } catch (GeneralSecurityException e) {
52 e.printStackTrace();
53 }
54 return encryptionKey;
55 }
56
57 /**
58 * encrypt text
59 *
60 * @param plaintext text to encrypt
61 * @return base64encoded iv:base64 encoded salt:base64 encoded encrypted text
62 */
63 public static String encrypt(String plaintext, String encryptionKey) {
64 try {
65 byte[] input = plaintext.getBytes();
66 byte[] salt = randomBytes(SALT_LENGTH_BYTES);
67 byte[] iv = randomBytes(IV_LENGTH_BYTES);
68
69 byte[] key = deriveKeyFromPassphrase(encryptionKey, salt, 2000);
70
71 Cipher cipher = Cipher.getInstance(AES_MODE);
72 cipher.init(Cipher.ENCRYPT_MODE, getSecretKey(key), new IvParameterSpec(iv));
73 /*
74 * Now we get back the IV that will actually be used. Some Android
75 * versions do funny stuff w/ the IV, so this is to work around bugs:
76 */
77 iv = cipher.getIV();
78
79 Log.e("base 64 encoded iv", Base64.encodeToString(iv, Base64.DEFAULT));
80 byte[] encodedBytes = cipher.doFinal(input);
81 String encryptedBase64Encoded = Base64.encodeToString(encodedBytes, Base64.DEFAULT);
82
83
84 return Base64.encodeToString(iv, Base64.DEFAULT) + ":" + Base64.encodeToString(salt, Base64.DEFAULT) + ":" + encryptedBase64Encoded;
85 } catch (Exception e) {
86 e.printStackTrace();
87 }
88 return null;
89 }
90
91 private static byte[] deriveKeyFromPassphrase(String passphrase, byte[] salt, int iterationCount) throws NoSuchAlgorithmException, InvalidKeySpecException {
92 SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
93 PBEKeySpec pbeKeySpec = new PBEKeySpec(passphrase.toCharArray(), salt, iterationCount, 384);
94 Key secretKey = factory.generateSecret(pbeKeySpec);
95 byte[] key = new byte[32];
96 System.arraycopy(secretKey.getEncoded(), 0, key, 0, 32);
97 return key;
98 }
99
100 /**
101 * decrypt encrypted string
102 *
103 * @param encrypted encrypted string. Must be generated by encrypt method.
104 * @return plain text
105 */
106 public static String decrypt(String encrypted, String encryptionKey) {
107 try {
108 String[] splitOfEncrypted = encrypted.split(":");
109 if (splitOfEncrypted.length == 3) {
110 byte[] iv = Base64.decode(splitOfEncrypted[0], Base64.DEFAULT);
111 byte[] salt = Base64.decode(splitOfEncrypted[1], Base64.DEFAULT);
112 byte[] encryptedBytes = Base64.decode(splitOfEncrypted[2], Base64.DEFAULT);
113
114 byte[] key = deriveKeyFromPassphrase(encryptionKey, salt, 2000);
115
116
117 Cipher cipher = Cipher.getInstance(AES_MODE);
118 cipher.init(Cipher.DECRYPT_MODE, getSecretKey(key), new IvParameterSpec(iv));
119 byte[] decodedBytes = cipher.doFinal(encryptedBytes);
120 return new String(decodedBytes);
121 }
122 } catch (Exception e) {
123 e.printStackTrace();
124 }
125 return null;
126 }
127
128 /**
129 * generate secure random bytes
130 *
131 * @param length byte length
132 * @return random bytes
133 * @throws GeneralSecurityException
134 */
135 private static byte[] randomBytes(int length) throws GeneralSecurityException {
136 SecureRandom random = new SecureRandom();
137 byte[] b = new byte[length];
138 random.nextBytes(b);
139 return b;
140 }
141}