PKWareExtraHeader.java

  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. import java.util.Arrays;
  21. import java.util.Collections;
  22. import java.util.HashMap;
  23. import java.util.Map;
  24. import java.util.zip.ZipException;

  25. /**
  26.  * Base class for all PKWare strong crypto extra headers.
  27.  *
  28.  * <p>
  29.  * 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
  30.  * strong encryption.
  31.  * </p>
  32.  *
  33.  * <b>Algorithm IDs</b> - integer identifier of the encryption algorithm from the following range
  34.  *
  35.  * <ul>
  36.  * <li>0x6601 - DES</li>
  37.  * <li>0x6602 - RC2 (version needed to extract &lt; 5.2)</li>
  38.  * <li>0x6603 - 3DES 168</li>
  39.  * <li>0x6609 - 3DES 112</li>
  40.  * <li>0x660E - AES 128</li>
  41.  * <li>0x660F - AES 192</li>
  42.  * <li>0x6610 - AES 256</li>
  43.  * <li>0x6702 - RC2 (version needed to extract &gt;= 5.2)</li>
  44.  * <li>0x6720 - Blowfish</li>
  45.  * <li>0x6721 - Twofish</li>
  46.  * <li>0x6801 - RC4</li>
  47.  * <li>0xFFFF - Unknown algorithm</li>
  48.  * </ul>
  49.  *
  50.  * <b>Hash Algorithms</b> - integer identifier of the hash algorithm from the following range
  51.  *
  52.  * <ul>
  53.  * <li>0x0000 - none</li>
  54.  * <li>0x0001 - CRC32</li>
  55.  * <li>0x8003 - MD5</li>
  56.  * <li>0x8004 - SHA1</li>
  57.  * <li>0x8007 - RIPEMD160</li>
  58.  * <li>0x800C - SHA256</li>
  59.  * <li>0x800D - SHA384</li>
  60.  * <li>0x800E - SHA512</li>
  61.  * </ul>
  62.  *
  63.  * @since 1.11
  64.  */
  65. public abstract class PKWareExtraHeader implements ZipExtraField {

  66.     /**
  67.      * Encryption algorithm.
  68.      *
  69.      * @since 1.11
  70.      */
  71.     public enum EncryptionAlgorithm {
  72.         DES(0x6601), RC2pre52(0x6602), TripleDES168(0x6603), TripleDES192(0x6609), AES128(0x660E), AES192(0x660F), AES256(0x6610), RC2(0x6702), RC4(0x6801),
  73.         UNKNOWN(0xFFFF);

  74.         private static final Map<Integer, EncryptionAlgorithm> codeToEnum;

  75.         static {
  76.             final Map<Integer, EncryptionAlgorithm> cte = new HashMap<>();
  77.             for (final EncryptionAlgorithm method : values()) {
  78.                 cte.put(method.getCode(), method);
  79.             }
  80.             codeToEnum = Collections.unmodifiableMap(cte);
  81.         }

  82.         /**
  83.          * Returns the EncryptionAlgorithm for the given code or null if the method is not known.
  84.          *
  85.          * @param code the code of the algorithm
  86.          * @return the EncryptionAlgorithm for the given code or null if the method is not known
  87.          */
  88.         public static EncryptionAlgorithm getAlgorithmByCode(final int code) {
  89.             return codeToEnum.get(code);
  90.         }

  91.         private final int code;

  92.         /**
  93.          * private constructor for enum style class.
  94.          */
  95.         EncryptionAlgorithm(final int code) {
  96.             this.code = code;
  97.         }

  98.         /**
  99.          * the algorithm id.
  100.          *
  101.          * @return the PKWare AlgorithmId
  102.          */
  103.         public int getCode() {
  104.             return code;
  105.         }
  106.     }

  107.     /**
  108.      * Hash Algorithm
  109.      *
  110.      * @since 1.11
  111.      */
  112.     public enum HashAlgorithm {
  113.         NONE(0), CRC32(1), MD5(0x8003), SHA1(0x8004), RIPEND160(0x8007), SHA256(0x800C), SHA384(0x800D), SHA512(0x800E);

  114.         private static final Map<Integer, HashAlgorithm> codeToEnum;

  115.         static {
  116.             final Map<Integer, HashAlgorithm> cte = new HashMap<>();
  117.             for (final HashAlgorithm method : values()) {
  118.                 cte.put(method.getCode(), method);
  119.             }
  120.             codeToEnum = Collections.unmodifiableMap(cte);
  121.         }

  122.         /**
  123.          * Returns the HashAlgorithm for the given code or null if the method is not known.
  124.          *
  125.          * @param code the code of the algorithm
  126.          * @return the HashAlgorithm for the given code or null if the method is not known
  127.          */
  128.         public static HashAlgorithm getAlgorithmByCode(final int code) {
  129.             return codeToEnum.get(code);
  130.         }

  131.         private final int code;

  132.         /**
  133.          * private constructor for enum style class.
  134.          */
  135.         HashAlgorithm(final int code) {
  136.             this.code = code;
  137.         }

  138.         /**
  139.          * the hash algorithm ID.
  140.          *
  141.          * @return the PKWare hashAlg
  142.          */
  143.         public int getCode() {
  144.             return code;
  145.         }
  146.     }

  147.     private final ZipShort headerId;

  148.     /**
  149.      * Extra field data in local file data - without Header-ID or length specifier.
  150.      */
  151.     private byte[] localData;

  152.     /**
  153.      * Extra field data in central directory - without Header-ID or length specifier.
  154.      */
  155.     private byte[] centralData;

  156.     protected PKWareExtraHeader(final ZipShort headerId) {
  157.         this.headerId = headerId;
  158.     }

  159.     protected final void assertMinimalLength(final int minimum, final int length) throws ZipException {
  160.         if (length < minimum) {
  161.             throw new ZipException(getClass().getName() + " is too short, only " + length + " bytes, expected at least " + minimum);
  162.         }
  163.     }

  164.     /**
  165.      * Gets the central data.
  166.      *
  167.      * @return the central data if present, else return the local file data
  168.      */
  169.     @Override
  170.     public byte[] getCentralDirectoryData() {
  171.         if (centralData != null) {
  172.             return ZipUtil.copy(centralData);
  173.         }
  174.         return getLocalFileDataData();
  175.     }

  176.     /**
  177.      * Gets the central data length. If there is no central data, get the local file data length.
  178.      *
  179.      * @return the central data length
  180.      */
  181.     @Override
  182.     public ZipShort getCentralDirectoryLength() {
  183.         if (centralData != null) {
  184.             return new ZipShort(centralData.length);
  185.         }
  186.         return getLocalFileDataLength();
  187.     }

  188.     /**
  189.      * Gets the header id.
  190.      *
  191.      * @return the header id
  192.      */
  193.     @Override
  194.     public ZipShort getHeaderId() {
  195.         return headerId;
  196.     }

  197.     /**
  198.      * Gets the local data.
  199.      *
  200.      * @return the local data
  201.      */
  202.     @Override
  203.     public byte[] getLocalFileDataData() {
  204.         return ZipUtil.copy(localData);
  205.     }

  206.     /**
  207.      * Gets the length of the local data.
  208.      *
  209.      * @return the length of the local data
  210.      */
  211.     @Override
  212.     public ZipShort getLocalFileDataLength() {
  213.         return new ZipShort(localData != null ? localData.length : 0);
  214.     }

  215.     /**
  216.      * @param data   the array of bytes.
  217.      * @param offset the source location in the data array.
  218.      * @param length the number of bytes to use in the data array.
  219.      * @see ZipExtraField#parseFromCentralDirectoryData(byte[], int, int)
  220.      */
  221.     @Override
  222.     public void parseFromCentralDirectoryData(final byte[] data, final int offset, final int length) throws ZipException {
  223.         final byte[] tmp = Arrays.copyOfRange(data, offset, offset + length);
  224.         setCentralDirectoryData(tmp);
  225.         if (localData == null) {
  226.             setLocalFileDataData(tmp);
  227.         }
  228.     }

  229.     /**
  230.      * @param data   the array of bytes.
  231.      * @param offset the source location in the data array.
  232.      * @param length the number of bytes to use in the data array.
  233.      * @see ZipExtraField#parseFromLocalFileData(byte[], int, int)
  234.      */
  235.     @Override
  236.     public void parseFromLocalFileData(final byte[] data, final int offset, final int length) throws ZipException {
  237.         setLocalFileDataData(Arrays.copyOfRange(data, offset, offset + length));
  238.     }

  239.     /**
  240.      * Sets the extra field data in central directory.
  241.      *
  242.      * @param data the data to use
  243.      */
  244.     public void setCentralDirectoryData(final byte[] data) {
  245.         centralData = ZipUtil.copy(data);
  246.     }

  247.     /**
  248.      * Sets the extra field data in the local file data - without Header-ID or length specifier.
  249.      *
  250.      * @param data the field data to use
  251.      */
  252.     public void setLocalFileDataData(final byte[] data) {
  253.         localData = ZipUtil.copy(data);
  254.     }
  255. }