Home | History | Annotate | Download | only in zip
      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 /**
     22  * Strong Encryption Header (0x0017).
     23  *
     24  * <p>Certificate-based encryption:</p>
     25  *
     26  * <pre>
     27  * Value     Size     Description
     28  * -----     ----     -----------
     29  * 0x0017    2 bytes  Tag for this "extra" block type
     30  * TSize     2 bytes  Size of data that follows
     31  * Format    2 bytes  Format definition for this record
     32  * AlgID     2 bytes  Encryption algorithm identifier
     33  * Bitlen    2 bytes  Bit length of encryption key (32-448 bits)
     34  * Flags     2 bytes  Processing flags
     35  * RCount    4 bytes  Number of recipients.
     36  * HashAlg   2 bytes  Hash algorithm identifier
     37  * HSize     2 bytes  Hash size
     38  * SRList    (var)    Simple list of recipients hashed public keys
     39  *
     40  * Flags -   This defines the processing flags.
     41  * </pre>
     42  *
     43  *           <ul>
     44  *           <li>0x0007 - reserved for future use
     45  *           <li>0x000F - reserved for future use
     46  *           <li>0x0100 - Indicates non-OAEP key wrapping was used.  If this
     47  *                        this field is set, the version needed to extract must
     48  *                        be at least 61.  This means OAEP key wrapping is not
     49  *                        used when generating a Master Session Key using
     50  *                        ErdData.
     51  *           <li>0x4000 - ErdData must be decrypted using 3DES-168, otherwise use the
     52  *                        same algorithm used for encrypting the file contents.
     53  *           <li>0x8000 - reserved for future use
     54  *           </ul>
     55  *
     56  * <pre>
     57  * RCount - This defines the number intended recipients whose
     58  *          public keys were used for encryption.  This identifies
     59  *          the number of elements in the SRList.
     60  *
     61  *          see also: reserved1
     62  *
     63  * HashAlg - This defines the hash algorithm used to calculate
     64  *           the public key hash of each public key used
     65  *           for encryption. This field currently supports
     66  *           only the following value for SHA-1
     67  *
     68  *           0x8004 - SHA1
     69  *
     70  * HSize -   This defines the size of a hashed public key.
     71  *
     72  * SRList -  This is a variable length list of the hashed
     73  *           public keys for each intended recipient.  Each
     74  *           element in this list is HSize.  The total size of
     75  *           SRList is determined using RCount * HSize.
     76  * </pre>
     77  *
     78  * <p>Password-based Extra Field 0x0017 in central header only.</p>
     79  *
     80  * <pre>
     81  * Value     Size     Description
     82  * -----     ----     -----------
     83  * 0x0017    2 bytes  Tag for this "extra" block type
     84  * TSize     2 bytes  Size of data that follows
     85  * Format    2 bytes  Format definition for this record
     86  * AlgID     2 bytes  Encryption algorithm identifier
     87  * Bitlen    2 bytes  Bit length of encryption key (32-448 bits)
     88  * Flags     2 bytes  Processing flags
     89  * (more?)
     90  * </pre>
     91  *
     92  * <p><b>Format</b> - the data format identifier for this record. The only value
     93  * allowed at this time is the integer value 2.</p>
     94  *
     95  * <p>Password-based Extra Field 0x0017 preceding compressed file data.</p>
     96  *
     97  * <pre>
     98  * Value     Size     Description
     99  * -----     ----     -----------
    100  * 0x0017    2 bytes  Tag for this "extra" block type
    101  * IVSize    2 bytes  Size of initialization vector (IV)
    102  * IVData    IVSize   Initialization vector for this file
    103  * Size      4 bytes  Size of remaining decryption header data
    104  * Format    2 bytes  Format definition for this record
    105  * AlgID     2 bytes  Encryption algorithm identifier
    106  * Bitlen    2 bytes  Bit length of encryption key (32-448 bits)
    107  * Flags     2 bytes  Processing flags
    108  * ErdSize   2 bytes  Size of Encrypted Random Data
    109  * ErdData   ErdSize  Encrypted Random Data
    110  * Reserved1 4 bytes  Reserved certificate processing data
    111  * Reserved2 (var)    Reserved for certificate processing data
    112  * VSize     2 bytes  Size of password validation data
    113  * VData     VSize-4  Password validation data
    114  * VCRC32    4 bytes  Standard ZIP CRC32 of password validation data
    115  *
    116  * IVData - The size of the IV should match the algorithm block size.
    117  *          The IVData can be completely random data.  If the size of
    118  *          the randomly generated data does not match the block size
    119  *          it should be complemented with zero's or truncated as
    120  *          necessary.  If IVSize is 0,then IV = CRC32 + Uncompressed
    121  *          File Size (as a 64 bit little-endian, unsigned integer value).
    122  *
    123  * Format -  the data format identifier for this record.  The only
    124  *           value allowed at this time is the integer value 2.
    125  *
    126  * ErdData - Encrypted random data is used to store random data that
    127  *           is used to generate a file session key for encrypting
    128  *           each file.  SHA1 is used to calculate hash data used to
    129  *           derive keys.  File session keys are derived from a master
    130  *           session key generated from the user-supplied password.
    131  *           If the Flags field in the decryption header contains
    132  *           the value 0x4000, then the ErdData field must be
    133  *           decrypted using 3DES. If the value 0x4000 is not set,
    134  *           then the ErdData field must be decrypted using AlgId.
    135  *
    136  * Reserved1 - Reserved for certificate processing, if value is
    137  *           zero, then Reserved2 data is absent.  See the explanation
    138  *           under the Certificate Processing Method for details on
    139  *           this data structure.
    140  *
    141  * Reserved2 - If present, the size of the Reserved2 data structure
    142  *           is located by skipping the first 4 bytes of this field
    143  *           and using the next 2 bytes as the remaining size.  See
    144  *           the explanation under the Certificate Processing Method
    145  *           for details on this data structure.
    146  *
    147  * VSize - This size value will always include the 4 bytes of the
    148  *         VCRC32 data and will be greater than 4 bytes.
    149  *
    150  * VData - Random data for password validation.  This data is VSize
    151  *         in length and VSize must be a multiple of the encryption
    152  *         block size.  VCRC32 is a checksum value of VData.
    153  *         VData and VCRC32 are stored encrypted and start the
    154  *         stream of encrypted data for a file.
    155  * </pre>
    156  *
    157  * <p>Reserved1 - Certificate Decryption Header Reserved1 Data:</p>
    158  *
    159  * <pre>
    160  * Value     Size     Description
    161  * -----     ----     -----------
    162  * RCount    4 bytes  Number of recipients.
    163  * </pre>
    164  *
    165  * <p>RCount - This defines the number intended recipients whose public keys were
    166  * used for encryption. This defines the number of elements in the REList field
    167  * defined below.</p>
    168  *
    169  * <p>Reserved2 - Certificate Decryption Header Reserved2 Data Structures:</p>
    170  *
    171  * <pre>
    172  * Value     Size     Description
    173  * -----     ----     -----------
    174  * HashAlg   2 bytes  Hash algorithm identifier
    175  * HSize     2 bytes  Hash size
    176  * REList    (var)    List of recipient data elements
    177  *
    178  * HashAlg - This defines the hash algorithm used to calculate
    179  *           the public key hash of each public key used
    180  *           for encryption. This field currently supports
    181  *           only the following value for SHA-1
    182  *
    183  *               0x8004 - SHA1
    184  *
    185  * HSize -   This defines the size of a hashed public key
    186  *           defined in REHData.
    187  *
    188  * REList -  This is a variable length of list of recipient data.
    189  *           Each element in this list consists of a Recipient
    190  *           Element data structure as follows:
    191  * </pre>
    192  *
    193  * <p>Recipient Element (REList) Data Structure:</p>
    194  *
    195  * <pre>
    196  * Value     Size     Description
    197  * -----     ----     -----------
    198  * RESize    2 bytes  Size of REHData + REKData
    199  * REHData   HSize    Hash of recipients public key
    200  * REKData   (var)    Simple key blob
    201  *
    202  *
    203  * RESize -  This defines the size of an individual REList
    204  *           element.  This value is the combined size of the
    205  *           REHData field + REKData field.  REHData is defined by
    206  *           HSize.  REKData is variable and can be calculated
    207  *           for each REList element using RESize and HSize.
    208  *
    209  * REHData - Hashed public key for this recipient.
    210  *
    211  * REKData - Simple Key Blob.  The format of this data structure
    212  *           is identical to that defined in the Microsoft
    213  *           CryptoAPI and generated using the CryptExportKey()
    214  *           function.  The version of the Simple Key Blob
    215  *           supported at this time is 0x02 as defined by
    216  *           Microsoft.
    217  *
    218  *           For more details see https://msdn.microsoft.com/en-us/library/aa920051.aspx
    219  * </pre>
    220  *
    221  * <p><b>Flags</b> - Processing flags needed for decryption</p>
    222  *
    223  * <ul>
    224  * <li>0x0001 - Password is required to decrypt</li>
    225  * <li>0x0002 - Certificates only</li>
    226  * <li>0x0003 - Password or certificate required to decrypt</li>
    227  * <li>0x0007 - reserved for future use
    228  * <li>0x000F - reserved for future use
    229  * <li>0x0100 - indicates non-OAEP key wrapping was used. If this field is set
    230  * the version needed to extract must be at least 61. This means OAEP key
    231  * wrapping is not used when generating a Master Session Key using ErdData.
    232  * <li>0x4000 - ErdData must be decrypted using 3DES-168, otherwise use the same
    233  * algorithm used for encrypting the file contents.
    234  * <li>0x8000 - reserved for future use.
    235  * </ul>
    236  *
    237  * <p><b>See the section describing the Strong Encryption Specification for
    238  * details. Refer to the section in this document entitled
    239  * "Incorporating PKWARE Proprietary Technology into Your Product" for more
    240  * information.</b></p>
    241  *
    242  * @NotThreadSafe
    243  * @since 1.11
    244  */
    245 public class X0017_StrongEncryptionHeader extends PKWareExtraHeader {
    246 
    247     public X0017_StrongEncryptionHeader() {
    248         super(new ZipShort(0x0017));
    249     }
    250 
    251     private int format; // TODO written but not read
    252     private EncryptionAlgorithm algId;
    253     private int bitlen; // TODO written but not read
    254     private int flags; // TODO written but not read
    255     private long rcount;
    256     private HashAlgorithm hashAlg;
    257     private int hashSize;
    258 
    259     // encryption data
    260     private byte ivData[];
    261     private byte erdData[];
    262 
    263     // encryption key
    264     private byte recipientKeyHash[];
    265     private byte keyBlob[];
    266 
    267     // password verification data
    268     private byte vData[];
    269     private byte vCRC32[];
    270 
    271     /**
    272      * Get record count.
    273      * @return the record count
    274      */
    275     public long getRecordCount() {
    276         return rcount;
    277     }
    278 
    279     /**
    280      * Get hash algorithm.
    281      * @return the hash algorithm
    282      */
    283     public HashAlgorithm getHashAlgorithm() {
    284         return hashAlg;
    285     }
    286 
    287     /**
    288      * Get encryption algorithm.
    289      * @return the encryption algorithm
    290      */
    291     public EncryptionAlgorithm getEncryptionAlgorithm() {
    292         return algId;
    293     }
    294 
    295     /**
    296      * Parse central directory format.
    297      *
    298      * @param data the buffer to read data from
    299      * @param offset offset into buffer to read data
    300      * @param length the length of data
    301      */
    302     public void parseCentralDirectoryFormat(final byte[] data, final int offset, final int length) {
    303         this.format = ZipShort.getValue(data, offset);
    304         this.algId = EncryptionAlgorithm.getAlgorithmByCode(ZipShort.getValue(data, offset + 2));
    305         this.bitlen = ZipShort.getValue(data, offset + 4);
    306         this.flags = ZipShort.getValue(data, offset + 6);
    307         this.rcount = ZipLong.getValue(data, offset + 8);
    308 
    309         if (rcount > 0) {
    310             this.hashAlg = HashAlgorithm.getAlgorithmByCode(ZipShort.getValue(data, offset + 12));
    311             this.hashSize = ZipShort.getValue(data, offset + 14);
    312             // srlist... hashed public keys
    313             for (long i = 0; i < this.rcount; i++) {
    314                 for (int j = 0; j < this.hashSize; j++) {
    315                     //  ZipUtil.signedByteToUnsignedInt(data[offset + 16 + (i * this.hashSize) + j]));
    316                 }
    317             }
    318         }
    319     }
    320 
    321     /**
    322      * Parse file header format.
    323      *
    324      * <p>(Password only?)</p>
    325      *
    326      * @param data the buffer to read data from
    327      * @param offset offset into buffer to read data
    328      * @param length the length of data
    329      */
    330     public void parseFileFormat(final byte[] data, final int offset, final int length) {
    331         final int ivSize = ZipShort.getValue(data, offset);
    332         this.ivData = new byte[ivSize];
    333         System.arraycopy(data, offset + 4, this.ivData, 0, ivSize);
    334 
    335         this.format = ZipShort.getValue(data, offset + ivSize + 6);
    336         this.algId = EncryptionAlgorithm.getAlgorithmByCode(ZipShort.getValue(data, offset + ivSize + 8));
    337         this.bitlen = ZipShort.getValue(data, offset + ivSize + 10);
    338         this.flags = ZipShort.getValue(data, offset + ivSize + 12);
    339 
    340         final int erdSize = ZipShort.getValue(data, offset + ivSize + 14);
    341         this.erdData = new byte[erdSize];
    342         System.arraycopy(data, offset + ivSize + 16, this.erdData, 0, erdSize);
    343 
    344         this.rcount = ZipLong.getValue(data, offset + ivSize + 16 + erdSize);
    345         System.out.println("rcount: " + rcount);
    346         if (rcount == 0) {
    347             final int vSize = ZipShort.getValue(data, offset + ivSize + 20 + erdSize);
    348             this.vData = new byte[vSize - 4];
    349             this.vCRC32 = new byte[4];
    350             System.arraycopy(data, offset + ivSize + 22 + erdSize , this.vData, 0, vSize - 4);
    351             System.arraycopy(data, offset + ivSize + 22 + erdSize + vSize - 4, vCRC32, 0, 4);
    352         } else {
    353             this.hashAlg = HashAlgorithm.getAlgorithmByCode(ZipShort.getValue(data, offset + ivSize + 20 + erdSize));
    354             this.hashSize = ZipShort.getValue(data, offset + ivSize + 22 + erdSize);
    355             final int resize = ZipShort.getValue(data, offset + ivSize + 24 + erdSize);
    356             this.recipientKeyHash = new byte[this.hashSize];
    357             this.keyBlob = new byte[resize - this.hashSize];
    358             System.arraycopy(data, offset + ivSize + 24 + erdSize, this.recipientKeyHash, 0, this.hashSize);
    359             System.arraycopy(data, offset + ivSize + 24 + erdSize + this.hashSize, this.keyBlob, 0, resize - this.hashSize);
    360 
    361             final int vSize = ZipShort.getValue(data, offset + ivSize + 26 + erdSize + resize);
    362             this.vData = new byte[vSize - 4];
    363             this.vCRC32 = new byte[4];
    364             System.arraycopy(data, offset + ivSize + 22 + erdSize + resize, this.vData, 0, vSize - 4);
    365             System.arraycopy(data, offset + ivSize + 22 + erdSize + resize + vSize - 4, vCRC32, 0, 4);
    366         }
    367 
    368         // validate values?
    369     }
    370 
    371     @Override
    372     public void parseFromLocalFileData(final byte[] data, final int offset, final int length) {
    373         super.parseFromLocalFileData(data, offset, length);
    374         parseFileFormat(data, offset, length);
    375     }
    376 
    377     @Override
    378     public void parseFromCentralDirectoryData(final byte[] data, final int offset, final int length) {
    379         super.parseFromCentralDirectoryData(data, offset, length);
    380         parseCentralDirectoryFormat(data, offset, length);
    381     }
    382 }
    383