    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(final ZipShort headerId) {
    081        this.headerId = headerId;
    082    }
    083
    084    /**
    085     * Get the header id.
    086     *
    087     * @return the header id
    088     */
    089    @Override
    090    public ZipShort getHeaderId() {
    091        return headerId;
    092    }
    093
    094    /**
    095     * Set the extra field data in the local file data - without Header-ID or
    096     * length specifier.
    097     *
    098     * @param data
    099     *            the field data to use
    100     */
    101    public void setLocalFileDataData(final byte[] data) {
    102        localData = ZipUtil.copy(data);
    103    }
    104
    105    /**
    106     * Get the length of the local data.
    107     *
    108     * @return the length of the local data
    109     */
    110    @Override
    111    public ZipShort getLocalFileDataLength() {
    112        return new ZipShort(localData != null ? localData.length : 0);
    113    }
    114
    115    /**
    116     * Get the local data.
    117     *
    118     * @return the local data
    119     */
    120    @Override
    121    public byte[] getLocalFileDataData() {
    122        return ZipUtil.copy(localData);
    123    }
    124
    125    /**
    126     * Set the extra field data in central directory.
    127     *
    128     * @param data
    129     *            the data to use
    130     */
    131    public void setCentralDirectoryData(final byte[] data) {
    132        centralData = ZipUtil.copy(data);
    133    }
    134
    135    /**
    136     * Get the central data length. If there is no central data, get the local
    137     * file data length.
    138     *
    139     * @return the central data length
    140     */
    141    @Override
    142    public ZipShort getCentralDirectoryLength() {
    143        if (centralData != null) {
    144            return new ZipShort(centralData.length);
    145        }
    146        return getLocalFileDataLength();
    147    }
    148
    149    /**
    150     * Get the central data.
    151     *
    152     * @return the central data if present, else return the local file data
    153     */
    154    @Override
    155    public byte[] getCentralDirectoryData() {
    156        if (centralData != null) {
    157            return ZipUtil.copy(centralData);
    158        }
    159        return getLocalFileDataData();
    160    }
    161
    162    /**
    163     * @param data
    164     *            the array of bytes.
    165     * @param offset
    166     *            the source location in the data array.
    167     * @param length
    168     *            the number of bytes to use in the data array.
    169     * @see ZipExtraField#parseFromLocalFileData(byte[], int, int)
    170     */
    171    @Override
    172    public void parseFromLocalFileData(final byte[] data, final int offset, final int length) {
    173        final byte[] tmp = new byte[length];
    174        System.arraycopy(data, offset, tmp, 0, length);
    175        setLocalFileDataData(tmp);
    176    }
    177
    178    /**
    179     * @param data
    180     *            the array of bytes.
    181     * @param offset
    182     *            the source location in the data array.
    183     * @param length
    184     *            the number of bytes to use in the data array.
    185     * @see ZipExtraField#parseFromCentralDirectoryData(byte[], int, int)
    186     */
    187    @Override
    188    public void parseFromCentralDirectoryData(final byte[] data, final int offset, final int length) {
    189        final byte[] tmp = new byte[length];
    190        System.arraycopy(data, offset, tmp, 0, length);
    191        setCentralDirectoryData(tmp);
    192        if (localData == null) {
    193            setLocalFileDataData(tmp);
    194        }
    195    }
    196
    197    /**
    198     * Encryption algorithm.
    199     *
    200     * @since 1.11
    201     */
    202    public enum EncryptionAlgorithm {
    203        DES(0x6601),
    204        RC2pre52(0x6602),
    205        TripleDES168(0x6603),
    206        TripleDES192(0x6609),
    207        AES128(0x660E),
    208        AES192(0x660F),
    209        AES256(0x6610),
    210        RC2(0x6702),
    211        RC4(0x6801),
    212        UNKNOWN(0xFFFF);
    213
    214        private final int code;
    215
    216        private static final Map<Integer, EncryptionAlgorithm> codeToEnum;
    217
    218        static {
    219            final Map<Integer, EncryptionAlgorithm> cte = new HashMap<>();
    220            for (final EncryptionAlgorithm method : values()) {
    221                cte.put(Integer.valueOf(method.getCode()), method);
    222            }
    223            codeToEnum = Collections.unmodifiableMap(cte);
    224        }
    225
    226        /**
    227         * private constructor for enum style class.
    228         */
    229        EncryptionAlgorithm(final int code) {
    230            this.code = code;
    231        }
    232
    233        /**
    234         * the algorithm id.
    235         *
    236         * @return the PKWare AlgorithmId
    237         */
    238        public int getCode() {
    239            return code;
    240        }
    241
    242        /**
    243         * Returns the EncryptionAlgorithm for the given code or null if the
    244         * method is not known.
    245         * @param code the code of the algorithm
    246         * @return the EncryptionAlgorithm for the given code or null
    247         * if the method is not known
    248         */
    249        public static EncryptionAlgorithm getAlgorithmByCode(final int code) {
    250            return codeToEnum.get(Integer.valueOf(code));
    251        }
    252    }
    253
    254    /**
    255     * Hash Algorithm
    256     *
    257     * @since 1.11
    258     */
    259    public enum HashAlgorithm {
    260        NONE(0),
    261        CRC32(1),
    262        MD5(0x8003),
    263        SHA1(0x8004),
    264        RIPEND160(0x8007),
    265        SHA256(0x800C),
    266        SHA384(0x800D),
    267        SHA512(0x800E);
    268
    269        private final int code;
    270
    271        private static final Map<Integer, HashAlgorithm> codeToEnum;
    272
    273        static {
    274            final Map<Integer, HashAlgorithm> cte = new HashMap<>();
    275            for (final HashAlgorithm method : values()) {
    276                cte.put(Integer.valueOf(method.getCode()), method);
    277            }
    278            codeToEnum = Collections.unmodifiableMap(cte);
    279        }
    280
    281        /**
    282         * private constructor for enum style class.
    283         */
    284        HashAlgorithm(final int code) {
    285            this.code = code;
    286        }
    287
    288        /**
    289         * the hash algorithm ID.
    290         *
    291         * @return the PKWare hashAlg
    292         */
    293        public int getCode() {
    294            return code;
    295        }
    296
    297        /**
    298         * Returns the HashAlgorithm for the given code or null if the method is
    299         * not known.
    300         * @param code the code of the algorithm
    301         * @return the HashAlgorithm for the given code or null
    302         * if the method is not known
    303         */
    304        public static HashAlgorithm getAlgorithmByCode(final int code) {
    305            return codeToEnum.get(Integer.valueOf(code));
    306        }
    307    }
    308}