Winzip AES encryption support for writing.
diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt
index cfd47f3..7393970 100644
--- a/lib/CMakeLists.txt
+++ b/lib/CMakeLists.txt
@@ -83,6 +83,7 @@
zip_file_rename.c
zip_file_replace.c
zip_file_set_comment.c
+ zip_file_set_encryption.c
zip_file_set_external_attributes.c
zip_file_set_mtime.c
zip_file_strerror.c
@@ -140,6 +141,8 @@
zip_source_tell.c
zip_source_tell_write.c
zip_source_window.c
+ zip_source_winzip_aes_decode.c
+ zip_source_winzip_aes_encode.c
zip_source_write.c
zip_source_zip.c
zip_source_zip_new.c
@@ -157,6 +160,7 @@
IF(WIN32)
SET(LIBZIP_OPSYS_FILES
+ zip_random_win32.c
zip_source_win32a.c
zip_source_win32handle.c
zip_source_win32utf8.c
@@ -164,6 +168,7 @@
)
ELSE(WIN32)
SET(LIBZIP_OPSYS_FILES
+ zip_random_unix.c
zip_source_file.c
)
ENDIF(WIN32)
diff --git a/lib/Makefile.am b/lib/Makefile.am
index d4b97bb..04740a2 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -12,18 +12,20 @@
libzip_la_LIBADD=@LTLIBOBJS@
if WIN32_HOST
-IO_SOURCES=\
+OS_SOURCES=\
+ zip_random_win32.c \
zip_source_win32a.c \
zip_source_win32handle.c \
zip_source_win32utf8.c \
zip_source_win32w.c
else
-IO_SOURCES=\
+OS_SOURCES=\
+ zip_random_unix.c \
zip_source_file.c
endif
libzip_la_SOURCES=\
- ${IO_SOURCES} \
+ ${OS_SOURCES} \
gladman-fcrypt.c \
zip_add.c \
zip_add_dir.c \
@@ -55,6 +57,7 @@
zip_file_rename.c \
zip_file_replace.c \
zip_file_set_comment.c \
+ zip_file_set_encryption.c \
zip_file_set_external_attributes.c \
zip_file_set_mtime.c \
zip_file_strerror.c \
@@ -113,7 +116,8 @@
zip_source_tell.c \
zip_source_tell_write.c \
zip_source_window.c \
- zip_source_winzip_aes.c \
+ zip_source_winzip_aes_decode.c \
+ zip_source_winzip_aes_encode.c \
zip_source_write.c \
zip_source_zip.c \
zip_source_zip_new.c \
diff --git a/lib/zip.h b/lib/zip.h
index 804dcea..97f01e5 100644
--- a/lib/zip.h
+++ b/lib/zip.h
@@ -358,6 +358,7 @@
ZIP_EXTERN int zip_file_rename(zip_t *, zip_uint64_t, const char *, zip_flags_t);
ZIP_EXTERN int zip_file_replace(zip_t *, zip_uint64_t, zip_source_t *, zip_flags_t);
ZIP_EXTERN int zip_file_set_comment(zip_t *, zip_uint64_t, const char *, zip_uint16_t, zip_flags_t);
+ZIP_EXTERN int zip_file_set_encryption(zip_t *, zip_uint64_t, zip_uint16_t, const char *);
ZIP_EXTERN int zip_file_set_external_attributes(zip_t *, zip_uint64_t, zip_flags_t, zip_uint8_t, zip_uint32_t);
ZIP_EXTERN int zip_file_set_mtime(zip_t *, zip_uint64_t, time_t, zip_flags_t);
ZIP_EXTERN const char *zip_file_strerror(zip_file_t *);
diff --git a/lib/zip_buffer.c b/lib/zip_buffer.c
index f622650..a59a020 100644
--- a/lib/zip_buffer.c
+++ b/lib/zip_buffer.c
@@ -140,6 +140,19 @@
}
+zip_uint64_t
+_zip_buffer_read(zip_buffer_t *buffer, zip_uint8_t *data, zip_uint64_t length)
+{
+ if (_zip_buffer_left(buffer) < length) {
+ length = _zip_buffer_left(buffer);
+ }
+
+ memcpy(data, _zip_buffer_get(buffer, length), length);
+
+ return length;
+}
+
+
zip_buffer_t *
_zip_buffer_new(zip_uint8_t *data, zip_uint64_t size)
{
diff --git a/lib/zip_close.c b/lib/zip_close.c
index ac536f1..fd5a107 100644
--- a/lib/zip_close.c
+++ b/lib/zip_close.c
@@ -134,7 +134,7 @@
i = filelist[j].idx;
entry = za->entry+i;
- new_data = (ZIP_ENTRY_DATA_CHANGED(entry) || ZIP_ENTRY_CHANGED(entry, ZIP_DIRENT_COMP_METHOD));
+ new_data = (ZIP_ENTRY_DATA_CHANGED(entry) || ZIP_ENTRY_CHANGED(entry, ZIP_DIRENT_COMP_METHOD) || ZIP_ENTRY_CHANGED(entry, ZIP_DIRENT_ENCRYPTION_METHOD));
/* create new local directory entry */
if (entry->changes == NULL) {
@@ -259,6 +259,10 @@
st.valid &= ~ZIP_STAT_COMP_SIZE;
}
+ if ((st.valid & ZIP_STAT_ENCRYPTION_METHOD) == 0) {
+ st.valid |= ZIP_STAT_ENCRYPTION_METHOD;
+ st.encryption_method = ZIP_EM_NONE;
+ }
flags = ZIP_EF_LOCAL;
@@ -290,8 +294,30 @@
bool needs_crc = (st.comp_method == ZIP_CM_STORE) || needs_decompress;
bool needs_compress = needs_recompress && (de->comp_method != ZIP_CM_STORE);
+ bool needs_reencrypt = needs_recompress || (de->changed & ZIP_DIRENT_PASSWORD) || (de->encryption_method != st.encryption_method);
+ bool needs_decrypt = needs_reencrypt && (st.encryption_method != ZIP_EM_NONE);
+ bool needs_encrypt = needs_reencrypt && (de->encryption_method != ZIP_EM_NONE);
+
src_final = src;
zip_source_keep(src_final);
+
+ if (needs_decrypt) {
+ zip_encryption_implementation impl;
+
+ if ((impl = _zip_get_encryption_implementation(st.encryption_method, ZIP_CODEC_DECODE)) == NULL) {
+ zip_error_set(&za->error, ZIP_ER_ENCRNOTSUPP, 0);
+ zip_source_free(src_final);
+ return -1;
+ }
+ if ((src_tmp = impl(za, src_final, st.encryption_method, ZIP_CODEC_DECODE, NULL)) == NULL) {
+ /* error set by impl */
+ zip_source_free(src_final);
+ return -1;
+ }
+
+ zip_source_free(src_final);
+ src_final = src_tmp;
+ }
if (needs_decompress) {
zip_compression_implementation comp_impl;
@@ -337,7 +363,26 @@
zip_source_free(src_final);
src_final = src_tmp;
}
+
+ if (needs_encrypt) {
+ zip_encryption_implementation impl;
+
+ if ((impl = _zip_get_encryption_implementation(de->encryption_method, ZIP_CODEC_ENCODE)) == NULL) {
+ zip_error_set(&za->error, ZIP_ER_ENCRNOTSUPP, 0);
+ zip_source_free(src_final);
+ return -1;
+ }
+ if ((src_tmp = impl(za, src_final, de->encryption_method, ZIP_CODEC_ENCODE, de->password)) == NULL) {
+ /* error set by impl */
+ zip_source_free(src_final);
+ return -1;
+ }
+
+ zip_source_free(src_final);
+ src_final = src_tmp;
+ }
+
if ((offdata = zip_source_tell_write(za->src)) < 0) {
return -1;
diff --git a/lib/zip_dirent.c b/lib/zip_dirent.c
index 6fcc6c7..4337bde 100644
--- a/lib/zip_dirent.c
+++ b/lib/zip_dirent.c
@@ -252,6 +252,13 @@
_zip_string_free(zde->comment);
zde->comment = NULL;
}
+ if (!zde->cloned || zde->changed & ZIP_DIRENT_PASSWORD) {
+ if (zde->password) {
+ _zip_crypto_clear(zde->password, strlen(zde->password));
+ }
+ free(zde->password);
+ zde->password = NULL;
+ }
}
@@ -290,6 +297,7 @@
de->ext_attrib = ZIP_EXT_ATTRIB_DEFAULT;
de->offset = 0;
de->encryption_method = ZIP_EM_NONE;
+ de->password = NULL;
}
@@ -758,6 +766,7 @@
zip_uint32_t ef_total_size;
bool is_zip64;
bool is_really_zip64;
+ bool is_winzip_aes;
zip_uint8_t buf[CDENTRYSIZE];
zip_buffer_t *buffer;
@@ -788,8 +797,16 @@
}
}
+ if (de->encryption_method == ZIP_EM_NONE) {
+ de->bitflags &= ~ZIP_GPBF_ENCRYPTED;
+ }
+ else {
+ de->bitflags |= ZIP_GPBF_ENCRYPTED;
+ }
+
is_really_zip64 = _zip_dirent_needs_zip64(de, flags);
is_zip64 = (flags & (ZIP_FL_LOCAL|ZIP_FL_FORCE_ZIP64)) == (ZIP_FL_LOCAL|ZIP_FL_FORCE_ZIP64) || is_really_zip64;
+ is_winzip_aes = de->encryption_method == ZIP_EM_AES_128 || de->encryption_method == ZIP_EM_AES_192 || de->encryption_method == ZIP_EM_AES_256;
if (is_zip64) {
zip_uint8_t ef_zip64[EFZIP64SIZE];
@@ -833,6 +850,35 @@
ef = ef64;
}
+ if (is_winzip_aes) {
+ zip_uint8_t data[EF_WINZIP_AES_SIZE];
+ zip_buffer_t *ef_buffer = _zip_buffer_new(data, sizeof(data));
+ zip_extra_field_t *ef_winzip;
+
+ if (ef_buffer == NULL) {
+ zip_error_set(&za->error, ZIP_ER_MEMORY, 0);
+ _zip_ef_free(ef);
+ return -1;
+ }
+
+ _zip_buffer_put_16(ef_buffer, 2);
+ _zip_buffer_put(ef_buffer, "AE", 2);
+ _zip_buffer_put_8(ef_buffer, (de->encryption_method & 0xff));
+ _zip_buffer_put_16(ef_buffer, de->comp_method);
+
+ if (!_zip_buffer_ok(ef_buffer)) {
+ zip_error_set(&za->error, ZIP_ER_INTERNAL, 0);
+ _zip_buffer_free(ef_buffer);
+ _zip_ef_free(ef);
+ return -1;
+ }
+
+ ef_winzip = _zip_ef_new(ZIP_EF_WINZIP_AES, EF_WINZIP_AES_SIZE, data, ZIP_EF_BOTH);
+ _zip_buffer_free(ef_buffer);
+ ef_winzip->next = ef;
+ ef = ef_winzip;
+ }
+
if ((buffer = _zip_buffer_new(buf, sizeof(buf))) == NULL) {
zip_error_set(&za->error, ZIP_ER_MEMORY, 0);
_zip_ef_free(ef);
@@ -846,13 +892,23 @@
}
_zip_buffer_put_16(buffer, (zip_uint16_t)(is_really_zip64 ? 45 : de->version_needed));
_zip_buffer_put_16(buffer, de->bitflags&0xfff9); /* clear compression method specific flags */
- _zip_buffer_put_16(buffer, (zip_uint16_t)de->comp_method);
+ if (is_winzip_aes) {
+ _zip_buffer_put_16(buffer, ZIP_CM_WINZIP_AES);
+ }
+ else {
+ _zip_buffer_put_16(buffer, (zip_uint16_t)de->comp_method);
+ }
_zip_u2d_time(de->last_mod, &dostime, &dosdate);
_zip_buffer_put_16(buffer, dostime);
_zip_buffer_put_16(buffer, dosdate);
- _zip_buffer_put_32(buffer, de->crc);
+ if (is_winzip_aes && de->uncomp_size < 20) {
+ _zip_buffer_put_32(buffer, 0);
+ }
+ else {
+ _zip_buffer_put_32(buffer, de->crc);
+ }
if (((flags & ZIP_FL_LOCAL) == ZIP_FL_LOCAL) && ((de->comp_size >= ZIP_UINT32_MAX) || (de->uncomp_size >= ZIP_UINT32_MAX))) {
/* In local headers, if a ZIP64 EF is written, it MUST contain
diff --git a/lib/zip_file_set_encryption.c b/lib/zip_file_set_encryption.c
new file mode 100644
index 0000000..9ef09f3
--- /dev/null
+++ b/lib/zip_file_set_encryption.c
@@ -0,0 +1,115 @@
+/*
+ zip_file_set_encryption.c -- set encryption for file in archive
+ Copyright (C) 2016 Dieter Baron and Thomas Klausner
+
+ This file is part of libzip, a library to manipulate ZIP archives.
+ The authors can be contacted at <libzip@nih.at>
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ 3. The names of the authors may not be used to endorse or promote
+ products derived from this software without specific prior
+ written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS
+ OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#include "zipint.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+ZIP_EXTERN int
+zip_file_set_encryption(zip_t *za, zip_uint64_t idx, zip_uint16_t method, const char *password)
+{
+ zip_entry_t *e;
+ zip_uint16_t old_method;
+
+ if (idx >= za->nentry) {
+ zip_error_set(&za->error, ZIP_ER_INVAL, 0);
+ return -1;
+ }
+
+ if (ZIP_IS_RDONLY(za)) {
+ zip_error_set(&za->error, ZIP_ER_RDONLY, 0);
+ return -1;
+ }
+
+ if (_zip_get_encryption_implementation(method, ZIP_CODEC_ENCODE) == NULL) {
+ zip_error_set(&za->error, ZIP_ER_COMPNOTSUPP, 0);
+ return -1;
+ }
+
+ e = za->entry+idx;
+
+ old_method = (e->orig == NULL ? ZIP_EM_NONE : e->orig->encryption_method);
+
+ if (method == old_method && password == NULL) {
+ if (e->changes) {
+ if (e->changes->changed & ZIP_DIRENT_PASSWORD) {
+ _zip_crypto_clear(e->changes->password, strlen(e->changes->password));
+ free(e->changes->password);
+ e->changes->password = e->orig->password;
+ }
+ e->changes->changed &= ~(ZIP_DIRENT_ENCRYPTION_METHOD|ZIP_DIRENT_PASSWORD);
+ if (e->changes->changed == 0) {
+ _zip_dirent_free(e->changes);
+ e->changes = NULL;
+ }
+ }
+ }
+ else {
+ char *our_password = NULL;
+
+ if (password) {
+ if ((our_password = strdup(password)) == NULL) {
+ zip_error_set(&za->error, ZIP_ER_MEMORY, 0);
+ return -1;
+ }
+ }
+
+ if (e->changes == NULL) {
+ if ((e->changes=_zip_dirent_clone(e->orig)) == NULL) {
+ _zip_crypto_clear(our_password, strlen(our_password));
+ free(our_password);
+ zip_error_set(&za->error, ZIP_ER_MEMORY, 0);
+ return -1;
+ }
+ }
+
+ e->changes->encryption_method = method;
+ e->changes->changed |= ZIP_DIRENT_ENCRYPTION_METHOD;
+ if (password) {
+ e->changes->password = our_password;
+ e->changes->changed |= ZIP_DIRENT_PASSWORD;
+ }
+ else {
+ if (e->changes->changed & ZIP_DIRENT_PASSWORD) {
+ _zip_crypto_clear(e->changes->password, strlen(e->changes->password));
+ free(e->changes->password);
+ e->changes->password = e->orig->password;
+ e->changes->changed &= ~ZIP_DIRENT_PASSWORD;
+ }
+ }
+ }
+
+ return 0;
+}
diff --git a/lib/zip_get_compression_implementation.c b/lib/zip_get_compression_implementation.c
index c1120d3..cd96339 100644
--- a/lib/zip_get_compression_implementation.c
+++ b/lib/zip_get_compression_implementation.c
@@ -36,7 +36,7 @@
zip_compression_implementation
-_zip_get_compression_implementation(zip_int32_t cm)
+_zip_get_compression_implementation(zip_int32_t cm, int operation)
{
if (cm == ZIP_CM_DEFLATE || ZIP_CM_IS_DEFAULT(cm))
return zip_source_deflate;
diff --git a/lib/zip_get_encryption_implementation.c b/lib/zip_get_encryption_implementation.c
index 96e939c..f8af7b0 100644
--- a/lib/zip_get_encryption_implementation.c
+++ b/lib/zip_get_encryption_implementation.c
@@ -1,6 +1,6 @@
/*
zip_get_encryption_implementation.c -- get encryption implementation
- Copyright (C) 2009-2014 Dieter Baron and Thomas Klausner
+ Copyright (C) 2009-2016 Dieter Baron and Thomas Klausner
This file is part of libzip, a library to manipulate ZIP archives.
The authors can be contacted at <libzip@nih.at>
@@ -36,16 +36,19 @@
zip_encryption_implementation
-_zip_get_encryption_implementation(zip_uint16_t em)
+_zip_get_encryption_implementation(zip_uint16_t em, int operation)
{
switch (em) {
case ZIP_EM_TRAD_PKWARE:
+ if (operation == ZIP_CODEC_ENCODE) {
+ return NULL;
+ }
return zip_source_pkware;
case ZIP_EM_AES_128:
case ZIP_EM_AES_192:
case ZIP_EM_AES_256:
- return zip_source_winzip_aes;
+ return operation == ZIP_CODEC_DECODE ? zip_source_winzip_aes_decode : zip_source_winzip_aes_encode;
default:
return NULL;
diff --git a/lib/zip_random_unix.c b/lib/zip_random_unix.c
new file mode 100644
index 0000000..ee016ac
--- /dev/null
+++ b/lib/zip_random_unix.c
@@ -0,0 +1,55 @@
+/*
+ zip_random_unix.c -- fill the user's buffer with random stuff (Unix version)
+ Copyright (C) 2016 Dieter Baron and Thomas Klausner
+
+ This file is part of libzip, a library to manipulate ZIP archives.
+ The authors can be contacted at <libzip@nih.at>
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ 3. The names of the authors may not be used to endorse or promote
+ products derived from this software without specific prior
+ written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS
+ OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "zipint.h"
+
+#include <fcntl.h>
+
+bool
+zip_random(zip_uint8_t *buffer, zip_uint16_t length)
+{
+ int fd;
+ int len_ret;
+
+ if ((fd = open("/dev/urandom", O_RDONLY)) < 0) {
+ return false;
+ }
+
+ if (read(fd, buffer, length) != length) {
+ close(fd);
+ return false;
+ }
+
+ close(fd);
+ return true;
+}
diff --git a/lib/zip_random_unix.c~ b/lib/zip_random_unix.c~
new file mode 100644
index 0000000..1a7fab2
--- /dev/null
+++ b/lib/zip_random_unix.c~
@@ -0,0 +1,51 @@
+/*
+ zip_random.c -- fill the user's buffer with random stuff
+ Copyright (C) 2016 Dieter Baron and Thomas Klausner
+
+ This file is part of libzip, a library to manipulate ZIP archives.
+ The authors can be contacted at <libzip@nih.at>
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ 3. The names of the authors may not be used to endorse or promote
+ products derived from this software without specific prior
+ written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS
+ OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+bool
+zip_random(zip_uint8_t *buffer, zip_uint16_t length)
+{
+ int fd;
+ int len_ret;
+
+ if ((fd = open("/dev/urandom", O_RDONLY)) < 0) {
+ return false;
+ }
+
+ if (read(fd, buffer, length) != length) {
+ close(fd);
+ return false;
+ }
+
+ close(fd);
+ return true;
+}
diff --git a/lib/zip_random_win32.c b/lib/zip_random_win32.c
new file mode 100644
index 0000000..ca1fe5e
--- /dev/null
+++ b/lib/zip_random_win32.c
@@ -0,0 +1,39 @@
+/*
+ zip_random_win32.c -- fill the user's buffer with random stuff (Windows version)
+ Copyright (C) 2016 Dieter Baron and Thomas Klausner
+
+ This file is part of libzip, a library to manipulate ZIP archives.
+ The authors can be contacted at <libzip@nih.at>
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ 3. The names of the authors may not be used to endorse or promote
+ products derived from this software without specific prior
+ written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS
+ OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+bool
+zip_random(zip_uint8_t *buffer, zip_uint16_t length)
+{
+ /* TODO: implement */
+ return false;
+}
diff --git a/lib/zip_random_win32.c~ b/lib/zip_random_win32.c~
new file mode 100644
index 0000000..1a7fab2
--- /dev/null
+++ b/lib/zip_random_win32.c~
@@ -0,0 +1,51 @@
+/*
+ zip_random.c -- fill the user's buffer with random stuff
+ Copyright (C) 2016 Dieter Baron and Thomas Klausner
+
+ This file is part of libzip, a library to manipulate ZIP archives.
+ The authors can be contacted at <libzip@nih.at>
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ 3. The names of the authors may not be used to endorse or promote
+ products derived from this software without specific prior
+ written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS
+ OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+bool
+zip_random(zip_uint8_t *buffer, zip_uint16_t length)
+{
+ int fd;
+ int len_ret;
+
+ if ((fd = open("/dev/urandom", O_RDONLY)) < 0) {
+ return false;
+ }
+
+ if (read(fd, buffer, length) != length) {
+ close(fd);
+ return false;
+ }
+
+ close(fd);
+ return true;
+}
diff --git a/lib/zip_source_error.c b/lib/zip_source_error.c
index e09199b..e9f050d 100644
--- a/lib/zip_source_error.c
+++ b/lib/zip_source_error.c
@@ -40,3 +40,9 @@
{
return &src->error;
}
+
+bool
+_zip_source_had_error(zip_source_t *src)
+{
+ return zip_source_error(src)->zip_err != ZIP_ER_OK;
+}
diff --git a/lib/zip_source_function.c b/lib/zip_source_function.c
index 1d4be93..345959e 100644
--- a/lib/zip_source_function.c
+++ b/lib/zip_source_function.c
@@ -94,6 +94,7 @@
src->source_archive = NULL;
src->refcount = 1;
zip_error_init(&src->error);
+ src->eof = false;
return src;
}
diff --git a/lib/zip_source_open.c b/lib/zip_source_open.c
index ec5e39d..a621995 100644
--- a/lib/zip_source_open.c
+++ b/lib/zip_source_open.c
@@ -67,6 +67,8 @@
}
}
+ src->eof = false;
+ _zip_error_clear(&src->error);
src->open_count++;
return 0;
diff --git a/lib/zip_source_read.c b/lib/zip_source_read.c
index 061a6f9..88edd65 100644
--- a/lib/zip_source_read.c
+++ b/lib/zip_source_read.c
@@ -38,6 +38,9 @@
zip_int64_t
zip_source_read(zip_source_t *src, void *data, zip_uint64_t len)
{
+ zip_uint64_t bytes_read;
+ zip_int64_t n;
+
if (src->source_closed) {
return -1;
}
@@ -46,5 +49,39 @@
return -1;
}
- return _zip_source_call(src, data, len, ZIP_SOURCE_READ);
+ if (_zip_source_had_error(src)) {
+ return -1;
+ }
+
+ if (_zip_source_eof(src)) {
+ return 0;
+ }
+
+ bytes_read = 0;
+ while (bytes_read < len) {
+ if ((n = _zip_source_call(src, data + bytes_read, len - bytes_read, ZIP_SOURCE_READ)) < 0) {
+ if (bytes_read == 0) {
+ return -1;
+ }
+ else {
+ return bytes_read;
+ }
+ }
+
+ if (n == 0) {
+ src->eof = 1;
+ break;
+ }
+
+ bytes_read += (zip_uint64_t)n;
+ }
+
+ return (zip_int64_t)bytes_read;
+}
+
+
+bool
+_zip_source_eof(zip_source_t *src)
+{
+ return src->eof;
}
diff --git a/lib/zip_source_winzip_aes.c b/lib/zip_source_winzip_aes_decode.c
similarity index 98%
rename from lib/zip_source_winzip_aes.c
rename to lib/zip_source_winzip_aes_decode.c
index 66a6a00..e083f95 100644
--- a/lib/zip_source_winzip_aes.c
+++ b/lib/zip_source_winzip_aes_decode.c
@@ -63,7 +63,7 @@
zip_source_t *
-zip_source_winzip_aes(zip_t *za, zip_source_t *src, zip_uint16_t em, int flags, const char *password)
+zip_source_winzip_aes_decode(zip_t *za, zip_source_t *src, zip_uint16_t em, int flags, const char *password)
{
zip_source_t *s2;
int mode = 0;
diff --git a/lib/zip_source_winzip_aes.c b/lib/zip_source_winzip_aes_encode.c
similarity index 65%
copy from lib/zip_source_winzip_aes.c
copy to lib/zip_source_winzip_aes_encode.c
index 66a6a00..eab2964 100644
--- a/lib/zip_source_winzip_aes.c
+++ b/lib/zip_source_winzip_aes_encode.c
@@ -47,31 +47,31 @@
struct winzip_aes {
char *password;
int mode;
+ zip_uint16_t encryption_method;
- zip_uint64_t data_length;
- zip_uint64_t current_position;
+ zip_uint8_t data[MAX_HEADER_LENGTH];
+ zip_buffer_t *buffer;
fcrypt_ctx fcrypt_ctx;
+ bool eof;
zip_error_t error;
};
-static int decrypt_header(zip_source_t *src, struct winzip_aes *ctx);
+static int encrypt_header(zip_source_t *src, struct winzip_aes *ctx);
static void winzip_aes_free(struct winzip_aes *);
-static zip_int64_t winzip_aes_decrypt(zip_source_t *src, void *ud, void *data, zip_uint64_t len, zip_source_cmd_t cmd);
-static struct winzip_aes * winzip_aes_new(int mode, const char *password);
+static zip_int64_t winzip_aes_encrypt(zip_source_t *src, void *ud, void *data, zip_uint64_t len, zip_source_cmd_t cmd);
+static struct winzip_aes * winzip_aes_new(int mode, zip_uint16_t encryption_method, const char *password);
zip_source_t *
-zip_source_winzip_aes(zip_t *za, zip_source_t *src, zip_uint16_t em, int flags, const char *password)
+zip_source_winzip_aes_encode(zip_t *za, zip_source_t *src, zip_uint16_t encryption_method, int flags, const char *password)
{
zip_source_t *s2;
int mode = 0;
- zip_stat_t st;
- zip_uint64_t aux_length;
struct winzip_aes *ctx;
- switch (em) {
+ switch (encryption_method) {
case ZIP_EM_AES_128:
mode = 1;
break;
@@ -87,31 +87,13 @@
zip_error_set(&za->error, ZIP_ER_INVAL, 0);
return NULL;
}
- if (flags & ZIP_CODEC_ENCODE) {
- zip_error_set(&za->error, ZIP_ER_ENCRNOTSUPP, 0);
- return NULL;
- }
- if (zip_source_stat(src, &st) != 0) {
- _zip_error_set_from_source(&za->error, src);
- return NULL;
- }
-
- aux_length = PWD_VER_LENGTH + salt_length[mode] + HMAC_LENGTH;
-
- if ((st.valid & ZIP_STAT_COMP_SIZE) == 0 || st.comp_size < aux_length) {
- zip_error_set(&za->error, ZIP_ER_OPNOTSUPP, 0);
- return NULL;
- }
-
- if ((ctx = winzip_aes_new(mode, password)) == NULL) {
+ if ((ctx = winzip_aes_new(mode, encryption_method, password)) == NULL) {
zip_error_set(&za->error, ZIP_ER_MEMORY, 0);
return NULL;
}
- ctx->data_length = st.comp_size - aux_length;
-
- if ((s2 = zip_source_layered(za, src, winzip_aes_decrypt, ctx)) == NULL) {
+ if ((s2 = zip_source_layered(za, src, winzip_aes_encrypt, ctx)) == NULL) {
winzip_aes_free(ctx);
return NULL;
}
@@ -121,33 +103,23 @@
static int
-decrypt_header(zip_source_t *src, struct winzip_aes *ctx)
+encrypt_header(zip_source_t *src, struct winzip_aes *ctx)
{
- zip_uint8_t header[MAX_HEADER_LENGTH];
- zip_uint8_t password_verification[PWD_VER_LENGTH];
- zip_uint8_t headerlen;
- zip_int64_t n;
- unsigned char key[16];
-
- headerlen = PWD_VER_LENGTH + salt_length[ctx->mode];
- if ((n=zip_source_read(src, header, headerlen)) < 0) {
- _zip_error_set_from_source(&ctx->error, src);
+ if (!zip_random(ctx->data, salt_length[ctx->mode])) {
+ zip_error_set(&ctx->error, ZIP_ER_INTERNAL, 0);
return -1;
- }
+ }
- if (n != headerlen) {
- zip_error_set(&ctx->error, ZIP_ER_EOF, 0);
- return -1;
- }
-
- if (_zip_fcrypt_init(ctx->mode, ctx->password, strlen(ctx->password), header, password_verification, &ctx->fcrypt_ctx) != 0) {
+ if (_zip_fcrypt_init(ctx->mode, ctx->password, strlen(ctx->password), ctx->data, ctx->data+salt_length[ctx->mode], &ctx->fcrypt_ctx) != 0) {
zip_error_set(&ctx->error, ZIP_ER_MEMORY, 0);
return -1;
}
- if (memcmp(password_verification, header + salt_length[ctx->mode], PWD_VER_LENGTH) != 0) {
- zip_error_set(&ctx->error, ZIP_ER_WRONGPASSWD, 0);
+
+ if ((ctx->buffer = _zip_buffer_new(ctx->data, salt_length[ctx->mode] + PWD_VER_LENGTH)) == NULL) {
+ zip_error_set(&ctx->error, ZIP_ER_MEMORY, 0);
return -1;
}
+
return 0;
}
@@ -173,43 +145,62 @@
static zip_int64_t
-winzip_aes_decrypt(zip_source_t *src, void *ud, void *data, zip_uint64_t len, zip_source_cmd_t cmd)
+winzip_aes_encrypt(zip_source_t *src, void *ud, void *data, zip_uint64_t length, zip_source_cmd_t cmd)
{
struct winzip_aes *ctx;
- zip_int64_t n;
+ zip_int64_t ret;
+ zip_uint64_t buffer_n, offset, n;
ctx = (struct winzip_aes *)ud;
switch (cmd) {
case ZIP_SOURCE_OPEN:
- if (decrypt_header(src, ctx) < 0) {
+ ctx->eof = false;
+ if (encrypt_header(src, ctx) < 0) {
return -1;
}
- ctx->current_position = 0;
return 0;
case ZIP_SOURCE_READ:
- if (len > ctx->data_length - ctx->current_position) {
- len = ctx->data_length - ctx->current_position;
+ buffer_n = 0;
+
+ if (ctx->buffer) {
+ buffer_n = _zip_buffer_read(ctx->buffer, data, length);
+
+ data += buffer_n;
+ length -= buffer_n;
+
+ if (_zip_buffer_eof(ctx->buffer)) {
+ _zip_buffer_free(ctx->buffer);
+ ctx->buffer = NULL;
+ }
}
- if (len == 0) {
- if (!verify_hmac(src, ctx)) {
- return -1;
- }
- return 0;
+ if (ctx->eof) {
+ return buffer_n;
}
-
- if ((n=zip_source_read(src, data, len)) < 0) {
+
+ if ((ret = zip_source_read(src, data, length)) < 0) {
_zip_error_set_from_source(&ctx->error, src);
return -1;
}
- ctx->current_position += n;
- /* TODO: loop if len > UINT_MAX */
- _zip_fcrypt_decrypt(data, n, &ctx->fcrypt_ctx);
+ n = (zip_uint64_t)ret;
+ for (offset = 0; offset < n; offset += ZIP_MIN(n - offset, UINT_MAX)) {
+ _zip_fcrypt_encrypt(data + offset, ZIP_MIN(n - offset, UINT_MAX), &ctx->fcrypt_ctx);
+ }
- return n;
+ if (n < length) {
+ ctx->eof = true;
+ _zip_fcrypt_end(ctx->data, &ctx->fcrypt_ctx);
+ if ((ctx->buffer = _zip_buffer_new(ctx->data, HMAC_LENGTH)) == NULL) {
+ zip_error_set(&ctx->error, ZIP_ER_MEMORY, 0);
+ /* TODO: return partial read? */
+ return -1;
+ }
+ }
+
+ return (zip_int64_t)(buffer_n + n);
case ZIP_SOURCE_CLOSE:
return 0;
@@ -219,11 +210,10 @@
zip_stat_t *st;
st = (zip_stat_t *)data;
-
- st->encryption_method = ZIP_EM_NONE;
+ st->encryption_method = ctx->encryption_method;
st->valid |= ZIP_STAT_ENCRYPTION_METHOD;
if (st->valid & ZIP_STAT_COMP_SIZE) {
- st->comp_size -= 12 + salt_length[ctx->mode];
+ st->comp_size += 12 + salt_length[ctx->mode];
}
return 0;
@@ -233,7 +223,7 @@
return zip_source_make_command_bitmap(ZIP_SOURCE_OPEN, ZIP_SOURCE_READ, ZIP_SOURCE_CLOSE, ZIP_SOURCE_STAT, ZIP_SOURCE_ERROR, ZIP_SOURCE_FREE, -1);
case ZIP_SOURCE_ERROR:
- return zip_error_to_data(&ctx->error, data, len);
+ return zip_error_to_data(&ctx->error, data, length);
case ZIP_SOURCE_FREE:
winzip_aes_free(ctx);
@@ -257,12 +247,13 @@
_zip_crypto_clear(ctx->password, strlen(ctx->password));
free(ctx->password);
zip_error_fini(&ctx->error);
+ _zip_buffer_free(ctx->buffer);
free(ctx);
}
static struct winzip_aes *
-winzip_aes_new(int mode, const char *password) {
+winzip_aes_new(int mode, zip_uint16_t encryption_method, const char *password) {
struct winzip_aes *ctx;
if ((ctx = (struct winzip_aes *)malloc(sizeof(*ctx))) == NULL) {
@@ -275,8 +266,11 @@
}
ctx->mode = mode;
+ ctx->encryption_method = encryption_method;
+ ctx->buffer = NULL;
zip_error_init(&ctx->error);
+ ctx->eof = false;
return ctx;
}
diff --git a/lib/zip_source_zip_new.c b/lib/zip_source_zip_new.c
index 40f1195..3d6c342 100644
--- a/lib/zip_source_zip_new.c
+++ b/lib/zip_source_zip_new.c
@@ -85,7 +85,7 @@
zip_error_set(&za->error, ZIP_ER_NOPASSWD, 0);
return NULL;
}
- if ((enc_impl=_zip_get_encryption_implementation(st.encryption_method)) == NULL) {
+ if ((enc_impl=_zip_get_encryption_implementation(st.encryption_method, ZIP_CODEC_DECODE)) == NULL) {
zip_error_set(&za->error, ZIP_ER_ENCRNOTSUPP, 0);
return NULL;
}
@@ -94,7 +94,7 @@
comp_impl = NULL;
if ((flags & ZIP_FL_COMPRESSED) == 0) {
if (st.comp_method != ZIP_CM_STORE) {
- if ((comp_impl=_zip_get_compression_implementation(st.comp_method)) == NULL) {
+ if ((comp_impl=_zip_get_compression_implementation(st.comp_method, ZIP_CODEC_DECODE)) == NULL) {
zip_error_set(&za->error, ZIP_ER_COMPNOTSUPP, 0);
return NULL;
}
diff --git a/lib/zipint.h b/lib/zipint.h
index fe62208..6d16caf 100644
--- a/lib/zipint.h
+++ b/lib/zipint.h
@@ -64,6 +64,7 @@
#define CDBUFSIZE (MAXCOMLEN+EOCDLEN+EOCD64LOCLEN)
#define BUFSIZE 8192
#define EFZIP64SIZE 28
+#define EF_WINZIP_AES_SIZE 7
#define ZIP_CM_REPLACED_DEFAULT (-2)
#define ZIP_CM_WINZIP_AES 99 /* Winzip AES encrypted */
@@ -98,8 +99,8 @@
typedef zip_source_t *(*zip_compression_implementation)(zip_t *, zip_source_t *, zip_int32_t, int);
typedef zip_source_t *(*zip_encryption_implementation)(zip_t *, zip_source_t *, zip_uint16_t, int, const char *);
-zip_compression_implementation _zip_get_compression_implementation(zip_int32_t);
-zip_encryption_implementation _zip_get_encryption_implementation(zip_uint16_t);
+zip_compression_implementation _zip_get_compression_implementation(zip_int32_t method, int operation);
+zip_encryption_implementation _zip_get_encryption_implementation(zip_uint16_t method, int operation);
@@ -120,7 +121,8 @@
int zip_source_remove(zip_source_t *);
zip_int64_t zip_source_supports(zip_source_t *src);
zip_source_t *zip_source_window(zip_t *, zip_source_t *, zip_uint64_t, zip_uint64_t);
-zip_source_t *zip_source_winzip_aes(zip_t *, zip_source_t *, zip_uint16_t, int, const char *);
+zip_source_t *zip_source_winzip_aes_decode(zip_t *, zip_source_t *, zip_uint16_t, int, const char *);
+zip_source_t *zip_source_winzip_aes_encode(zip_t *, zip_source_t *, zip_uint16_t, int, const char *);
/* error source for layered sources */
@@ -211,13 +213,15 @@
/* zip archive directory entry (central or local) */
-#define ZIP_DIRENT_COMP_METHOD 0x0001u
-#define ZIP_DIRENT_FILENAME 0x0002u
-#define ZIP_DIRENT_COMMENT 0x0004u
-#define ZIP_DIRENT_EXTRA_FIELD 0x0008u
-#define ZIP_DIRENT_ATTRIBUTES 0x0010u
-#define ZIP_DIRENT_LAST_MOD 0x0020u
-#define ZIP_DIRENT_ALL 0xffffu
+#define ZIP_DIRENT_COMP_METHOD 0x0001u
+#define ZIP_DIRENT_FILENAME 0x0002u
+#define ZIP_DIRENT_COMMENT 0x0004u
+#define ZIP_DIRENT_EXTRA_FIELD 0x0008u
+#define ZIP_DIRENT_ATTRIBUTES 0x0010u
+#define ZIP_DIRENT_LAST_MOD 0x0020u
+#define ZIP_DIRENT_ENCRYPTION_METHOD 0x0040u
+#define ZIP_DIRENT_PASSWORD 0x0080u
+#define ZIP_DIRENT_ALL ZIP_UINT32_MAX
struct zip_dirent {
zip_uint32_t changed;
@@ -243,6 +247,7 @@
zip_uint64_t offset; /* (c) offset of local header */
zip_uint16_t encryption_method; /* encryption method, computed from other fields */
+ char *password; /* file specific encryption password */
};
/* zip archive central directory */
@@ -288,6 +293,7 @@
bool source_closed; /* set if source archive is closed */
zip_t *source_archive; /* zip archive we're reading from, NULL if not from archive */
unsigned int refcount;
+ bool eof; /* EOF reached */
};
#define ZIP_SOURCE_IS_OPEN_READING(src) ((src)->open_count > 0)
@@ -340,6 +346,8 @@
extern const int _zip_nerr_str;
extern const int _zip_err_type[];
+#define ZIP_MAX(a, b) ((a) > (b) ? (a) : (b))
+#define ZIP_MIN(a, b) ((a) < (b) ? (a) : (b))
#define ZIP_ENTRY_CHANGED(e, f) ((e)->changes && ((e)->changes->changed & (f)))
@@ -380,6 +388,7 @@
int _zip_buffer_put_32(zip_buffer_t *buffer, zip_uint32_t i);
int _zip_buffer_put_64(zip_buffer_t *buffer, zip_uint64_t i);
int _zip_buffer_put_8(zip_buffer_t *buffer, zip_uint8_t i);
+zip_uint64_t _zip_buffer_read(zip_buffer_t *buffer, zip_uint8_t *data, zip_uint64_t length);
int _zip_buffer_skip(zip_buffer_t *buffer, zip_uint64_t length);
int _zip_buffer_set_offset(zip_buffer_t *buffer, zip_uint64_t offset);
zip_uint64_t _zip_buffer_size(zip_buffer_t *buffer);
@@ -443,6 +452,8 @@
zip_t *_zip_open(zip_source_t *, unsigned int, zip_error_t *);
+bool zip_random(zip_uint8_t *buffer, zip_uint16_t length);
+
int _zip_read(zip_source_t *src, zip_uint8_t *data, zip_uint64_t length, zip_error_t *error);
int _zip_read_at_offset(zip_source_t *src, zip_uint64_t offset, unsigned char *b, size_t length, zip_error_t *error);
zip_uint8_t *_zip_read_data(zip_buffer_t *buffer, zip_source_t *src, size_t length, bool nulp, zip_error_t *error);
@@ -453,8 +464,10 @@
void _zip_set_open_error(int *zep, const zip_error_t *err, int ze);
zip_int64_t _zip_source_call(zip_source_t *src, void *data, zip_uint64_t length, zip_source_cmd_t command);
+bool _zip_source_eof(zip_source_t *);
zip_source_t *_zip_source_file_or_p(const char *, FILE *, zip_uint64_t, zip_int64_t, const zip_stat_t *, zip_error_t *error);
void _zip_source_invalidate(zip_source_t *src);
+bool _zip_source_had_error(zip_source_t *);
zip_source_t *_zip_source_new(zip_error_t *error);
int _zip_source_set_source_archive(zip_source_t *, zip_t *);
zip_source_t *_zip_source_window_new(zip_source_t *src, zip_uint64_t start, zip_uint64_t length, zip_stat_t *st, zip_error_t *error);