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); }