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 021/** 022 * Strong Encryption Header (0x0017). 023 * 024 * <p>Certificate-based encryption:</p> 025 * 026 * <pre> 027 * Value Size Description 028 * ----- ---- ----------- 029 * 0x0017 2 bytes Tag for this "extra" block type 030 * TSize 2 bytes Size of data that follows 031 * Format 2 bytes Format definition for this record 032 * AlgID 2 bytes Encryption algorithm identifier 033 * Bitlen 2 bytes Bit length of encryption key (32-448 bits) 034 * Flags 2 bytes Processing flags 035 * RCount 4 bytes Number of recipients. 036 * HashAlg 2 bytes Hash algorithm identifier 037 * HSize 2 bytes Hash size 038 * SRList (var) Simple list of recipients hashed public keys 039 * 040 * Flags - This defines the processing flags. 041 * </pre> 042 * 043 * <ul> 044 * <li>0x0007 - reserved for future use 045 * <li>0x000F - reserved for future use 046 * <li>0x0100 - Indicates non-OAEP key wrapping was used. If this 047 * this field is set, the version needed to extract must 048 * be at least 61. This means OAEP key wrapping is not 049 * used when generating a Master Session Key using 050 * ErdData. 051 * <li>0x4000 - ErdData must be decrypted using 3DES-168, otherwise use the 052 * same algorithm used for encrypting the file contents. 053 * <li>0x8000 - reserved for future use 054 * </ul> 055 * 056 * <pre> 057 * RCount - This defines the number intended recipients whose 058 * public keys were used for encryption. This identifies 059 * the number of elements in the SRList. 060 * 061 * see also: reserved1 062 * 063 * HashAlg - This defines the hash algorithm used to calculate 064 * the public key hash of each public key used 065 * for encryption. This field currently supports 066 * only the following value for SHA-1 067 * 068 * 0x8004 - SHA1 069 * 070 * HSize - This defines the size of a hashed public key. 071 * 072 * SRList - This is a variable length list of the hashed 073 * public keys for each intended recipient. Each 074 * element in this list is HSize. The total size of 075 * SRList is determined using RCount * HSize. 076 * </pre> 077 * 078 * <p>Password-based Extra Field 0x0017 in central header only.</p> 079 * 080 * <pre> 081 * Value Size Description 082 * ----- ---- ----------- 083 * 0x0017 2 bytes Tag for this "extra" block type 084 * TSize 2 bytes Size of data that follows 085 * Format 2 bytes Format definition for this record 086 * AlgID 2 bytes Encryption algorithm identifier 087 * Bitlen 2 bytes Bit length of encryption key (32-448 bits) 088 * Flags 2 bytes Processing flags 089 * (more?) 090 * </pre> 091 * 092 * <p><b>Format</b> - the data format identifier for this record. The only value 093 * allowed at this time is the integer value 2.</p> 094 * 095 * <p>Password-based Extra Field 0x0017 preceding compressed file data.</p> 096 * 097 * <pre> 098 * Value Size Description 099 * ----- ---- ----------- 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 */ 245public 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 (int 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}