Program: 6
Project: VUL4J
Buggy source:
//* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements.  See the NOTICE file * distributed with this work for additional information * regarding copyright ownership.  The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License.  You may obtain a copy of the License at * * http: * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied.  See the License for the * specific language governing permissions and limitations * under the License. *//package org.apache.commons.compress.archivers.zip;//** * Strong Encryption Header (0x0017). * * <p>Certificate-based encryption:<//p> * * <pre> * Value     Size     Description * -----     ----     ----------- * 0x0017    2 bytes  Tag for this "extra" block type * TSize     2 bytes  Size of data that follows * Format    2 bytes  Format definition for this record * AlgID     2 bytes  Encryption algorithm identifier * Bitlen    2 bytes  Bit length of encryption key (32-448 bits) * Flags     2 bytes  Processing flags * RCount    4 bytes  Number of recipients. * HashAlg   2 bytes  Hash algorithm identifier * HSize     2 bytes  Hash size * SRList    (var)    Simple list of recipients hashed public keys * * Flags -   This defines the processing flags. * <//pre> * *           <ul> *           <li>0x0007 - reserved for future use *           <li>0x000F - reserved for future use *           <li>0x0100 - Indicates non-OAEP key wrapping was used.  If this *                        this field is set, the version needed to extract must *                        be at least 61.  This means OAEP key wrapping is not *                        used when generating a Master Session Key using *                        ErdData. *           <li>0x4000 - ErdData must be decrypted using 3DES-168, otherwise use the *                        same algorithm used for encrypting the file contents. *           <li>0x8000 - reserved for future use *           <//ul> * * <pre> * RCount - This defines the number intended recipients whose *          public keys were used for encryption.  This identifies *          the number of elements in the SRList. * *          see also: reserved1 * * HashAlg - This defines the hash algorithm used to calculate *           the public key hash of each public key used *           for encryption. This field currently supports *           only the following value for SHA-1 * *           0x8004 - SHA1 * * HSize -   This defines the size of a hashed public key. * * SRList -  This is a variable length list of the hashed *           public keys for each intended recipient.  Each *           element in this list is HSize.  The total size of *           SRList is determined using RCount * HSize. * <//pre> * * <p>Password-based Extra Field 0x0017 in central header only.<//p> * * <pre> * Value     Size     Description * -----     ----     ----------- * 0x0017    2 bytes  Tag for this "extra" block type * TSize     2 bytes  Size of data that follows * Format    2 bytes  Format definition for this record * AlgID     2 bytes  Encryption algorithm identifier * Bitlen    2 bytes  Bit length of encryption key (32-448 bits) * Flags     2 bytes  Processing flags * (more?) * <//pre> * * <p><b>Format<//b> - the data format identifier for this record. The only value * allowed at this time is the integer value 2.<//p> * * <p>Password-based Extra Field 0x0017 preceding compressed file data.<//p> * * <pre> * Value     Size     Description * -----     ----     ----------- * 0x0017    2 bytes  Tag for this "extra" block type * IVSize    2 bytes  Size of initialization vector (IV) * IVData    IVSize   Initialization vector for this file * Size      4 bytes  Size of remaining decryption header data * Format    2 bytes  Format definition for this record * AlgID     2 bytes  Encryption algorithm identifier * Bitlen    2 bytes  Bit length of encryption key (32-448 bits) * Flags     2 bytes  Processing flags * ErdSize   2 bytes  Size of Encrypted Random Data * ErdData   ErdSize  Encrypted Random Data * Reserved1 4 bytes  Reserved certificate processing data * Reserved2 (var)    Reserved for certificate processing data * VSize     2 bytes  Size of password validation data * VData     VSize-4  Password validation data * VCRC32    4 bytes  Standard ZIP CRC32 of password validation data * * IVData - The size of the IV should match the algorithm block size. *          The IVData can be completely random data.  If the size of *          the randomly generated data does not match the block size *          it should be complemented with zero's or truncated as *          necessary.  If IVSize is 0,then IV = CRC32 + Uncompressed *          File Size (as a 64 bit little-endian, unsigned integer value). * * Format -  the data format identifier for this record.  The only *           value allowed at this time is the integer value 2. * * ErdData - Encrypted random data is used to store random data that *           is used to generate a file session key for encrypting *           each file.  SHA1 is used to calculate hash data used to *           derive keys.  File session keys are derived from a master *           session key generated from the user-supplied password. *           If the Flags field in the decryption header contains *           the value 0x4000, then the ErdData field must be *           decrypted using 3DES. If the value 0x4000 is not set, *           then the ErdData field must be decrypted using AlgId. * * Reserved1 - Reserved for certificate processing, if value is *           zero, then Reserved2 data is absent.  See the explanation *           under the Certificate Processing Method for details on *           this data structure. * * Reserved2 - If present, the size of the Reserved2 data structure *           is located by skipping the first 4 bytes of this field *           and using the next 2 bytes as the remaining size.  See *           the explanation under the Certificate Processing Method *           for details on this data structure. * * VSize - This size value will always include the 4 bytes of the *         VCRC32 data and will be greater than 4 bytes. * * VData - Random data for password validation.  This data is VSize *         in length and VSize must be a multiple of the encryption *         block size.  VCRC32 is a checksum value of VData. *         VData and VCRC32 are stored encrypted and start the *         stream of encrypted data for a file. * <//pre> * * <p>Reserved1 - Certificate Decryption Header Reserved1 Data:<//p> * * <pre> * Value     Size     Description * -----     ----     ----------- * RCount    4 bytes  Number of recipients. * <//pre> * * <p>RCount - This defines the number intended recipients whose public keys were * used for encryption. This defines the number of elements in the REList field * defined below.<//p> * * <p>Reserved2 - Certificate Decryption Header Reserved2 Data Structures:<//p> * * <pre> * Value     Size     Description * -----     ----     ----------- * HashAlg   2 bytes  Hash algorithm identifier * HSize     2 bytes  Hash size * REList    (var)    List of recipient data elements * * HashAlg - This defines the hash algorithm used to calculate *           the public key hash of each public key used *           for encryption. This field currently supports *           only the following value for SHA-1 * *               0x8004 - SHA1 * * HSize -   This defines the size of a hashed public key *           defined in REHData. * * REList -  This is a variable length of list of recipient data. *           Each element in this list consists of a Recipient *           Element data structure as follows: * <//pre> * * <p>Recipient Element (REList) Data Structure:<//p> * * <pre> * Value     Size     Description * -----     ----     ----------- * RESize    2 bytes  Size of REHData + REKData * REHData   HSize    Hash of recipients public key * REKData   (var)    Simple key blob * * * RESize -  This defines the size of an individual REList *           element.  This value is the combined size of the *           REHData field + REKData field.  REHData is defined by *           HSize.  REKData is variable and can be calculated *           for each REList element using RESize and HSize. * * REHData - Hashed public key for this recipient. * * REKData - Simple Key Blob.  The format of this data structure *           is identical to that defined in the Microsoft *           CryptoAPI and generated using the CryptExportKey() *           function.  The version of the Simple Key Blob *           supported at this time is 0x02 as defined by *           Microsoft. * *           For more details see https: * <//pre> * * <p><b>Flags<//b> - Processing flags needed for decryption<//p> * * <ul> * <li>0x0001 - Password is required to decrypt<//li> * <li>0x0002 - Certificates only<//li> * <li>0x0003 - Password or certificate required to decrypt<//li> * <li>0x0007 - reserved for future use * <li>0x000F - reserved for future use * <li>0x0100 - indicates non-OAEP key wrapping was used. If this field is set * the version needed to extract must be at least 61. This means OAEP key * wrapping is not used when generating a Master Session Key using ErdData. * <li>0x4000 - ErdData must be decrypted using 3DES-168, otherwise use the same * algorithm used for encrypting the file contents. * <li>0x8000 - reserved for future use. * <//ul> * * <p><b>See the section describing the Strong Encryption Specification for * details. Refer to the section in this document entitled * "Incorporating PKWARE Proprietary Technology into Your Product" for more * information.<//b><//p> * * @NotThreadSafe * @since 1.11 *//public class X0017_StrongEncryptionHeader extends PKWareExtraHeader {    public X0017_StrongEncryptionHeader() {        super(new ZipShort(0x0017));    }    private int format;     private EncryptionAlgorithm algId;    private int bitlen;     private int flags;     private long rcount;    private HashAlgorithm hashAlg;    private int hashSize;        private byte ivData[];    private byte erdData[];        private byte recipientKeyHash[];    private byte keyBlob[];        private byte vData[];    private byte vCRC32[];    //**     * Get record count.     * @return the record count     *//    public long getRecordCount() {        return rcount;    }    //**     * Get hash algorithm.     * @return the hash algorithm     *//    public HashAlgorithm getHashAlgorithm() {        return hashAlg;    }    //**     * Get encryption algorithm.     * @return the encryption algorithm     *//    public EncryptionAlgorithm getEncryptionAlgorithm() {        return algId;    }    //**     * Parse central directory format.     *     * @param data the buffer to read data from     * @param offset offset into buffer to read data     * @param length the length of data     *//    public void parseCentralDirectoryFormat(final byte[] data, final int offset, final int length) {        this.format = ZipShort.getValue(data, offset);        this.algId = EncryptionAlgorithm.getAlgorithmByCode(ZipShort.getValue(data, offset + 2));        this.bitlen = ZipShort.getValue(data, offset + 4);        this.flags = ZipShort.getValue(data, offset + 6);        this.rcount = ZipLong.getValue(data, offset + 8);        if (rcount > 0) {            this.hashAlg = HashAlgorithm.getAlgorithmByCode(ZipShort.getValue(data, offset + 12));            this.hashSize = ZipShort.getValue(data, offset + 14);                        <START_BUG> for (int i = 0; i < this.rcount; i++) { <END_BUG>                for (int j = 0; j < this.hashSize; j++) {                                    }            }        }    }    //**     * Parse file header format.     *     * <p>(Password only?)<//p>     *     * @param data the buffer to read data from     * @param offset offset into buffer to read data     * @param length the length of data     *//    public void parseFileFormat(final byte[] data, final int offset, final int length) {        final int ivSize = ZipShort.getValue(data, offset);        this.ivData = new byte[ivSize];        System.arraycopy(data, offset + 4, this.ivData, 0, ivSize);        this.format = ZipShort.getValue(data, offset + ivSize + 6);        this.algId = EncryptionAlgorithm.getAlgorithmByCode(ZipShort.getValue(data, offset + ivSize + 8));        this.bitlen = ZipShort.getValue(data, offset + ivSize + 10);        this.flags = ZipShort.getValue(data, offset + ivSize + 12);        final int erdSize = ZipShort.getValue(data, offset + ivSize + 14);        this.erdData = new byte[erdSize];        System.arraycopy(data, offset + ivSize + 16, this.erdData, 0, erdSize);        this.rcount = ZipLong.getValue(data, offset + ivSize + 16 + erdSize);        System.out.println("rcount: " + rcount);        if (rcount == 0) {            final int vSize = ZipShort.getValue(data, offset + ivSize + 20 + erdSize);            this.vData = new byte[vSize - 4];            this.vCRC32 = new byte[4];            System.arraycopy(data, offset + ivSize + 22 + erdSize , this.vData, 0, vSize - 4);            System.arraycopy(data, offset + ivSize + 22 + erdSize + vSize - 4, vCRC32, 0, 4);        } else {            this.hashAlg = HashAlgorithm.getAlgorithmByCode(ZipShort.getValue(data, offset + ivSize + 20 + erdSize));            this.hashSize = ZipShort.getValue(data, offset + ivSize + 22 + erdSize);            final int resize = ZipShort.getValue(data, offset + ivSize + 24 + erdSize);            this.recipientKeyHash = new byte[this.hashSize];            this.keyBlob = new byte[resize - this.hashSize];            System.arraycopy(data, offset + ivSize + 24 + erdSize, this.recipientKeyHash, 0, this.hashSize);            System.arraycopy(data, offset + ivSize + 24 + erdSize + this.hashSize, this.keyBlob, 0, resize - this.hashSize);            final int vSize = ZipShort.getValue(data, offset + ivSize + 26 + erdSize + resize);            this.vData = new byte[vSize - 4];            this.vCRC32 = new byte[4];            System.arraycopy(data, offset + ivSize + 22 + erdSize + resize, this.vData, 0, vSize - 4);            System.arraycopy(data, offset + ivSize + 22 + erdSize + resize + vSize - 4, vCRC32, 0, 4);        }            }    @Override    public void parseFromLocalFileData(final byte[] data, final int offset, final int length) {        super.parseFromLocalFileData(data, offset, length);        parseFileFormat(data, offset, length);    }    @Override    public void parseFromCentralDirectoryData(final byte[] data, final int offset, final int length) {        super.parseFromCentralDirectoryData(data, offset, length);        parseCentralDirectoryFormat(data, offset, length);    }}


Fixed version (ground truth):
for (long i = 0; i < this.rcount; i++) {