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