· 6 years ago · Aug 13, 2019, 12:36 PM
1public final class AesEncoder implements Encoder {
2
3 private final Cipher cipher;
4 private final Mac mac;
5 private final byte[] salt;
6 private final byte[] derivedPasswordVerifier;
7
8 // AesStrength is an Enum with AES strength constants like salt or mac length
9 public static AesEncoder create(AesStrength strength, char[] password) throws Exception {
10 KeySpec spec = new PBEKeySpec(password, salt, 1000, strength.getSize());
11 SecretKey secretKey = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1").generateSecret(spec);
12 byte[] iv = { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
13
14 Cipher cipher = Cipher.getInstance("AES/CTR/NoPadding");
15 cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(secretKey.getEncoded(), "AES"), new IvParameterSpec(iv));
16
17 Mac mac = Mac.getInstance("HmacSHA1");
18 mac.init(new SecretKeySpec(macKey, "HmacSHA1"));
19 return new AesEncoder(cipher, mac, salt, derivedPasswordVerifier);
20 }
21
22 private static byte[] generateSalt(AesStrength strength) {
23 SecureRandom random = new SecureRandom();
24 byte[] buf = new byte[strength.getSaltLength()];
25 random.nextBytes(buf);
26 return buf;
27 }
28
29 @Override
30 public void encrypt(byte[] buf, int offs, int len) {
31 try {
32 // buf is INPUT DATA WITH LENGTH 16 bytes (alwasy, because AES requires it)
33 cipher.update(buf, offs, len, buf);
34 mac.update(buf, offs, len);
35 } catch(Exception e) {
36 throw new Zip4jException(e);
37 }
38 }
39
40 // ...
41
42}
43
44private static void increment(byte[] b) {
45 int n = b.length - 1;
46 while ((n >= 0) && (++b[n] == 0)) {
47 n--;
48 }
49}