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 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>This base class acts as a marker so you know you can ignore all 031 * extra fields that extend this class if you are not interested in 032 * the meta data of PKWare strong encryption.</p> 033 * 034 * <b>Algorithm IDs</b> - integer identifier of the encryption algorithm from 035 * 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 * <b>Hash Algorithms</b> - integer identifier of the hash algorithm from the 053 * following range 054 * 055 * <ul> 056 * <li>0x0000 - none</li> 057 * <li>0x0001 - CRC32</li> 058 * <li>0x8003 - MD5</li> 059 * <li>0x8004 - SHA1</li> 060 * <li>0x8007 - RIPEMD160</li> 061 * <li>0x800C - SHA256</li> 062 * <li>0x800D - SHA384</li> 063 * <li>0x800E - SHA512</li> 064 * </ul> 065 * 066 * @since 1.11 067 */ 068public abstract class PKWareExtraHeader implements ZipExtraField { 069 070 /** 071 * Encryption algorithm. 072 * 073 * @since 1.11 074 */ 075 public enum EncryptionAlgorithm { 076 DES(0x6601), 077 RC2pre52(0x6602), 078 TripleDES168(0x6603), 079 TripleDES192(0x6609), 080 AES128(0x660E), 081 AES192(0x660F), 082 AES256(0x6610), 083 RC2(0x6702), 084 RC4(0x6801), 085 UNKNOWN(0xFFFF); 086 087 private static final Map<Integer, EncryptionAlgorithm> codeToEnum; 088 089 static { 090 final Map<Integer, EncryptionAlgorithm> cte = new HashMap<>(); 091 for (final EncryptionAlgorithm method : values()) { 092 cte.put(method.getCode(), method); 093 } 094 codeToEnum = Collections.unmodifiableMap(cte); 095 } 096 097 /** 098 * Returns the EncryptionAlgorithm for the given code or null if the 099 * method is not known. 100 * @param code the code of the algorithm 101 * @return the EncryptionAlgorithm for the given code or null 102 * if the method is not known 103 */ 104 public static EncryptionAlgorithm getAlgorithmByCode(final int code) { 105 return codeToEnum.get(code); 106 } 107 108 private final int code; 109 110 /** 111 * private constructor for enum style class. 112 */ 113 EncryptionAlgorithm(final int code) { 114 this.code = code; 115 } 116 117 /** 118 * the algorithm id. 119 * 120 * @return the PKWare AlgorithmId 121 */ 122 public int getCode() { 123 return code; 124 } 125 } 126 127 /** 128 * Hash Algorithm 129 * 130 * @since 1.11 131 */ 132 public enum HashAlgorithm { 133 NONE(0), 134 CRC32(1), 135 MD5(0x8003), 136 SHA1(0x8004), 137 RIPEND160(0x8007), 138 SHA256(0x800C), 139 SHA384(0x800D), 140 SHA512(0x800E); 141 142 private static final Map<Integer, HashAlgorithm> codeToEnum; 143 144 static { 145 final Map<Integer, HashAlgorithm> cte = new HashMap<>(); 146 for (final HashAlgorithm method : values()) { 147 cte.put(method.getCode(), method); 148 } 149 codeToEnum = Collections.unmodifiableMap(cte); 150 } 151 152 /** 153 * Returns the HashAlgorithm for the given code or null if the method is 154 * not known. 155 * @param code the code of the algorithm 156 * @return the HashAlgorithm for the given code or null 157 * if the method is not known 158 */ 159 public static HashAlgorithm getAlgorithmByCode(final int code) { 160 return codeToEnum.get(code); 161 } 162 163 private final int code; 164 165 /** 166 * private constructor for enum style class. 167 */ 168 HashAlgorithm(final int code) { 169 this.code = code; 170 } 171 172 /** 173 * the hash algorithm ID. 174 * 175 * @return the PKWare hashAlg 176 */ 177 public int getCode() { 178 return code; 179 } 180 } 181 private final ZipShort headerId; 182 183 /** 184 * Extra field data in local file data - without Header-ID or length 185 * specifier. 186 */ 187 private byte[] localData; 188 189 /** 190 * Extra field data in central directory - without Header-ID or length 191 * specifier. 192 */ 193 private byte[] centralData; 194 195 protected PKWareExtraHeader(final ZipShort headerId) { 196 this.headerId = headerId; 197 } 198 199 protected final void assertMinimalLength(final int minimum, final int length) 200 throws ZipException { 201 if (length < minimum) { 202 throw new ZipException(getClass().getName() + " is too short, only " 203 + length + " bytes, expected at least " + minimum); 204 } 205 } 206 207 /** 208 * Get the central data. 209 * 210 * @return the central data if present, else return the local file data 211 */ 212 @Override 213 public byte[] getCentralDirectoryData() { 214 if (centralData != null) { 215 return ZipUtil.copy(centralData); 216 } 217 return getLocalFileDataData(); 218 } 219 220 /** 221 * Get the central data length. If there is no central data, get the local 222 * file data length. 223 * 224 * @return the central data length 225 */ 226 @Override 227 public ZipShort getCentralDirectoryLength() { 228 if (centralData != null) { 229 return new ZipShort(centralData.length); 230 } 231 return getLocalFileDataLength(); 232 } 233 234 /** 235 * Get the header id. 236 * 237 * @return the header id 238 */ 239 @Override 240 public ZipShort getHeaderId() { 241 return headerId; 242 } 243 244 /** 245 * Get the local data. 246 * 247 * @return the local data 248 */ 249 @Override 250 public byte[] getLocalFileDataData() { 251 return ZipUtil.copy(localData); 252 } 253 254 /** 255 * Get the length of the local data. 256 * 257 * @return the length of the local data 258 */ 259 @Override 260 public ZipShort getLocalFileDataLength() { 261 return new ZipShort(localData != null ? localData.length : 0); 262 } 263 264 /** 265 * @param data 266 * the array of bytes. 267 * @param offset 268 * the source location in the data array. 269 * @param length 270 * the number of bytes to use in the data array. 271 * @see ZipExtraField#parseFromCentralDirectoryData(byte[], int, int) 272 */ 273 @Override 274 public void parseFromCentralDirectoryData(final byte[] data, final int offset, final int length) 275 throws ZipException { 276 final byte[] tmp = Arrays.copyOfRange(data, offset, offset + length); 277 setCentralDirectoryData(tmp); 278 if (localData == null) { 279 setLocalFileDataData(tmp); 280 } 281 } 282 283 /** 284 * @param data 285 * the array of bytes. 286 * @param offset 287 * the source location in the data array. 288 * @param length 289 * the number of bytes to use in the data array. 290 * @see ZipExtraField#parseFromLocalFileData(byte[], int, int) 291 */ 292 @Override 293 public void parseFromLocalFileData(final byte[] data, final int offset, final int length) 294 throws ZipException { 295 setLocalFileDataData(Arrays.copyOfRange(data, offset, offset + length)); 296 } 297 298 /** 299 * Set the extra field data in central directory. 300 * 301 * @param data 302 * the data to use 303 */ 304 public void setCentralDirectoryData(final byte[] data) { 305 centralData = ZipUtil.copy(data); 306 } 307 308 /** 309 * Set the extra field data in the local file data - without Header-ID or 310 * length specifier. 311 * 312 * @param data 313 * the field data to use 314 */ 315 public void setLocalFileDataData(final byte[] data) { 316 localData = ZipUtil.copy(data); 317 } 318}