· 9 years ago · Nov 04, 2016, 12:12 PM
1package com.itelinc.android.itelmobile.utils.encryption;
2
3import com.itelinc.android.itelmobile.utils.HexEncoder;
4
5import org.apache.commons.io.IOUtils;
6
7import java.io.File;
8import java.io.FileInputStream;
9import java.io.FileOutputStream;
10import java.io.IOException;
11import java.io.InputStream;
12import java.io.OutputStream;
13import java.security.MessageDigest;
14import java.security.SecureRandom;
15
16import javax.crypto.Cipher;
17import javax.crypto.CipherInputStream;
18import javax.crypto.CipherOutputStream;
19import javax.crypto.SecretKey;
20import javax.crypto.SecretKeyFactory;
21import javax.crypto.spec.IvParameterSpec;
22import javax.crypto.spec.PBEKeySpec;
23import javax.crypto.spec.SecretKeySpec;
24
25import timber.log.Timber;
26
27public final class EncryptionUtils {
28
29 private static final String PROVIDER = "BC";
30 private static final int IV_LENGTH = 16;
31 private static final int SALT_LENGTH = 32;
32 private static final int PBE_ITERATION_COUNT = 100;
33
34 private static final String RANDOM_ALGORITHM = "SHA1PRNG";
35 private static final String HASH_ALGORITHM = "SHA-512";
36 private static final String PBE_ALGORITHM = "PBEWithSHA256And256BitAES-CBC-BC";
37 private static final String CIPHER_ALGORITHM = "AES/CBC/PKCS5Padding";
38 private static final String SECRET_KEY_ALGORITHM = "AES";
39
40 private EncryptionUtils() {
41
42 }
43
44 public static String encrypt(final SecretKey secret, final String cleartext) {
45 try {
46 final byte[] iv = generateIv();
47 final String ivHex = HexEncoder.encode(iv);
48 final IvParameterSpec ivspec = new IvParameterSpec(iv);
49
50 final Cipher encryptionCipher = Cipher.getInstance(
51 CIPHER_ALGORITHM, PROVIDER);
52 encryptionCipher.init(Cipher.ENCRYPT_MODE, secret, ivspec);
53 final byte[] encryptedText = encryptionCipher.doFinal(cleartext
54 .getBytes("UTF-8"));
55 final String encryptedHex = HexEncoder.encode(encryptedText);
56
57 return ivHex + encryptedHex;
58 } catch (Exception e) {
59 throw new RuntimeException("Unable to encrypt", e);
60 }
61 }
62
63 public static String decrypt(final SecretKey secret, final String encrypted) {
64 try {
65 final Cipher decryptionCipher = Cipher.getInstance(
66 CIPHER_ALGORITHM, PROVIDER);
67 final String ivHex = encrypted.substring(0, IV_LENGTH * 2);
68 final String encryptedHex = encrypted.substring(IV_LENGTH * 2);
69 final IvParameterSpec ivspec = new IvParameterSpec(
70 HexEncoder.decode(ivHex));
71 decryptionCipher.init(Cipher.DECRYPT_MODE, secret, ivspec);
72 final byte[] decryptedText = decryptionCipher.doFinal(HexEncoder
73 .decode(encryptedHex));
74 final String decrypted = new String(decryptedText, "UTF-8");
75 return decrypted;
76 } catch (Exception e) {
77 throw new RuntimeException("Unable to decrypt", e);
78 }
79 }
80
81 public static SecretKey getSecretKey(final String password,
82 final String salt) {
83 try {
84 final PBEKeySpec pbeKeySpec = new PBEKeySpec(
85 password.toCharArray(), HexEncoder.decode(salt),
86 PBE_ITERATION_COUNT, 256);
87 final SecretKeyFactory factory = SecretKeyFactory.getInstance(
88 PBE_ALGORITHM, PROVIDER);
89 final SecretKey tmp = factory.generateSecret(pbeKeySpec);
90 final SecretKey secret = new SecretKeySpec(tmp.getEncoded(),
91 SECRET_KEY_ALGORITHM);
92 return secret;
93 } catch (Exception e) {
94 throw new RuntimeException("Unable to get secret key", e);
95 }
96 }
97
98 public static String getHash(final String password, final String salt) {
99 try {
100 final String input = password + salt;
101 final MessageDigest md = MessageDigest.getInstance(HASH_ALGORITHM,
102 PROVIDER);
103 final byte[] out = md.digest(input.getBytes("UTF-8"));
104 return HexEncoder.encode(out);
105 } catch (Exception e) {
106 throw new RuntimeException("Unable to get hash", e);
107 }
108 }
109
110 public static String generateSalt(final int length) {
111 try {
112 final SecureRandom random = SecureRandom
113 .getInstance(RANDOM_ALGORITHM);
114 final byte[] salt = new byte[length];
115 random.nextBytes(salt);
116 final String saltHex = HexEncoder.encode(salt);
117 return saltHex;
118 } catch (Exception e) {
119 throw new RuntimeException("Unable to generate salt", e);
120 }
121 }
122
123 private static byte[] generateIv() {
124 try {
125 final SecureRandom random = SecureRandom
126 .getInstance(RANDOM_ALGORITHM);
127 final byte[] iv = new byte[IV_LENGTH];
128 random.nextBytes(iv);
129 return iv;
130 } catch (Exception e) {
131 throw new RuntimeException("Unable to generate IV", e);
132 }
133 }
134
135 public static void encryptFile(final File input, final File output, String password) throws IOException {
136 InputStream inputStream = new FileInputStream(input);
137 OutputStream outputStream = new FileOutputStream(output);
138 encryptStream(password, inputStream, outputStream);
139 }
140
141 public static InputStream decryptFile(final File input, String password) throws IOException {
142 return decryptedStream(password, new FileInputStream(input));
143 }
144
145 public static void encryptStream(final String password,
146 final InputStream inputStream, final OutputStream outputStream)
147 throws IOException {
148 final OutputStream encryptedStream = encryptedStream(password,
149 outputStream);
150 IOUtils.copy(inputStream, encryptedStream);
151 }
152
153 public static OutputStream encryptedStream(final String password,
154 final OutputStream outputStream) throws IOException {
155
156 final byte[] iv = generateIv();
157
158 final IvParameterSpec ivspec = new IvParameterSpec(iv);
159
160 try {
161 final Cipher encryptionCipher = Cipher.getInstance(
162 CIPHER_ALGORITHM, PROVIDER);
163
164 final String passwordSalt = generateSalt(SALT_LENGTH);
165
166 final SecretKey secretKey = getSecretKey(password, passwordSalt);
167
168 encryptionCipher.init(Cipher.ENCRYPT_MODE, secretKey, ivspec);
169
170 outputStream.write(iv);
171 outputStream.write(HexEncoder.decode(passwordSalt));
172
173 final CipherOutputStream cos = new CipherOutputStream(outputStream,
174 encryptionCipher);
175
176 return cos;
177 } catch (Exception e) {
178 Timber.e(e, "Unable to encrypt stream");
179 throw new RuntimeException("Unable to encrypt stream", e);
180 }
181 }
182
183 public static InputStream decryptedStream(final String password,
184 final InputStream inputStream) throws IOException {
185
186 final byte[] iv = new byte[IV_LENGTH];
187 final int ivBytesRead = inputStream.read(iv);
188 if (ivBytesRead != IV_LENGTH) {
189 throw new RuntimeException("Can't read IV from stream");
190 }
191
192 final byte[] passwordSalt = new byte[SALT_LENGTH];
193 final int saltBytesRead = inputStream.read(passwordSalt);
194
195 if (saltBytesRead != SALT_LENGTH) {
196 throw new RuntimeException("Can't read salt from stream");
197 }
198
199 final IvParameterSpec ivspec = new IvParameterSpec(iv);
200
201 try {
202 final Cipher decryptionCipher = Cipher.getInstance(
203 CIPHER_ALGORITHM, PROVIDER);
204
205 final SecretKey secretKey = getSecretKey(password,
206 HexEncoder.encode(passwordSalt));
207
208 decryptionCipher.init(Cipher.DECRYPT_MODE, secretKey, ivspec);
209
210 final CipherInputStream cis = new CipherInputStream(inputStream,
211 decryptionCipher);
212
213 return cis;
214 } catch (Exception e) {
215 Timber.e(e, "Unable to decrypt stream");
216 throw new RuntimeException("Unable to decrypt stream", e);
217 }
218 }
219
220 public static InputStream decryptedStream(final String password,
221 final File file) throws IOException {
222 return decryptedStream(password, new FileInputStream(file));
223 }
224}