View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   https://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.commons.compress.archivers.sevenz;
20  
21  import java.security.GeneralSecurityException;
22  import java.security.NoSuchAlgorithmException;
23  import java.security.SecureRandom;
24  
25  import javax.crypto.Cipher;
26  import javax.crypto.SecretKey;
27  import javax.crypto.spec.IvParameterSpec;
28  import javax.crypto.spec.SecretKeySpec;
29  
30  /**
31   * Options for {@link SevenZMethod#AES256SHA256} encoder
32   *
33   * @since 1.23
34   * @see AES256SHA256Decoder
35   */
36  final class AES256Options {
37  
38      private static final byte[] EMPTY_BYTE_ARRAY = {};
39  
40      static final String ALGORITHM = "AES";
41  
42      static final String TRANSFORMATION = "AES/CBC/NoPadding";
43  
44      static SecretKeySpec newSecretKeySpec(final byte[] bytes) {
45          return new SecretKeySpec(bytes, ALGORITHM);
46      }
47  
48      private static byte[] randomBytes(final int size) {
49          final byte[] bytes = new byte[size];
50          try {
51              SecureRandom.getInstanceStrong().nextBytes(bytes);
52          } catch (final NoSuchAlgorithmException e) {
53              throw new IllegalStateException("No strong secure random available to generate strong AES key", e);
54          }
55          return bytes;
56      }
57  
58      private final byte[] salt;
59      private final byte[] iv;
60  
61      private final int numCyclesPower;
62  
63      private final Cipher cipher;
64  
65      /**
66       * @param password password used for encryption
67       */
68      AES256Options(final char[] password) {
69          this(password, EMPTY_BYTE_ARRAY, randomBytes(16), 19);
70      }
71  
72      /**
73       * @param password       password used for encryption
74       * @param salt           for password hash salting (enforce password security)
75       * @param iv             Initialization Vector (IV) used by cipher algorithm
76       * @param numCyclesPower another password security enforcer parameter that controls the cycles of password hashing. More the this number is high, more
77       *                       security you'll have but also high CPU usage
78       */
79      AES256Options(final char[] password, final byte[] salt, final byte[] iv, final int numCyclesPower) {
80          this.salt = salt;
81          this.iv = iv;
82          this.numCyclesPower = numCyclesPower;
83  
84          // NOTE: for security purposes, password is wrapped in a Cipher as soon as possible to not stay in memory
85          final byte[] aesKeyBytes = AES256SHA256Decoder.sha256Password(password, numCyclesPower, salt);
86          final SecretKey aesKey = newSecretKeySpec(aesKeyBytes);
87  
88          try {
89              cipher = Cipher.getInstance(TRANSFORMATION);
90              cipher.init(Cipher.ENCRYPT_MODE, aesKey, new IvParameterSpec(iv));
91          } catch (final GeneralSecurityException generalSecurityException) {
92              throw new IllegalStateException("Encryption error (do you have the JCE Unlimited Strength Jurisdiction Policy Files installed?)",
93                      generalSecurityException);
94          }
95      }
96  
97      Cipher getCipher() {
98          return cipher;
99      }
100 
101     byte[] getIv() {
102         return iv;
103     }
104 
105     int getNumCyclesPower() {
106         return numCyclesPower;
107     }
108 
109     byte[] getSalt() {
110         return salt;
111     }
112 }