001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 * http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing,
013 * software distributed under the License is distributed on an
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 * KIND, either express or implied.  See the License for the
016 * specific language governing permissions and limitations
017 * under the License.
018 */
019package org.apache.commons.compress.archivers.zip;
020
021import java.util.Collections;
022import java.util.HashMap;
023import java.util.Map;
024
025/**
026 * Base class for all PKWare strong crypto extra headers.
027 *
028 * <p>This base class acts as a marker so you know you can ignore all
029 * extra fields that extend this class if you are not interested in
030 * the meta data of PKWare strong encryption.</p>
031 *
032 * <b>Algorithm IDs</b> - integer identifier of the encryption algorithm from
033 * the following range
034 *
035 * <ul>
036 * <li>0x6601 - DES</li>
037 * <li>0x6602 - RC2 (version needed to extract &lt; 5.2)</li>
038 * <li>0x6603 - 3DES 168</li>
039 * <li>0x6609 - 3DES 112</li>
040 * <li>0x660E - AES 128</li>
041 * <li>0x660F - AES 192</li>
042 * <li>0x6610 - AES 256</li>
043 * <li>0x6702 - RC2 (version needed to extract &gt;= 5.2)</li>
044 * <li>0x6720 - Blowfish</li>
045 * <li>0x6721 - Twofish</li>
046 * <li>0x6801 - RC4</li>
047 * <li>0xFFFF - Unknown algorithm</li>
048 * </ul>
049 *
050 * <b>Hash Algorithms</b> - integer identifier of the hash algorithm from the
051 * following range
052 *
053 * <ul>
054 * <li>0x0000 - none</li>
055 * <li>0x0001 - CRC32</li>
056 * <li>0x8003 - MD5</li>
057 * <li>0x8004 - SHA1</li>
058 * <li>0x8007 - RIPEMD160</li>
059 * <li>0x800C - SHA256</li>
060 * <li>0x800D - SHA384</li>
061 * <li>0x800E - SHA512</li>
062 * </ul>
063 *
064 * @since 1.11
065 */
066public abstract class PKWareExtraHeader implements ZipExtraField {
067
068    private final ZipShort headerId;
069    /**
070     * Extra field data in local file data - without Header-ID or length
071     * specifier.
072     */
073    private byte[] localData;
074    /**
075     * Extra field data in central directory - without Header-ID or length
076     * specifier.
077     */
078    private byte[] centralData;
079
080    protected PKWareExtraHeader(ZipShort headerId) {
081        this.headerId = headerId;
082    }
083    
084    /**
085     * Get the header id.
086     *
087     * @return the header id
088     */
089    public ZipShort getHeaderId() {
090        return headerId;
091    }
092
093    /**
094     * Set the extra field data in the local file data - without Header-ID or
095     * length specifier.
096     *
097     * @param data
098     *            the field data to use
099     */
100    public void setLocalFileDataData(byte[] data) {
101        localData = ZipUtil.copy(data);
102    }
103
104    /**
105     * Get the length of the local data.
106     *
107     * @return the length of the local data
108     */
109    public ZipShort getLocalFileDataLength() {
110        return new ZipShort(localData != null ? localData.length : 0);
111    }
112
113    /**
114     * Get the local data.
115     *
116     * @return the local data
117     */
118    public byte[] getLocalFileDataData() {
119        return ZipUtil.copy(localData);
120    }
121
122    /**
123     * Set the extra field data in central directory.
124     *
125     * @param data
126     *            the data to use
127     */
128    public void setCentralDirectoryData(byte[] data) {
129        centralData = ZipUtil.copy(data);
130    }
131
132    /**
133     * Get the central data length. If there is no central data, get the local
134     * file data length.
135     *
136     * @return the central data length
137     */
138    public ZipShort getCentralDirectoryLength() {
139        if (centralData != null) {
140            return new ZipShort(centralData.length);
141        }
142        return getLocalFileDataLength();
143    }
144
145    /**
146     * Get the central data.
147     *
148     * @return the central data if present, else return the local file data
149     */
150    public byte[] getCentralDirectoryData() {
151        if (centralData != null) {
152            return ZipUtil.copy(centralData);
153        }
154        return getLocalFileDataData();
155    }
156
157    /**
158     * @param data
159     *            the array of bytes.
160     * @param offset
161     *            the source location in the data array.
162     * @param length
163     *            the number of bytes to use in the data array.
164     * @see ZipExtraField#parseFromLocalFileData(byte[], int, int)
165     */
166    public void parseFromLocalFileData(byte[] data, int offset, int length) {
167        byte[] tmp = new byte[length];
168        System.arraycopy(data, offset, tmp, 0, length);
169        setLocalFileDataData(tmp);
170    }
171
172    /**
173     * @param data
174     *            the array of bytes.
175     * @param offset
176     *            the source location in the data array.
177     * @param length
178     *            the number of bytes to use in the data array.
179     * @see ZipExtraField#parseFromCentralDirectoryData(byte[], int, int)
180     */
181    public void parseFromCentralDirectoryData(byte[] data, int offset, int length) {
182        byte[] tmp = new byte[length];
183        System.arraycopy(data, offset, tmp, 0, length);
184        setCentralDirectoryData(tmp);
185        if (localData == null) {
186            setLocalFileDataData(tmp);
187        }
188    }
189    
190    /**
191     * Encryption algorithm.
192     *
193     * @since 1.11
194     */
195    public enum EncryptionAlgorithm {
196        DES(0x6601),
197        RC2pre52(0x6602),
198        TripleDES168(0x6603),
199        TripleDES192(0x6609),
200        AES128(0x660E),
201        AES192(0x660F),
202        AES256(0x6610),
203        RC2(0x6702),
204        RC4(0x6801),
205        UNKNOWN(0xFFFF);
206
207        private final int code;
208
209        private static final Map<Integer, EncryptionAlgorithm> codeToEnum;
210
211        static {
212            Map<Integer, EncryptionAlgorithm> cte = new HashMap<Integer, EncryptionAlgorithm>();
213            for (EncryptionAlgorithm method : values()) {
214                cte.put(Integer.valueOf(method.getCode()), method);
215            }
216            codeToEnum = Collections.unmodifiableMap(cte);
217        }
218
219        /**
220         * private constructor for enum style class.
221         */
222        EncryptionAlgorithm(int code) {
223            this.code = code;
224        }
225
226        /**
227         * the algorithm id.
228         *
229         * @return the PKWare AlgorithmId
230         */
231        public int getCode() {
232            return code;
233        }
234
235        /**
236         * Returns the EncryptionAlgorithm for the given code or null if the
237         * method is not known.
238         * @param code the code of the algorithm
239         * @return the EncryptionAlgorithm for the given code or null
240         * if the method is not known
241         */
242        public static EncryptionAlgorithm getAlgorithmByCode(int code) {
243            return codeToEnum.get(Integer.valueOf(code));
244        }
245    }
246
247    /**
248     * Hash Algorithm
249     *
250     * @since 1.11
251     */
252    public enum HashAlgorithm {
253        NONE(0),
254        CRC32(1),
255        MD5(0x8003),
256        SHA1(0x8004),
257        RIPEND160(0x8007),
258        SHA256(0x800C),
259        SHA384(0x800D),
260        SHA512(0x800E);
261
262        private final int code;
263
264        private static final Map<Integer, HashAlgorithm> codeToEnum;
265
266        static {
267            Map<Integer, HashAlgorithm> cte = new HashMap<Integer, HashAlgorithm>();
268            for (HashAlgorithm method : values()) {
269                cte.put(Integer.valueOf(method.getCode()), method);
270            }
271            codeToEnum = Collections.unmodifiableMap(cte);
272        }
273
274        /**
275         * private constructor for enum style class.
276         */
277        HashAlgorithm(int code) {
278            this.code = code;
279        }
280
281        /**
282         * the hash algorithm ID.
283         *
284         * @return the PKWare hashAlg
285         */
286        public int getCode() {
287            return code;
288        }
289
290        /**
291         * Returns the HashAlgorithm for the given code or null if the method is
292         * not known.
293         * @param code the code of the algorithm
294         * @return the HashAlgorithm for the given code or null
295         * if the method is not known
296         */
297        public static HashAlgorithm getAlgorithmByCode(int code) {
298            return codeToEnum.get(Integer.valueOf(code));
299        }
300    }
301}