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 * https://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.Arrays; 022import java.util.Collections; 023import java.util.HashMap; 024import java.util.Map; 025import java.util.zip.ZipException; 026 027/** 028 * Base class for all PKWare strong crypto extra headers. 029 * 030 * <p> 031 * 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 032 * strong encryption. 033 * </p> 034 * 035 * <strong>Algorithm IDs</strong> - integer identifier of the encryption algorithm from the following range 036 * 037 * <ul> 038 * <li>0x6601 - DES</li> 039 * <li>0x6602 - RC2 (version needed to extract < 5.2)</li> 040 * <li>0x6603 - 3DES 168</li> 041 * <li>0x6609 - 3DES 112</li> 042 * <li>0x660E - AES 128</li> 043 * <li>0x660F - AES 192</li> 044 * <li>0x6610 - AES 256</li> 045 * <li>0x6702 - RC2 (version needed to extract >= 5.2)</li> 046 * <li>0x6720 - Blowfish</li> 047 * <li>0x6721 - Twofish</li> 048 * <li>0x6801 - RC4</li> 049 * <li>0xFFFF - Unknown algorithm</li> 050 * </ul> 051 * 052 * <strong>Hash Algorithms</strong> - integer identifier of the hash algorithm from the following range 053 * 054 * <ul> 055 * <li>0x0000 - none</li> 056 * <li>0x0001 - CRC32</li> 057 * <li>0x8003 - MD5</li> 058 * <li>0x8004 - SHA1</li> 059 * <li>0x8007 - RIPEMD160</li> 060 * <li>0x800C - SHA256</li> 061 * <li>0x800D - SHA384</li> 062 * <li>0x800E - SHA512</li> 063 * </ul> 064 * 065 * @since 1.11 066 */ 067public abstract class PKWareExtraHeader implements ZipExtraField { 068 069 /** 070 * Enumerates encryption algorithm. 071 * 072 * @since 1.11 073 */ 074 public enum EncryptionAlgorithm { 075 076 /** 077 * DES with code 0x6601. 078 */ 079 DES(0x6601), 080 081 /** 082 * RC2pre52 with code 0x6602. 083 */ 084 RC2pre52(0x6602), 085 086 /** 087 * TripleDES168 with code 0x6603. 088 */ 089 TripleDES168(0x6603), 090 091 /** 092 * TripleDES192 with code 0x6609. 093 */ 094 TripleDES192(0x6609), 095 096 /** 097 * AES128 with code 0x660E. 098 */ 099 AES128(0x660E), 100 101 /** 102 * AES192 with code 0x660F. 103 */ 104 AES192(0x660F), 105 106 /** 107 * AES256 with code 0x6610. 108 */ 109 AES256(0x6610), 110 111 /** 112 * RC2 with code 0x6702. 113 */ 114 RC2(0x6702), 115 116 /** 117 * RC4 with code 0x6801. 118 */ 119 RC4(0x6801), 120 121 /** 122 * UNKNOWN with code 0xFFFF. 123 */ 124 UNKNOWN(0xFFFF); 125 126 private static final Map<Integer, EncryptionAlgorithm> codeToEnum; 127 128 static { 129 final Map<Integer, EncryptionAlgorithm> cte = new HashMap<>(); 130 for (final EncryptionAlgorithm method : values()) { 131 cte.put(method.getCode(), method); 132 } 133 codeToEnum = Collections.unmodifiableMap(cte); 134 } 135 136 /** 137 * Returns the EncryptionAlgorithm for the given code or null if the method is not known. 138 * 139 * @param code the code of the algorithm 140 * @return the EncryptionAlgorithm for the given code or null if the method is not known 141 */ 142 public static EncryptionAlgorithm getAlgorithmByCode(final int code) { 143 return codeToEnum.get(code); 144 } 145 146 private final int code; 147 148 /** 149 * Constructs a new instance. 150 */ 151 EncryptionAlgorithm(final int code) { 152 this.code = code; 153 } 154 155 /** 156 * Gets the algorithm ID. 157 * 158 * @return the PKWare AlgorithmId 159 */ 160 public int getCode() { 161 return code; 162 } 163 } 164 165 /** 166 * Enumerates hash Algorithm 167 * 168 * @since 1.11 169 */ 170 public enum HashAlgorithm { 171 172 /** 173 * NONE with code 0. 174 */ 175 NONE(0), 176 177 /** 178 * CRC32 with code 1. 179 */ 180 CRC32(1), 181 182 /** 183 * MD5 with code 0x8003. 184 */ 185 MD5(0x8003), 186 187 /** 188 * SHA1 with code 0x8004. 189 */ 190 SHA1(0x8004), 191 192 /** 193 * RIPEND160 with code 0x8007. 194 */ 195 RIPEND160(0x8007), 196 197 /** 198 * SHA256 with code 0x800C. 199 */ 200 SHA256(0x800C), 201 202 /** 203 * SHA384 with code 0x800D. 204 */ 205 SHA384(0x800D), 206 207 /** 208 * SHA512 with code 0x800E. 209 */ 210 SHA512(0x800E); 211 212 private static final Map<Integer, HashAlgorithm> codeToEnum; 213 214 static { 215 final Map<Integer, HashAlgorithm> cte = new HashMap<>(); 216 for (final HashAlgorithm method : values()) { 217 cte.put(method.getCode(), method); 218 } 219 codeToEnum = Collections.unmodifiableMap(cte); 220 } 221 222 /** 223 * Returns the HashAlgorithm for the given code or null if the method is not known. 224 * 225 * @param code the code of the algorithm 226 * @return the HashAlgorithm for the given code or null if the method is not known 227 */ 228 public static HashAlgorithm getAlgorithmByCode(final int code) { 229 return codeToEnum.get(code); 230 } 231 232 private final int code; 233 234 /** 235 * Constructs a new instance. 236 */ 237 HashAlgorithm(final int code) { 238 this.code = code; 239 } 240 241 /** 242 * Gets the hash algorithm ID. 243 * 244 * @return the PKWare hashAlg 245 */ 246 public int getCode() { 247 return code; 248 } 249 } 250 251 private final ZipShort headerId; 252 253 /** 254 * Extra field data in local file data - without Header-ID or length specifier. 255 */ 256 private byte[] localData; 257 258 /** 259 * Extra field data in central directory - without Header-ID or length specifier. 260 */ 261 private byte[] centralData; 262 263 /** 264 * Constructs a new instance. 265 * 266 * @param headerId The header ID. 267 */ 268 protected PKWareExtraHeader(final ZipShort headerId) { 269 this.headerId = headerId; 270 } 271 272 /** 273 * Asserts the given length is greater or equal to the given minimum. 274 * 275 * @param minimum the minimum. 276 * @param length the length. 277 * @throws ZipException Thrown if the length is less than the minimum. 278 */ 279 protected final void assertMinimalLength(final int minimum, final int length) throws ZipException { 280 if (length < minimum) { 281 throw new ZipException(getClass().getName() + " is too short, only " + length + " bytes, expected at least " + minimum); 282 } 283 } 284 285 /** 286 * Gets the central data. 287 * 288 * @return the central data if present, else return the local file data 289 */ 290 @Override 291 public byte[] getCentralDirectoryData() { 292 if (centralData != null) { 293 return ZipUtil.copy(centralData); 294 } 295 return getLocalFileDataData(); 296 } 297 298 /** 299 * Gets the central data length. If there is no central data, get the local file data length. 300 * 301 * @return the central data length 302 */ 303 @Override 304 public ZipShort getCentralDirectoryLength() { 305 if (centralData != null) { 306 return new ZipShort(centralData.length); 307 } 308 return getLocalFileDataLength(); 309 } 310 311 /** 312 * Gets the header id. 313 * 314 * @return the header id 315 */ 316 @Override 317 public ZipShort getHeaderId() { 318 return headerId; 319 } 320 321 /** 322 * Gets the local data. 323 * 324 * @return the local data 325 */ 326 @Override 327 public byte[] getLocalFileDataData() { 328 return ZipUtil.copy(localData); 329 } 330 331 /** 332 * Gets the length of the local data. 333 * 334 * @return the length of the local data. 335 */ 336 @Override 337 public ZipShort getLocalFileDataLength() { 338 return ZipShort.lengthOf(localData); 339 } 340 341 /** 342 * @param data the array of bytes. 343 * @param offset the source location in the data array. 344 * @param length the number of bytes to use in the data array. 345 * @see ZipExtraField#parseFromCentralDirectoryData(byte[], int, int) 346 */ 347 @Override 348 public void parseFromCentralDirectoryData(final byte[] data, final int offset, final int length) throws ZipException { 349 final byte[] tmp = Arrays.copyOfRange(data, offset, offset + length); 350 setCentralDirectoryData(tmp); 351 if (localData == null) { 352 setLocalFileDataData(tmp); 353 } 354 } 355 356 /** 357 * @param data the array of bytes. 358 * @param offset the source location in the data array. 359 * @param length the number of bytes to use in the data array. 360 * @see ZipExtraField#parseFromLocalFileData(byte[], int, int) 361 */ 362 @Override 363 public void parseFromLocalFileData(final byte[] data, final int offset, final int length) throws ZipException { 364 setLocalFileDataData(Arrays.copyOfRange(data, offset, offset + length)); 365 } 366 367 /** 368 * Sets the extra field data in central directory. 369 * 370 * @param data the data to use 371 */ 372 public void setCentralDirectoryData(final byte[] data) { 373 centralData = ZipUtil.copy(data); 374 } 375 376 /** 377 * Sets the extra field data in the local file data - without Header-ID or length specifier. 378 * 379 * @param data the field data to use 380 */ 381 public void setLocalFileDataData(final byte[] data) { 382 localData = ZipUtil.copy(data); 383 } 384}