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