Winzip AES encryption support for writing.
diff --git a/TODO.md b/TODO.md
index 928a97c..902ac6b 100644
--- a/TODO.md
+++ b/TODO.md
@@ -35,10 +35,9 @@
# Features
* Winzip AES support
- * encryption
- * don't write CRC if file too small
- * write EF 0x9901
- * test cases: correct pw, wrong pw, 128/192/256, <=20, >20
+ * test cases decryption: correct password, wrong password, no password, 128/192/256, <=20, >20
+ * test cases encryption: no password, default password, file-specific password, 128/192/256, <=20, >20
+ * Windows random
* document existence
* xz support
* consistently use `_zip_crypto_clear()` for passwords
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);
diff --git a/man/CMakeLists.txt b/man/CMakeLists.txt
index a8a8e3d..9f893f5 100644
--- a/man/CMakeLists.txt
+++ b/man/CMakeLists.txt
@@ -31,6 +31,9 @@
zip_file_get_error.mdoc
zip_file_rename.mdoc
zip_file_set_comment.mdoc
+ zip_file_set_encryption.mdoc
+ zip_file_set_external_attributes.mdoc
+ zip_file_set_mtime.mdoc
zip_file_strerror.mdoc
zip_fopen.mdoc
zip_fopen_encrypted.mdoc
diff --git a/man/Makefile.am b/man/Makefile.am
index 2ceb27c..4e0cc8e 100644
--- a/man/Makefile.am
+++ b/man/Makefile.am
@@ -40,6 +40,7 @@
zip_file_get_external_attributes.mdoc \
zip_file_rename.mdoc \
zip_file_set_comment.mdoc \
+ zip_file_set_encryption.mdoc \
zip_file_set_external_attributes.mdoc \
zip_file_set_mtime.mdoc \
zip_file_strerror.mdoc \
diff --git a/man/zip_file_set_encryption.mdoc b/man/zip_file_set_encryption.mdoc
new file mode 100644
index 0000000..14fdf98
--- /dev/null
+++ b/man/zip_file_set_encryption.mdoc
@@ -0,0 +1,112 @@
+.\" zip_file_set_encryption.mdoc -- set encryption method for file
+.\" Copyright (C) 2016 Dieter Baron and Thomas Klausner
+.\"
+.\" This file is part of libzip, a library to manipulate ZIP files.
+.\" 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.
+.\"
+.Dd December 16, 2016
+.Dt ZIP_FILE_SET_ENCRYPTION 3
+.Os
+.Sh NAME
+.Nm zip_file_set_encryption
+.Nd set encryption method for file in zip
+.Sh LIBRARY
+libzip (-lzip)
+.Sh SYNOPSIS
+.In zip.h
+.Ft int
+.Fn zip_file_set_encryption "zip_t *archive" "zip_uint64_t index" \
+"zip_int32_t method" "const char *password"
+.Sh DESCRIPTION
+The
+.Fn zip_file_set_encryption
+function sets the encryption method for the file at position
+.Ar index
+in the zip archive to
+.Ar method
+using the password
+.Ar password .
+The
+.Ar method
+is the same as returned by
+.Xr zip_stat 3 .
+For the
+.Ar method
+argument, currently only the following values are supported:
+.Bl -tag -width ZIP_CM_DEFLATE_XX
+.It Dv ZIP_EM_NONE
+No encryption.
+.It Dv ZIP_EM_AES_128
+Winzip AES-128 encryption.
+.It Dv ZIP_EM_AES_192
+Winzip AES-192 encryption.
+.It Dv ZIP_EM_AES_256
+Winzip AES-256 encryption.
+.El
+.Pp
+If
+.Ar password
+is
+.Dv NULL ,
+the default password provided by
+.Xr zip_set_default_password 3
+is used.
+.Pp
+The current encryption method for a file in a zip archive can be
+determined using
+.Xr zip_stat 3 .
+.Sh RETURN VALUES
+Upon successful completion 0 is returned.
+Otherwise, \-1 is returned and the error information in
+.Ar archive
+is set to indicate the error.
+.Sh ERRORS
+.Fn zip_file_set_encryption
+fails if:
+.Bl -tag -width Er
+.It Bq Er ZIP_ER_ENCRNOTSUPP
+Unsupported compression method requested.
+.It Bq Er ZIP_ER_INVAL
+.Ar index
+is not a valid file index in
+.Ar archive ,
+or the argument combination is invalid.
+.It Bq Er ZIP_ER_MEMORY
+Required memory could not be allocated.
+.It Bq Er ZIP_ER_RDONLY
+Read-only zip file, no changes allowed.
+.El
+.Sh SEE ALSO
+.Xr libzip 3 ,
+.Xr zip_set_default_password 3 ,
+.Xr zip_stat 3
+.Sh AUTHORS
+.An -nosplit
+.An Dieter Baron Aq Mt dillo@nih.at
+and
+.An Thomas Klausner Aq Mt tk@giga.or.at
diff --git a/man/zip_source_function.mdoc b/man/zip_source_function.mdoc
index ae8b865..4cdfd44 100644
--- a/man/zip_source_function.mdoc
+++ b/man/zip_source_function.mdoc
@@ -1,5 +1,5 @@
.\" zip_source_function.mdoc -- create data source from function
-.\" Copyright (C) 2004-2014 Dieter Baron and Thomas Klausner
+.\" Copyright (C) 2004-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>
@@ -29,7 +29,7 @@
.\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
.\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
-.Dd November 13, 2014
+.Dd December 16, 2016
.Dt ZIP_SOURCE_FUNCTION 3
.Os
.Sh NAME
@@ -146,7 +146,7 @@
.Ar len .
Return the number of bytes placed into
.Ar data
-on success.
+on success, and zero for end-of-file.
.Ss Dv ZIP_SOURCE_REMOVE
Remove the underlying file.
This is called if a zip archive is empty when closed.
diff --git a/man/zip_source_read.mdoc b/man/zip_source_read.mdoc
index c9a29b9..7fb5d96 100644
--- a/man/zip_source_read.mdoc
+++ b/man/zip_source_read.mdoc
@@ -1,5 +1,5 @@
.\" zip_source_read.mdoc -- read data from zip source
-.\" Copyright (C) 2014 Dieter Baron and Thomas Klausner
+.\" Copyright (C) 2014-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>
@@ -29,7 +29,7 @@
.\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
.\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
-.Dd November 18, 2014
+.Dd December 16, 2016
.Dt ZIP_SOURCE_READ 3
.Os
.Sh NAME
@@ -58,6 +58,7 @@
first.
.Sh RETURN VALUES
Upon successful completion the number of bytes read is returned.
+Upon reading end-of-file, zero is returned.
Otherwise, \-1 is returned and the error information in
.Ar source
is set to indicate the error.
diff --git a/man/ziptool.mdoc b/man/ziptool.mdoc
index ec7a751..4eca252 100644
--- a/man/ziptool.mdoc
+++ b/man/ziptool.mdoc
@@ -29,7 +29,7 @@
.\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
.\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
-.Dd August 25, 2016
+.Dd December 16, 2016
.Dt ZIPTOOL 1
.Os
.Sh NAME
@@ -256,6 +256,13 @@
Currently,
.Ar compression_flags
are ignored.
+.It Cm set_file_encryption Ar index method password
+Set file encryption method for archive entry
+.Ar index
+to
+.Ar method
+with password
+.Ar password .
.It Cm set_file_mtime Ar index timestamp
Set file modification time for archive entry
.Ar index
@@ -304,6 +311,19 @@
.It
.Dv store
.El
+.Ss Encryption Methods
+Some commands take encryption method arguments.
+Supported methods are:
+.Bl -bullet -compact -offset indent
+.It
+.Dv none
+.It
+.Dv AES-128
+.It
+.Dv AES-192
+.It
+.Dv AES-256
+.El
.Sh EXIT STATUS
.Ex -std
.Sh EXAMPLES
diff --git a/src/ziptool.c b/src/ziptool.c
index a0f4be4..63763ce 100644
--- a/src/ziptool.c
+++ b/src/ziptool.c
@@ -71,6 +71,7 @@
static zip_flags_t get_flags(const char *arg);
static zip_int32_t get_compression_method(const char *arg);
+static zip_uint16_t get_encryption_method(const char *arg);
static void hexdump(const zip_uint8_t *data, zip_uint16_t len);
static zip_t *read_to_memory(const char *archive, int flags, zip_error_t *error, zip_source_t **srcp);
static zip_source_t *source_nul(zip_t *za, zip_uint64_t length);
@@ -482,6 +483,24 @@
}
static int
+set_file_encryption(int argc, char *argv[]) {
+ zip_int32_t method;
+ zip_uint64_t idx;
+ char *password;
+ idx = strtoull(argv[0], NULL, 10);
+ method = get_encryption_method(argv[1]);
+ password = argv[2];
+ if (strlen(password) == 0) {
+ password = NULL;
+ }
+ if (zip_file_set_encryption(za, idx, method, password) < 0) {
+ fprintf(stderr, "can't set file encryption method at index '%" PRIu64 "' to `%s': %s\n", idx, argv[1], zip_strerror(za));
+ return -1;
+ }
+ return 0;
+}
+
+static int
set_file_mtime(int argc, char *argv[]) {
/* set file last modification time (mtime) */
time_t mtime;
@@ -617,10 +636,26 @@
return ZIP_CM_DEFAULT;
else if (strcmp(arg, "store") == 0)
return ZIP_CM_STORE;
- else if (strcmp(arg, "deflate") ==0)
+ else if (strcmp(arg, "deflate") == 0)
return ZIP_CM_DEFLATE;
- else if (strcmp(arg, "unknown") ==0)
- return 99;
+ else if (strcmp(arg, "unknown") == 0)
+ return 100;
+ return 0; /* TODO: error handling */
+}
+
+static zip_uint16_t
+get_encryption_method(const char *arg)
+{
+ if (strcmp(arg, "none") == 0)
+ return ZIP_EM_NONE;
+ else if (strcmp(arg, "AES-128") == 0)
+ return ZIP_EM_AES_128;
+ else if (strcmp(arg, "AES-192") == 0)
+ return ZIP_EM_AES_192;
+ else if (strcmp(arg, "AES-256") == 0)
+ return ZIP_EM_AES_256;
+ else if (strcmp(arg, "unknown") == 0)
+ return 100;
return 0; /* TODO: error handling */
}
@@ -898,6 +933,7 @@
{ "set_extra", 5, "index extra_id extra_index flags value", "set extra field", set_extra },
{ "set_file_comment", 2, "index comment", "set file comment", set_file_comment },
{ "set_file_compression", 3, "index method compression_flags", "set file compression method", set_file_compression },
+ { "set_file_encryption", 3, "index method password", "set file encryption method", set_file_encryption },
{ "set_file_mtime", 2, "index timestamp", "set file modification time", set_file_mtime },
{ "set_file_mtime_all", 1, "timestamp", "set file modification time for all files", set_file_mtime_all },
{ "set_password", 1, "password", "set default password for encryption", set_password },
@@ -973,6 +1009,11 @@
"\tdefault\n"
"\tdeflate\n"
"\tstore\n");
+ fprintf(out, "\nSupported compression methods are:\n"
+ "\tnone\n"
+ "\tAES-128\n"
+ "\tAES-192\n"
+ "\tAES-256\n");
fprintf(out, "\nThe index is zero-based.\n");
exit(0);
}