You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by bo...@apache.org on 2015/12/13 17:38:41 UTC
[2/7] commons-compress git commit: Added headers to recognize PKWARE
crypto headers.
http://git-wip-us.apache.org/repos/asf/commons-compress/blob/a433f625/src/main/java/org/apache/commons/compress/archivers/zip/PKWareExtraHeader.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/compress/archivers/zip/PKWareExtraHeader.java b/src/main/java/org/apache/commons/compress/archivers/zip/PKWareExtraHeader.java
new file mode 100644
index 0000000..fbd1c09
--- /dev/null
+++ b/src/main/java/org/apache/commons/compress/archivers/zip/PKWareExtraHeader.java
@@ -0,0 +1,166 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.commons.compress.archivers.zip;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.zip.ZipEntry;
+
+/**
+ * Base class for all PKWare strong crypto extra headers.
+ *
+ * <b>Algorithm IDs</b> - integer identifier of the encryption algorithm from
+ * the following range
+ *
+ * <ul>
+ * <li>0x6601 - DES</li>
+ * <li>0x6602 - RC2 (version needed to extract < 5.2)</li>
+ * <li>0x6603 - 3DES 168</li>
+ * <li>0x6609 - 3DES 112</li>
+ * <li>0x660E - AES 128</li>
+ * <li>0x660F - AES 192</li>
+ * <li>0x6610 - AES 256</li>
+ * <li>0x6702 - RC2 (version needed to extract >= 5.2)</li>
+ * <li>0x6720 - Blowfish</li>
+ * <li>0x6721 - Twofish</li>
+ * <li>0x6801 - RC4</li>
+ * <li>0xFFFF - Unknown algorithm</li>
+ * </ul>
+ *
+ * <b>Hash Algorithms</b> - integer identifier of the hash algorithm from the
+ * following range
+ *
+ * <ul>
+ * <li>0x0000 - none</li>
+ * <li>0x0001 - CRC32</li>
+ * <li>0x8003 - MD5</li>
+ * <li>0x8004 - SHA1</li>
+ * <li>0x8007 - RIPEMD160</li>
+ * <li>0x800C - SHA256</li>
+ * <li>0x800D - SHA384</li>
+ * <li>0x800E - SHA512</li>
+ * </ul>
+ *
+ * TODO: define enums for crypto and hash algorithms.
+ */
+public abstract class PKWareExtraHeader implements ZipExtraField {
+
+ /**
+ * Encryption algorithm.
+ */
+ public enum EncryptionAlgorithm {
+ DES(0x6601),
+ RC2pre52(0x6602),
+ TripleDES168(0x6603),
+ TripleDES192(0x6609),
+ AES128(0x660E),
+ AES192(0x660F),
+ AES256(0x6610),
+ RC2(0x6702),
+ RC4(0x6801),
+ UNKNOWN(0xFFFF);
+
+ private final int code;
+
+ private static final Map<Integer, EncryptionAlgorithm> codeToEnum;
+
+ static {
+ Map<Integer, EncryptionAlgorithm> cte = new HashMap<Integer, EncryptionAlgorithm>();
+ for (EncryptionAlgorithm method : values()) {
+ cte.put(Integer.valueOf(method.getCode()), method);
+ }
+ codeToEnum = Collections.unmodifiableMap(cte);
+ }
+
+ /**
+ * private constructor for enum style class.
+ */
+ EncryptionAlgorithm(int code) {
+ this.code = code;
+ }
+
+ /**
+ * the algorithm id.
+ *
+ * @return the PKWare AlgorithmId
+ */
+ public int getCode() {
+ return code;
+ }
+
+ /**
+ * returns the EncryptionAlgorithm for the given code or null if the
+ * method is not known.
+ */
+ public static EncryptionAlgorithm getAlgorithmByCode(int code) {
+ return codeToEnum.get(Integer.valueOf(code));
+ }
+ }
+
+ /**
+ * Hash Algorithm
+ */
+ public enum HashAlgorithm {
+ NONE(0),
+ CRC32(1),
+ MD5(0x8003),
+ SHA1(0x8004),
+ RIPEND160(0x8007),
+ SHA256(0x800C),
+ SHA384(0x800D),
+ SHA512(0x800E);
+
+ private final int code;
+
+ private static final Map<Integer, HashAlgorithm> codeToEnum;
+
+ static {
+ Map<Integer, HashAlgorithm> cte = new HashMap<Integer, HashAlgorithm>();
+ for (HashAlgorithm method : values()) {
+ cte.put(Integer.valueOf(method.getCode()), method);
+ }
+ codeToEnum = Collections.unmodifiableMap(cte);
+ }
+
+ /**
+ * private constructor for enum style class.
+ */
+ HashAlgorithm(int code) {
+ this.code = code;
+ }
+
+ /**
+ * the hash algorithm ID.
+ *
+ * @return the PKWare hashAlg
+ */
+ public int getCode() {
+ return code;
+ }
+
+ /**
+ * returns the HashAlgorithm for the given code or null if the method is
+ * not known.
+ */
+ public static HashAlgorithm getAlgorithmByCode(int code) {
+ return codeToEnum.get(Integer.valueOf(code));
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/commons-compress/blob/a433f625/src/main/java/org/apache/commons/compress/archivers/zip/X0014_X509Certificates.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/compress/archivers/zip/X0014_X509Certificates.java b/src/main/java/org/apache/commons/compress/archivers/zip/X0014_X509Certificates.java
new file mode 100644
index 0000000..669700b
--- /dev/null
+++ b/src/main/java/org/apache/commons/compress/archivers/zip/X0014_X509Certificates.java
@@ -0,0 +1,166 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.commons.compress.archivers.zip;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+/**
+ * PKCS#7 Store for X.509 Certificates (0x0014):
+ *
+ * This field MUST contain information about each of the certificates files may
+ * be signed with. When the Central Directory Encryption feature is enabled for
+ * a ZIP file, this record will appear in the Archive Extra Data Record,
+ * otherwise it will appear in the first central directory record and will be
+ * ignored in any other record.
+ *
+ * Note: all fields stored in Intel low-byte/high-byte order.
+ *
+ * <pre>
+ * Value Size Description
+ * ----- ---- -----------
+ * (Store) 0x0014 2 bytes Tag for this "extra" block type
+ * TSize 2 bytes Size of the store data
+ * TData TSize Data about the store
+ * </pre>
+ *
+ * @NotThreadSafe
+ */
+public class X0014_X509Certificates extends PKWareExtraHeader implements ZipExtraField {
+ private static final ZipShort HEADER_ID = new ZipShort(0x0014);
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Get the header id.
+ *
+ * @return the header id
+ */
+ public ZipShort getHeaderId() {
+ return HEADER_ID;
+ }
+
+ /**
+ * Extra field data in local file data - without Header-ID or length
+ * specifier.
+ */
+ private byte[] localData;
+
+ /**
+ * Set the extra field data in the local file data - without Header-ID or
+ * length specifier.
+ *
+ * @param data
+ * the field data to use
+ */
+ public void setLocalFileDataData(byte[] data) {
+ localData = ZipUtil.copy(data);
+ }
+
+ /**
+ * Get the length of the local data.
+ *
+ * @return the length of the local data
+ */
+ public ZipShort getLocalFileDataLength() {
+ return new ZipShort(localData != null ? localData.length : 0);
+ }
+
+ /**
+ * Get the local data.
+ *
+ * @return the local data
+ */
+ public byte[] getLocalFileDataData() {
+ return ZipUtil.copy(localData);
+ }
+
+ /**
+ * Extra field data in central directory - without Header-ID or length
+ * specifier.
+ */
+ private byte[] centralData;
+
+ /**
+ * Set the extra field data in central directory.
+ *
+ * @param data
+ * the data to use
+ */
+ public void setCentralDirectoryData(byte[] data) {
+ centralData = ZipUtil.copy(data);
+ }
+
+ /**
+ * Get the central data length. If there is no central data, get the local
+ * file data length.
+ *
+ * @return the central data length
+ */
+ public ZipShort getCentralDirectoryLength() {
+ if (centralData != null) {
+ return new ZipShort(centralData.length);
+ }
+ return getLocalFileDataLength();
+ }
+
+ /**
+ * Get the central data.
+ *
+ * @return the central data if present, else return the local file data
+ */
+ public byte[] getCentralDirectoryData() {
+ if (centralData != null) {
+ return ZipUtil.copy(centralData);
+ }
+ return getLocalFileDataData();
+ }
+
+ /**
+ * @param data
+ * the array of bytes.
+ * @param offset
+ * the source location in the data array.
+ * @param length
+ * the number of bytes to use in the data array.
+ * @see ZipExtraField#parseFromLocalFileData(byte[], int, int)
+ */
+ public void parseFromLocalFileData(byte[] data, int offset, int length) {
+ byte[] tmp = new byte[length];
+ System.arraycopy(data, offset, tmp, 0, length);
+ setLocalFileDataData(tmp);
+ }
+
+ /**
+ * @param data
+ * the array of bytes.
+ * @param offset
+ * the source location in the data array.
+ * @param length
+ * the number of bytes to use in the data array.
+ * @see ZipExtraField#parseFromCentralDirectoryData(byte[], int, int)
+ */
+ public void parseFromCentralDirectoryData(byte[] data, int offset, int length) {
+ byte[] tmp = new byte[length];
+ System.arraycopy(data, offset, tmp, 0, length);
+ setCentralDirectoryData(tmp);
+ if (localData == null) {
+ setLocalFileDataData(tmp);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/commons-compress/blob/a433f625/src/main/java/org/apache/commons/compress/archivers/zip/X0015_CertificateIdForFile.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/compress/archivers/zip/X0015_CertificateIdForFile.java b/src/main/java/org/apache/commons/compress/archivers/zip/X0015_CertificateIdForFile.java
new file mode 100644
index 0000000..44295db
--- /dev/null
+++ b/src/main/java/org/apache/commons/compress/archivers/zip/X0015_CertificateIdForFile.java
@@ -0,0 +1,186 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.commons.compress.archivers.zip;
+
+/**
+ * X.509 Certificate ID and Signature for individual file (0x0015):
+ *
+ * This field contains the information about which certificate in the PKCS#7
+ * store was used to sign a particular file. It also contains the signature
+ * data. This field can appear multiple times, but can only appear once per
+ * certificate.
+ *
+ * Note: all fields stored in Intel low-byte/high-byte order.
+ *
+ * <pre>
+ * Value Size Description
+ * ----- ---- -----------
+ * (CID) 0x0015 2 bytes Tag for this "extra" block type
+ * TSize 2 bytes Size of data that follows
+ * RCount 4 bytes Number of recipients. (inferred)
+ * HashAlg 2 bytes Hash algorithm identifier. (inferred)
+ * TData TSize Signature Data
+ * </pre>
+ *
+ * @NotThreadSafe
+ */
+public class X0015_CertificateIdForFile extends PKWareExtraHeader implements ZipExtraField {
+ private static final ZipShort HEADER_ID = new ZipShort(0x0015);
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Get the header id.
+ *
+ * @return the header id
+ */
+ public ZipShort getHeaderId() {
+ return HEADER_ID;
+ }
+
+ /**
+ * Extra field data in local file data - without Header-ID or length
+ * specifier.
+ */
+ private byte[] localData;
+
+ private int rcount;
+ private HashAlgorithm hashAlg;
+
+ /**
+ * Get record count.
+ * @return
+ */
+ public int getRecordCount() {
+ return rcount;
+ }
+
+ /**
+ * Get hash algorithm.
+ * @return
+ */
+ public HashAlgorithm getHashAlgorithm() {
+ return hashAlg;
+ }
+
+ /**
+ * Set the extra field data in the local file data - without Header-ID or
+ * length specifier.
+ *
+ * @param data
+ * the field data to use
+ */
+ public void setLocalFileDataData(byte[] data) {
+ localData = ZipUtil.copy(data);
+ }
+
+ /**
+ * Get the length of the local data.
+ *
+ * @return the length of the local data
+ */
+ public ZipShort getLocalFileDataLength() {
+ return new ZipShort(localData != null ? localData.length : 0);
+ }
+
+ /**
+ * Get the local data.
+ *
+ * @return the local data
+ */
+ public byte[] getLocalFileDataData() {
+ return ZipUtil.copy(localData);
+ }
+
+ /**
+ * Extra field data in central directory - without Header-ID or length
+ * specifier.
+ */
+ private byte[] centralData;
+
+ /**
+ * Set the extra field data in central directory.
+ *
+ * @param data
+ * the data to use
+ */
+ public void setCentralDirectoryData(byte[] data) {
+ centralData = ZipUtil.copy(data);
+ }
+
+ /**
+ * Get the central data length. If there is no central data, get the local
+ * file data length.
+ *
+ * @return the central data length
+ */
+ public ZipShort getCentralDirectoryLength() {
+ if (centralData != null) {
+ return new ZipShort(centralData.length);
+ }
+ return getLocalFileDataLength();
+ }
+
+ /**
+ * Get the central data.
+ *
+ * @return the central data if present, else return the local file data
+ */
+ public byte[] getCentralDirectoryData() {
+ if (centralData != null) {
+ return ZipUtil.copy(centralData);
+ }
+ return getLocalFileDataData();
+ }
+
+ /**
+ * @param data
+ * the array of bytes.
+ * @param offset
+ * the source location in the data array.
+ * @param length
+ * the number of bytes to use in the data array.
+ * @see ZipExtraField#parseFromLocalFileData(byte[], int, int)
+ */
+ public void parseFromLocalFileData(byte[] data, int offset, int length) {
+ byte[] tmp = new byte[length];
+ System.arraycopy(data, offset, tmp, 0, length);
+ setLocalFileDataData(tmp);
+ }
+
+ /**
+ * @param data
+ * the array of bytes.
+ * @param offset
+ * the source location in the data array.
+ * @param length
+ * the number of bytes to use in the data array.
+ * @see ZipExtraField#parseFromCentralDirectoryData(byte[], int, int)
+ */
+ public void parseFromCentralDirectoryData(byte[] data, int offset, int length) {
+ byte[] tmp = new byte[length];
+ System.arraycopy(data, offset, tmp, 0, length);
+ setCentralDirectoryData(tmp);
+ if (localData == null) {
+ setLocalFileDataData(tmp);
+ }
+
+ this.rcount = ZipShort.getValue(data, offset);
+ this.hashAlg = HashAlgorithm.getAlgorithmByCode(ZipShort.getValue(data, offset + 2));
+ }
+}
http://git-wip-us.apache.org/repos/asf/commons-compress/blob/a433f625/src/main/java/org/apache/commons/compress/archivers/zip/X0016_CertificateIdForCentralDirectory.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/compress/archivers/zip/X0016_CertificateIdForCentralDirectory.java b/src/main/java/org/apache/commons/compress/archivers/zip/X0016_CertificateIdForCentralDirectory.java
new file mode 100644
index 0000000..2696c61
--- /dev/null
+++ b/src/main/java/org/apache/commons/compress/archivers/zip/X0016_CertificateIdForCentralDirectory.java
@@ -0,0 +1,186 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.commons.compress.archivers.zip;
+
+/**
+ * X.509 Certificate ID and Signature for central directory (0x0016):
+ *
+ * This field contains the information about which certificate in the PKCS#7
+ * store was used to sign the central directory structure. When the Central
+ * Directory Encryption feature is enabled for a ZIP file, this record will
+ * appear in the Archive Extra Data Record, otherwise it will appear in the
+ * first central directory record.
+ *
+ * Note: all fields stored in Intel low-byte/high-byte order.
+ *
+ * <pre>
+ * Value Size Description
+ * ----- ---- -----------
+ * (CDID) 0x0016 2 bytes Tag for this "extra" block type
+ * TSize 2 bytes Size of data that follows
+ * RCount 4 bytes Number of recipients. (inferred)
+ * HashAlg 2 bytes Hash algorithm identifier. (inferred)
+ * TData TSize Data
+ * </pre>
+ *
+ * @NotThreadSafe
+ */
+public class X0016_CertificateIdForCentralDirectory extends PKWareExtraHeader implements ZipExtraField {
+ private static final ZipShort HEADER_ID = new ZipShort(0x0016);
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Get the header id.
+ *
+ * @return the header id
+ */
+ public ZipShort getHeaderId() {
+ return HEADER_ID;
+ }
+
+ /**
+ * Extra field data in local file data - without Header-ID or length
+ * specifier.
+ */
+ private byte[] localData;
+
+ private int rcount;
+ private HashAlgorithm hashAlg;
+
+ /**
+ * Get record count.
+ * @return
+ */
+ public int getRecordCount() {
+ return rcount;
+ }
+
+ /**
+ * Get hash algorithm.
+ * @return
+ */
+ public HashAlgorithm getHashAlgorithm() {
+ return hashAlg;
+ }
+
+ /**
+ * Set the extra field data in the local file data - without Header-ID or
+ * length specifier.
+ *
+ * @param data
+ * the field data to use
+ */
+ public void setLocalFileDataData(byte[] data) {
+ localData = ZipUtil.copy(data);
+ }
+
+ /**
+ * Get the length of the local data.
+ *
+ * @return the length of the local data
+ */
+ public ZipShort getLocalFileDataLength() {
+ return new ZipShort(localData != null ? localData.length : 0);
+ }
+
+ /**
+ * Get the local data.
+ *
+ * @return the local data
+ */
+ public byte[] getLocalFileDataData() {
+ return ZipUtil.copy(localData);
+ }
+
+ /**
+ * Extra field data in central directory - without Header-ID or length
+ * specifier.
+ */
+ private byte[] centralData;
+
+ /**
+ * Set the extra field data in central directory.
+ *
+ * @param data
+ * the data to use
+ */
+ public void setCentralDirectoryData(byte[] data) {
+ centralData = ZipUtil.copy(data);
+ }
+
+ /**
+ * Get the central data length. If there is no central data, get the local
+ * file data length.
+ *
+ * @return the central data length
+ */
+ public ZipShort getCentralDirectoryLength() {
+ if (centralData != null) {
+ return new ZipShort(centralData.length);
+ }
+ return getLocalFileDataLength();
+ }
+
+ /**
+ * Get the central data.
+ *
+ * @return the central data if present, else return the local file data
+ */
+ public byte[] getCentralDirectoryData() {
+ if (centralData != null) {
+ return ZipUtil.copy(centralData);
+ }
+ return getLocalFileDataData();
+ }
+
+ /**
+ * This should never be called for this header type.
+ *
+ * @param data
+ * the array of bytes.
+ * @param offset
+ * the source location in the data array.
+ * @param length
+ * the number of bytes to use in the data array.
+ * @see ZipExtraField#parseFromLocalFileData(byte[], int, int)
+ */
+ public void parseFromLocalFileData(byte[] data, int offset, int length) {
+ byte[] tmp = new byte[length];
+ System.arraycopy(data, offset, tmp, 0, length);
+ setLocalFileDataData(tmp);
+ }
+
+ /**
+ * @param data
+ * the array of bytes.
+ * @param offset
+ * the source location in the data array.
+ * @param length
+ * the number of bytes to use in the data array.
+ * @see ZipExtraField#parseFromCentralDirectoryData(byte[], int, int)
+ */
+ public void parseFromCentralDirectoryData(byte[] data, int offset, int length) {
+ byte[] tmp = new byte[length];
+ System.arraycopy(data, offset, tmp, 0, length);
+ setCentralDirectoryData(tmp);
+
+ this.rcount = ZipShort.getValue(data, offset);
+ this.hashAlg = HashAlgorithm.getAlgorithmByCode(ZipShort.getValue(data, offset + 2));
+ }
+}
http://git-wip-us.apache.org/repos/asf/commons-compress/blob/a433f625/src/main/java/org/apache/commons/compress/archivers/zip/X0017_StrongEncryptionHeader.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/compress/archivers/zip/X0017_StrongEncryptionHeader.java b/src/main/java/org/apache/commons/compress/archivers/zip/X0017_StrongEncryptionHeader.java
new file mode 100644
index 0000000..ca9c829
--- /dev/null
+++ b/src/main/java/org/apache/commons/compress/archivers/zip/X0017_StrongEncryptionHeader.java
@@ -0,0 +1,482 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.commons.compress.archivers.zip;
+
+/**
+ * Strong Encryption Header (0x0017)
+ *
+ * Certificate-based encryption:
+ *
+ * <pre>
+ * Value Size Description
+ * ----- ---- -----------
+ * 0x0017 2 bytes Tag for this "extra" block type
+ * TSize 2 bytes Size of data that follows
+ * Format 2 bytes Format definition for this record
+ * AlgID 2 bytes Encryption algorithm identifier
+ * Bitlen 2 bytes Bit length of encryption key (32-448 bits)
+ * Flags 2 bytes Processing flags
+ * RCount 4 bytes Number of recipients.
+ * HashAlg 2 bytes Hash algorithm identifier
+ * HSize 2 bytes Hash size
+ * SRList (var) Simple list of recipients hashed public keys
+ *
+ * Flags - This defines the processing flags.
+ *
+ * <ul>
+ * <li>0x0007 - reserved for future use
+ * <li>0x000F - reserved for future use
+ * <li>0x0100 - Indicates non-OAEP key wrapping was used. If this
+ * this field is set, the version needed to extract must
+ * be at least 61. This means OAEP key wrapping is not
+ * used when generating a Master Session Key using
+ * ErdData.
+ * <li>0x4000 - ErdData must be decrypted using 3DES-168, otherwise use the
+ * same algorithm used for encrypting the file contents.
+ * <li>0x8000 - reserved for future use
+ * </ul>
+ *
+ * RCount - This defines the number intended recipients whose
+ * public keys were used for encryption. This identifies
+ * the number of elements in the SRList.
+ *
+ * see also: reserved1
+ *
+ * HashAlg - This defines the hash algorithm used to calculate
+ * the public key hash of each public key used
+ * for encryption. This field currently supports
+ * only the following value for SHA-1
+ *
+ * 0x8004 - SHA1
+ *
+ * HSize - This defines the size of a hashed public key.
+ *
+ * SRList - This is a variable length list of the hashed
+ * public keys for each intended recipient. Each
+ * element in this list is HSize. The total size of
+ * SRList is determined using RCount * HSize.
+ * </pre>
+ *
+ * Password-based Extra Field 0x0017 in central header only.
+ *
+ * <pre>
+ * Value Size Description
+ * ----- ---- -----------
+ * 0x0017 2 bytes Tag for this "extra" block type
+ * TSize 2 bytes Size of data that follows
+ * Format 2 bytes Format definition for this record
+ * AlgID 2 bytes Encryption algorithm identifier
+ * Bitlen 2 bytes Bit length of encryption key (32-448 bits)
+ * Flags 2 bytes Processing flags
+ * (more?)
+ * </pre>
+ *
+ * <b>Format</b> - the data format identifier for this record. The only value
+ * allowed at this time is the integer value 2.
+ *
+ * Password-based Extra Field 0x0017 preceding compressed file data.
+ *
+ * <pre>
+ * Value Size Description
+ * ----- ---- -----------
+ * 0x0017 2 bytes Tag for this "extra" block type
+ * IVSize 2 bytes Size of initialization vector (IV)
+ * IVData IVSize Initialization vector for this file
+ * Size 4 bytes Size of remaining decryption header data
+ * Format 2 bytes Format definition for this record
+ * AlgID 2 bytes Encryption algorithm identifier
+ * Bitlen 2 bytes Bit length of encryption key (32-448 bits)
+ * Flags 2 bytes Processing flags
+ * ErdSize 2 bytes Size of Encrypted Random Data
+ * ErdData ErdSize Encrypted Random Data
+ * Reserved1 4 bytes Reserved certificate processing data
+ * Reserved2 (var) Reserved for certificate processing data
+ * VSize 2 bytes Size of password validation data
+ * VData VSize-4 Password validation data
+ * VCRC32 4 bytes Standard ZIP CRC32 of password validation data
+ *
+ * IVData - The size of the IV should match the algorithm block size.
+ * The IVData can be completely random data. If the size of
+ * the randomly generated data does not match the block size
+ * it should be complemented with zero's or truncated as
+ * necessary. If IVSize is 0,then IV = CRC32 + Uncompressed
+ * File Size (as a 64 bit little-endian, unsigned integer value).
+ *
+ * Format - the data format identifier for this record. The only
+ * value allowed at this time is the integer value 2.
+ *
+ * ErdData - Encrypted random data is used to store random data that
+ * is used to generate a file session key for encrypting
+ * each file. SHA1 is used to calculate hash data used to
+ * derive keys. File session keys are derived from a master
+ * session key generated from the user-supplied password.
+ * If the Flags field in the decryption header contains
+ * the value 0x4000, then the ErdData field must be
+ * decrypted using 3DES. If the value 0x4000 is not set,
+ * then the ErdData field must be decrypted using AlgId.
+ *
+ * Reserved1 - Reserved for certificate processing, if value is
+ * zero, then Reserved2 data is absent. See the explanation
+ * under the Certificate Processing Method for details on
+ * this data structure.
+ *
+ * Reserved2 - If present, the size of the Reserved2 data structure
+ * is located by skipping the first 4 bytes of this field
+ * and using the next 2 bytes as the remaining size. See
+ * the explanation under the Certificate Processing Method
+ * for details on this data structure.
+ *
+ * VSize - This size value will always include the 4 bytes of the
+ * VCRC32 data and will be greater than 4 bytes.
+ *
+ * VData - Random data for password validation. This data is VSize
+ * in length and VSize must be a multiple of the encryption
+ * block size. VCRC32 is a checksum value of VData.
+ * VData and VCRC32 are stored encrypted and start the
+ * stream of encrypted data for a file.
+ * </pre>
+ *
+ *
+ * Reserved1 - Certificate Decryption Header Reserved1 Data:
+ *
+ * <pre>
+ * Value Size Description
+ * ----- ---- -----------
+ * RCount 4 bytes Number of recipients.
+ * </pre>
+ *
+ * RCount - This defines the number intended recipients whose public keys were
+ * used for encryption. This defines the number of elements in the REList field
+ * defined below.
+ *
+ *
+ * Reserved2 - Certificate Decryption Header Reserved2 Data Structures:
+ *
+ * <pre>
+ * Value Size Description
+ * ----- ---- -----------
+ * HashAlg 2 bytes Hash algorithm identifier
+ * HSize 2 bytes Hash size
+ * REList (var) List of recipient data elements
+ *
+ * HashAlg - This defines the hash algorithm used to calculate
+ * the public key hash of each public key used
+ * for encryption. This field currently supports
+ * only the following value for SHA-1
+ *
+ * 0x8004 - SHA1
+ *
+ * HSize - This defines the size of a hashed public key
+ * defined in REHData.
+ *
+ * REList - This is a variable length of list of recipient data.
+ * Each element in this list consists of a Recipient
+ * Element data structure as follows:
+ * </pre>
+ *
+ * Recipient Element (REList) Data Structure:
+ *
+ * <pre>
+ * Value Size Description
+ * ----- ---- -----------
+ * RESize 2 bytes Size of REHData + REKData
+ * REHData HSize Hash of recipients public key
+ * REKData (var) Simple key blob
+ *
+ *
+ * RESize - This defines the size of an individual REList
+ * element. This value is the combined size of the
+ * REHData field + REKData field. REHData is defined by
+ * HSize. REKData is variable and can be calculated
+ * for each REList element using RESize and HSize.
+ *
+ * REHData - Hashed public key for this recipient.
+ *
+ * REKData - Simple Key Blob. The format of this data structure
+ * is identical to that defined in the Microsoft
+ * CryptoAPI and generated using the CryptExportKey()
+ * function. The version of the Simple Key Blob
+ * supported at this time is 0x02 as defined by
+ * Microsoft.
+ *
+ * For more details see https://msdn.microsoft.com/en-us/library/aa920051.aspx
+ * </pre>
+ *
+ * <b>Flags</b> - Processing flags needed for decryption
+ *
+ * <ul>
+ * <li>0x0001 - Password is required to decrypt</li>
+ * <li>0x0002 - Certificates only</li>
+ * <li>0x0003 - Password or certificate required to decrypt</li>
+ * <li>0x0007 - reserved for future use
+ * <li>0x000F - reserved for future use
+ * <li>0x0100 - indicates non-OAEP key wrapping was used. If this field is set
+ * the version needed to extract must be at least 61. This means OAEP key
+ * wrapping is not used when generating a Master Session Key using ErdData.
+ * <li>0x4000 - ErdData must be decrypted using 3DES-168, otherwise use the same
+ * algorithm used for encrypting the file contents.
+ * <li>0x8000 - reserved for future use.
+ * </ul>
+ *
+ * <b>See the section describing the Strong Encryption Specification for
+ * details. Refer to the section in this document entitled
+ * "Incorporating PKWARE Proprietary Technology into Your Product" for more
+ * information.</b>
+ *
+ * @NotThreadSafe
+ */
+public class X0017_StrongEncryptionHeader extends PKWareExtraHeader implements ZipExtraField {
+ private static final ZipShort HEADER_ID = new ZipShort(0x0017);
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Get the header id.
+ *
+ * @return the header id
+ */
+ public ZipShort getHeaderId() {
+ return HEADER_ID;
+ }
+
+ /**
+ * Extra field data in local file data - without Header-ID or length
+ * specifier.
+ */
+ private byte[] localData;
+
+ private int format;
+ private EncryptionAlgorithm algId;
+ private int bitlen;
+ private int flags;
+ private long rcount;
+ private HashAlgorithm hashAlg;
+ private int hashSize;
+
+ // encryption data
+ private byte ivData[];
+ private byte erdData[];
+
+ // encryption key
+ private byte recipientKeyHash[];
+ private byte keyBlob[];
+
+ // password verification data
+ private byte vData[];
+ private byte vCRC32[];
+
+ /**
+ * Get record count.
+ * @return
+ */
+ public long getRecordCount() {
+ return rcount;
+ }
+
+ /**
+ * Get hash algorithm.
+ * @return
+ */
+ public HashAlgorithm getHashAlgorithm() {
+ return hashAlg;
+ }
+
+ /**
+ * Get encryption algorithm.
+ * @return
+ */
+ public EncryptionAlgorithm getEncryptionAlgorithm() {
+ return algId;
+ }
+
+ /**
+ * Set the extra field data in the local file data - without Header-ID or
+ * length specifier.
+ *
+ * @param data
+ * the field data to use
+ */
+ public void setLocalFileDataData(byte[] data) {
+ localData = ZipUtil.copy(data);
+ }
+
+ /**
+ * Get the length of the local data.
+ *
+ * @return the length of the local data
+ */
+ public ZipShort getLocalFileDataLength() {
+ return new ZipShort(localData != null ? localData.length : 0);
+ }
+
+ /**
+ * Get the local data.
+ *
+ * @return the local data
+ */
+ public byte[] getLocalFileDataData() {
+ return ZipUtil.copy(localData);
+ }
+
+ /**
+ * Extra field data in central directory - without Header-ID or length
+ * specifier.
+ */
+ private byte[] centralData;
+
+ /**
+ * Set the extra field data in central directory.
+ *
+ * @param data
+ * the data to use
+ */
+ public void setCentralDirectoryData(byte[] data) {
+ centralData = ZipUtil.copy(data);
+ }
+
+ /**
+ * Get the central data length. If there is no central data, get the local
+ * file data length.
+ *
+ * @return the central data length
+ */
+ public ZipShort getCentralDirectoryLength() {
+ if (centralData != null) {
+ return new ZipShort(centralData.length);
+ }
+ return getLocalFileDataLength();
+ }
+
+ /**
+ * Get the central data.
+ *
+ * @return the central data if present, else return the local file data
+ */
+ public byte[] getCentralDirectoryData() {
+ if (centralData != null) {
+ return ZipUtil.copy(centralData);
+ }
+ return getLocalFileDataData();
+ }
+
+ /**
+ * Parse central directory format.
+ *
+ * @param data
+ * @param offset
+ * @param length
+ */
+ public void parseCentralDirectoryFormat(byte[] data, int offset, int length) {
+ this.format = ZipShort.getValue(data, offset);
+ this.algId = EncryptionAlgorithm.getAlgorithmByCode(ZipShort.getValue(data, offset + 2));
+ this.bitlen = ZipShort.getValue(data, offset + 4);
+ this.flags = ZipShort.getValue(data, offset + 6);
+ this.rcount = ZipLong.getValue(data, offset + 8);
+
+ if (rcount > 0) {
+ this.hashAlg = HashAlgorithm.getAlgorithmByCode(ZipShort.getValue(data, offset + 12));
+ this.hashSize = ZipShort.getValue(data, offset + 14);
+ // srlist... hashed public keys
+ for (int i = 0; i < this.rcount; i++) {
+ for (int j = 0; j < this.hashSize; j++) {
+ // ZipUtil.signedByteToUnsignedInt(data[offset + 16 + (i * this.hashSize) + j]));
+ }
+ }
+ }
+ }
+
+ /**
+ * Parse file header format. (Password only?)
+ *
+ * @param data
+ * @param offset
+ * @param length
+ */
+ public void parseFileFormat(byte[] data, int offset, int length) {
+ int ivSize = ZipShort.getValue(data, offset);
+ this.ivData = new byte[ivSize];
+ System.arraycopy(data, offset + 4, this.ivData, 0, ivSize);
+
+ long size = ZipLong.getValue(data, offset + ivSize + 2);
+ this.format = ZipShort.getValue(data, offset + ivSize + 6);
+ this.algId = EncryptionAlgorithm.getAlgorithmByCode(ZipShort.getValue(data, offset + ivSize + 8));
+ this.bitlen = ZipShort.getValue(data, offset + ivSize + 10);
+ this.flags = ZipShort.getValue(data, offset + ivSize + 12);
+
+ int erdSize = ZipShort.getValue(data, offset + ivSize + 14);
+ this.erdData = new byte[erdSize];
+ System.arraycopy(data, offset + ivSize + 16, this.erdData, 0, erdSize);
+
+ this.rcount = ZipLong.getValue(data, offset + ivSize + 16 + erdSize);
+ System.out.println("rcount: " + rcount);
+ if (rcount == 0) {
+ int vSize = ZipShort.getValue(data, offset + ivSize + 20 + erdSize);
+ this.vData = new byte[vSize - 4];
+ this.vCRC32 = new byte[4];
+ System.arraycopy(data, offset + ivSize + 22 + erdSize , this.vData, 0, vSize - 4);
+ System.arraycopy(data, offset + ivSize + 22 + erdSize + vSize - 4, vCRC32, 0, 4);
+ } else {
+ this.hashAlg = HashAlgorithm.getAlgorithmByCode(ZipShort.getValue(data, offset + ivSize + 20 + erdSize));
+ this.hashSize = ZipShort.getValue(data, offset + ivSize + 22 + erdSize);
+ int resize = ZipShort.getValue(data, offset + ivSize + 24 + erdSize);
+ this.recipientKeyHash = new byte[this.hashSize];
+ this.keyBlob = new byte[resize - this.hashSize];
+ System.arraycopy(data, offset + ivSize + 24 + erdSize, this.recipientKeyHash, 0, this.hashSize);
+ System.arraycopy(data, offset + ivSize + 24 + erdSize + this.hashSize, this.keyBlob, 0, resize - this.hashSize);
+
+ int vSize = ZipShort.getValue(data, offset + ivSize + 26 + erdSize + resize);
+ this.vData = new byte[vSize - 4];
+ this.vCRC32 = new byte[4];
+ System.arraycopy(data, offset + ivSize + 22 + erdSize + resize, this.vData, 0, vSize - 4);
+ System.arraycopy(data, offset + ivSize + 22 + erdSize + resize + vSize - 4, vCRC32, 0, 4);
+ }
+
+ // validate values?
+ }
+
+ /**
+ * @param data
+ * the array of bytes.
+ * @param offset
+ * the source location in the data array.
+ * @param length
+ * the number of bytes to use in the data array.
+ * @see ZipExtraField#parseFromLocalFileData(byte[], int, int)
+ */
+ public void parseFromLocalFileData(byte[] data, int offset, int length) {
+ byte[] tmp = new byte[length];
+ System.arraycopy(data, offset, tmp, 0, length);
+ parseFileFormat(data, offset, length);
+ }
+
+ /**
+ * @param data
+ * the array of bytes.
+ * @param offset
+ * the source location in the data array.
+ * @param length
+ * the number of bytes to use in the data array.
+ * @see ZipExtraField#parseFromCentralDirectoryData(byte[], int, int)
+ */
+ public void parseFromCentralDirectoryData(byte[] data, int offset, int length) {
+ byte[] tmp = new byte[length];
+ System.arraycopy(data, offset, tmp, 0, length);
+ setCentralDirectoryData(tmp);
+ parseCentralDirectoryFormat(data, offset, length);
+ }
+}
http://git-wip-us.apache.org/repos/asf/commons-compress/blob/a433f625/src/main/java/org/apache/commons/compress/archivers/zip/X0019_EncryptionRecipientCertificateList.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/compress/archivers/zip/X0019_EncryptionRecipientCertificateList.java b/src/main/java/org/apache/commons/compress/archivers/zip/X0019_EncryptionRecipientCertificateList.java
new file mode 100644
index 0000000..2fad277
--- /dev/null
+++ b/src/main/java/org/apache/commons/compress/archivers/zip/X0019_EncryptionRecipientCertificateList.java
@@ -0,0 +1,171 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.commons.compress.archivers.zip;
+
+/**
+ * PKCS#7 Encryption Recipient Certificate List (0x0019)
+ *
+ * This field MAY contain information about each of the certificates used in
+ * encryption processing and it can be used to identify who is allowed to
+ * decrypt encrypted files. This field should only appear in the archive extra
+ * data record. This field is not required and serves only to aid archive
+ * modifications by preserving public encryption key data. Individual security
+ * requirements may dictate that this data be omitted to deter information
+ * exposure.
+ *
+ * Note: all fields stored in Intel low-byte/high-byte order.
+ *
+ * <pre>
+ * Value Size Description
+ * ----- ---- -----------
+ * (CStore) 0x0019 2 bytes Tag for this "extra" block type
+ * TSize 2 bytes Size of the store data
+ * Version 2 bytes Format version number - must 0x0001 at this time
+ * CStore (var) PKCS#7 data blob
+ * </pre>
+ *
+ * <b>See the section describing the Strong Encryption Specification for
+ * details. Refer to the section in this document entitled
+ * "Incorporating PKWARE Proprietary Technology into Your Product" for more
+ * information.</b>
+ *
+ * @NotThreadSafe
+ */
+public class X0019_EncryptionRecipientCertificateList extends PKWareExtraHeader implements ZipExtraField {
+ private static final ZipShort HEADER_ID = new ZipShort(0x0019);
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Get the header id.
+ *
+ * @return the header id
+ */
+ public ZipShort getHeaderId() {
+ return HEADER_ID;
+ }
+
+ /**
+ * Extra field data in local file data - without Header-ID or length
+ * specifier.
+ */
+ private byte[] localData;
+
+ /**
+ * Set the extra field data in the local file data - without Header-ID or
+ * length specifier.
+ *
+ * @param data
+ * the field data to use
+ */
+ public void setLocalFileDataData(byte[] data) {
+ localData = ZipUtil.copy(data);
+ }
+
+ /**
+ * Get the length of the local data.
+ *
+ * @return the length of the local data
+ */
+ public ZipShort getLocalFileDataLength() {
+ return new ZipShort(localData != null ? localData.length : 0);
+ }
+
+ /**
+ * Get the local data.
+ *
+ * @return the local data
+ */
+ public byte[] getLocalFileDataData() {
+ return ZipUtil.copy(localData);
+ }
+
+ /**
+ * Extra field data in central directory - without Header-ID or length
+ * specifier.
+ */
+ private byte[] centralData;
+
+ /**
+ * Set the extra field data in central directory.
+ *
+ * @param data
+ * the data to use
+ */
+ public void setCentralDirectoryData(byte[] data) {
+ centralData = ZipUtil.copy(data);
+ }
+
+ /**
+ * Get the central data length. If there is no central data, get the local
+ * file data length.
+ *
+ * @return the central data length
+ */
+ public ZipShort getCentralDirectoryLength() {
+ if (centralData != null) {
+ return new ZipShort(centralData.length);
+ }
+ return getLocalFileDataLength();
+ }
+
+ /**
+ * Get the central data.
+ *
+ * @return the central data if present, else return the local file data
+ */
+ public byte[] getCentralDirectoryData() {
+ if (centralData != null) {
+ return ZipUtil.copy(centralData);
+ }
+ return getLocalFileDataData();
+ }
+
+ /**
+ * @param data
+ * the array of bytes.
+ * @param offset
+ * the source location in the data array.
+ * @param length
+ * the number of bytes to use in the data array.
+ * @see ZipExtraField#parseFromLocalFileData(byte[], int, int)
+ */
+ public void parseFromLocalFileData(byte[] data, int offset, int length) {
+ byte[] tmp = new byte[length];
+ System.arraycopy(data, offset, tmp, 0, length);
+ setLocalFileDataData(tmp);
+ }
+
+ /**
+ * @param data
+ * the array of bytes.
+ * @param offset
+ * the source location in the data array.
+ * @param length
+ * the number of bytes to use in the data array.
+ * @see ZipExtraField#parseFromCentralDirectoryData(byte[], int, int)
+ */
+ public void parseFromCentralDirectoryData(byte[] data, int offset, int length) {
+ byte[] tmp = new byte[length];
+ System.arraycopy(data, offset, tmp, 0, length);
+ setCentralDirectoryData(tmp);
+ if (localData == null) {
+ setLocalFileDataData(tmp);
+ }
+ }
+}