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