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   * http://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.zip;
20  
21  import java.util.Arrays;
22  import java.util.Collections;
23  import java.util.HashMap;
24  import java.util.Map;
25  import java.util.zip.ZipException;
26  
27  /**
28   * Base class for all PKWare strong crypto extra headers.
29   *
30   * <p>
31   * This base class acts as a marker so you know you can ignore all extra fields that extend this class if you are not interested in the meta data of PKWare
32   * strong encryption.
33   * </p>
34   *
35   * <b>Algorithm IDs</b> - integer identifier of the encryption algorithm from the following range
36   *
37   * <ul>
38   * <li>0x6601 - DES</li>
39   * <li>0x6602 - RC2 (version needed to extract &lt; 5.2)</li>
40   * <li>0x6603 - 3DES 168</li>
41   * <li>0x6609 - 3DES 112</li>
42   * <li>0x660E - AES 128</li>
43   * <li>0x660F - AES 192</li>
44   * <li>0x6610 - AES 256</li>
45   * <li>0x6702 - RC2 (version needed to extract &gt;= 5.2)</li>
46   * <li>0x6720 - Blowfish</li>
47   * <li>0x6721 - Twofish</li>
48   * <li>0x6801 - RC4</li>
49   * <li>0xFFFF - Unknown algorithm</li>
50   * </ul>
51   *
52   * <b>Hash Algorithms</b> - integer identifier of the hash algorithm from the following range
53   *
54   * <ul>
55   * <li>0x0000 - none</li>
56   * <li>0x0001 - CRC32</li>
57   * <li>0x8003 - MD5</li>
58   * <li>0x8004 - SHA1</li>
59   * <li>0x8007 - RIPEMD160</li>
60   * <li>0x800C - SHA256</li>
61   * <li>0x800D - SHA384</li>
62   * <li>0x800E - SHA512</li>
63   * </ul>
64   *
65   * @since 1.11
66   */
67  public abstract class PKWareExtraHeader implements ZipExtraField {
68  
69      /**
70       * Encryption algorithm.
71       *
72       * @since 1.11
73       */
74      public enum EncryptionAlgorithm {
75          DES(0x6601), RC2pre52(0x6602), TripleDES168(0x6603), TripleDES192(0x6609), AES128(0x660E), AES192(0x660F), AES256(0x6610), RC2(0x6702), RC4(0x6801),
76          UNKNOWN(0xFFFF);
77  
78          private static final Map<Integer, EncryptionAlgorithm> codeToEnum;
79  
80          static {
81              final Map<Integer, EncryptionAlgorithm> cte = new HashMap<>();
82              for (final EncryptionAlgorithm method : values()) {
83                  cte.put(method.getCode(), method);
84              }
85              codeToEnum = Collections.unmodifiableMap(cte);
86          }
87  
88          /**
89           * Returns the EncryptionAlgorithm for the given code or null if the method is not known.
90           *
91           * @param code the code of the algorithm
92           * @return the EncryptionAlgorithm for the given code or null if the method is not known
93           */
94          public static EncryptionAlgorithm getAlgorithmByCode(final int code) {
95              return codeToEnum.get(code);
96          }
97  
98          private final int code;
99  
100         /**
101          * private constructor for enum style class.
102          */
103         EncryptionAlgorithm(final int code) {
104             this.code = code;
105         }
106 
107         /**
108          * the algorithm id.
109          *
110          * @return the PKWare AlgorithmId
111          */
112         public int getCode() {
113             return code;
114         }
115     }
116 
117     /**
118      * Hash Algorithm
119      *
120      * @since 1.11
121      */
122     public enum HashAlgorithm {
123         NONE(0), CRC32(1), MD5(0x8003), SHA1(0x8004), RIPEND160(0x8007), SHA256(0x800C), SHA384(0x800D), SHA512(0x800E);
124 
125         private static final Map<Integer, HashAlgorithm> codeToEnum;
126 
127         static {
128             final Map<Integer, HashAlgorithm> cte = new HashMap<>();
129             for (final HashAlgorithm method : values()) {
130                 cte.put(method.getCode(), method);
131             }
132             codeToEnum = Collections.unmodifiableMap(cte);
133         }
134 
135         /**
136          * Returns the HashAlgorithm for the given code or null if the method is not known.
137          *
138          * @param code the code of the algorithm
139          * @return the HashAlgorithm for the given code or null if the method is not known
140          */
141         public static HashAlgorithm getAlgorithmByCode(final int code) {
142             return codeToEnum.get(code);
143         }
144 
145         private final int code;
146 
147         /**
148          * private constructor for enum style class.
149          */
150         HashAlgorithm(final int code) {
151             this.code = code;
152         }
153 
154         /**
155          * the hash algorithm ID.
156          *
157          * @return the PKWare hashAlg
158          */
159         public int getCode() {
160             return code;
161         }
162     }
163 
164     private final ZipShort headerId;
165 
166     /**
167      * Extra field data in local file data - without Header-ID or length specifier.
168      */
169     private byte[] localData;
170 
171     /**
172      * Extra field data in central directory - without Header-ID or length specifier.
173      */
174     private byte[] centralData;
175 
176     protected PKWareExtraHeader(final ZipShort headerId) {
177         this.headerId = headerId;
178     }
179 
180     protected final void assertMinimalLength(final int minimum, final int length) throws ZipException {
181         if (length < minimum) {
182             throw new ZipException(getClass().getName() + " is too short, only " + length + " bytes, expected at least " + minimum);
183         }
184     }
185 
186     /**
187      * Gets the central data.
188      *
189      * @return the central data if present, else return the local file data
190      */
191     @Override
192     public byte[] getCentralDirectoryData() {
193         if (centralData != null) {
194             return ZipUtil.copy(centralData);
195         }
196         return getLocalFileDataData();
197     }
198 
199     /**
200      * Gets the central data length. If there is no central data, get the local file data length.
201      *
202      * @return the central data length
203      */
204     @Override
205     public ZipShort getCentralDirectoryLength() {
206         if (centralData != null) {
207             return new ZipShort(centralData.length);
208         }
209         return getLocalFileDataLength();
210     }
211 
212     /**
213      * Gets the header id.
214      *
215      * @return the header id
216      */
217     @Override
218     public ZipShort getHeaderId() {
219         return headerId;
220     }
221 
222     /**
223      * Gets the local data.
224      *
225      * @return the local data
226      */
227     @Override
228     public byte[] getLocalFileDataData() {
229         return ZipUtil.copy(localData);
230     }
231 
232     /**
233      * Gets the length of the local data.
234      *
235      * @return the length of the local data
236      */
237     @Override
238     public ZipShort getLocalFileDataLength() {
239         return new ZipShort(localData != null ? localData.length : 0);
240     }
241 
242     /**
243      * @param data   the array of bytes.
244      * @param offset the source location in the data array.
245      * @param length the number of bytes to use in the data array.
246      * @see ZipExtraField#parseFromCentralDirectoryData(byte[], int, int)
247      */
248     @Override
249     public void parseFromCentralDirectoryData(final byte[] data, final int offset, final int length) throws ZipException {
250         final byte[] tmp = Arrays.copyOfRange(data, offset, offset + length);
251         setCentralDirectoryData(tmp);
252         if (localData == null) {
253             setLocalFileDataData(tmp);
254         }
255     }
256 
257     /**
258      * @param data   the array of bytes.
259      * @param offset the source location in the data array.
260      * @param length the number of bytes to use in the data array.
261      * @see ZipExtraField#parseFromLocalFileData(byte[], int, int)
262      */
263     @Override
264     public void parseFromLocalFileData(final byte[] data, final int offset, final int length) throws ZipException {
265         setLocalFileDataData(Arrays.copyOfRange(data, offset, offset + length));
266     }
267 
268     /**
269      * Sets the extra field data in central directory.
270      *
271      * @param data the data to use
272      */
273     public void setCentralDirectoryData(final byte[] data) {
274         centralData = ZipUtil.copy(data);
275     }
276 
277     /**
278      * Sets the extra field data in the local file data - without Header-ID or length specifier.
279      *
280      * @param data the field data to use
281      */
282     public void setLocalFileDataData(final byte[] data) {
283         localData = ZipUtil.copy(data);
284     }
285 }