Decryption improvements: - Implement zip_set_default_password(). - Fix ZIP_SOURCE_STAT in file source. - Fix error returns for pkware decryption. XXX: Actually decrypting still fails. --HG-- branch : HEAD
diff --git a/lib/Makefile.am b/lib/Makefile.am index 68dbaf8..e4baef8 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am
@@ -52,6 +52,7 @@ zip_replace.c \ zip_set_archive_comment.c \ zip_set_archive_flag.c \ + zip_set_default_password.c \ zip_set_file_comment.c \ zip_source_buffer.c \ zip_source_call.c \
diff --git a/lib/zip.h b/lib/zip.h index 26350d9..4a764de 100644 --- a/lib/zip.h +++ b/lib/zip.h
@@ -235,6 +235,7 @@ ZIP_EXTERN int zip_replace(struct zip *, zip_uint64_t, struct zip_source *); ZIP_EXTERN int zip_set_archive_comment(struct zip *, const char *, int); ZIP_EXTERN int zip_set_archive_flag(struct zip *, int, int); +ZIP_EXTERN int zip_set_default_password(struct zip *, const char *); ZIP_EXTERN int zip_set_file_comment(struct zip *, zip_uint64_t, const char *, int); ZIP_EXTERN struct zip_source *zip_source_buffer(struct zip *, const void *,
diff --git a/lib/zip_fopen_index_encrypted.c b/lib/zip_fopen_index_encrypted.c index 4e01958..0abbcef 100644 --- a/lib/zip_fopen_index_encrypted.c +++ b/lib/zip_fopen_index_encrypted.c
@@ -83,6 +83,10 @@ enc_impl = NULL; if ((flags & ZIP_FL_ENCRYPTED) == 0) { if (st.encryption_method != ZIP_EM_NONE) { + if (password == NULL) { + _zip_error_set(&za->error, ZIP_ER_NOPASSWD, 0); + return NULL; + } if ((enc_impl=zip_get_encryption_implementation( st.encryption_method)) == NULL) { _zip_error_set(&za->error, ZIP_ER_ENCRNOTSUPP, 0); @@ -117,6 +121,7 @@ if ((s2=enc_impl(za, src, ZIP_EM_TRAD_PKWARE, 0, password)) == NULL) { zip_source_free(src); + /* XXX: set error (how?) */ return NULL; } src = s2; @@ -125,6 +130,7 @@ if ((s2=comp_impl(za, src, za->cdir->entry[fileno].comp_method, 0)) == NULL) { zip_source_free(src); + /* XXX: set error (how?) */ return NULL; } src = s2; @@ -132,6 +138,12 @@ } if (zip_source_call(src, NULL, 0, ZIP_SOURCE_OPEN) < 0) { + int e[2]; + + if (zip_source_call(src, e, sizeof(e), ZIP_SOURCE_ERROR) < 0) + _zip_error_set(&za->error, ZIP_ER_INTERNAL, 0); + else + _zip_error_set(&za->error, e[0], e[1]); zip_source_free(src); return NULL; }
diff --git a/lib/zip_set_default_password.c b/lib/zip_set_default_password.c new file mode 100644 index 0000000..eb02c34 --- /dev/null +++ b/lib/zip_set_default_password.c
@@ -0,0 +1,59 @@ +/* + zip_set_default_password.c -- set default password for decryption + Copyright (C) 2009 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 <stdlib.h> +#include <string.h> + +#include "zipint.h" + + + +ZIP_EXTERN int +zip_set_default_password(struct zip *za, const char *passwd) +{ + if (za->default_password) + free(za->default_password); + + if (passwd) { + if ((za->default_password=strdup(passwd)) == NULL) { + _zip_error_set(&za->error, ZIP_ER_MEMORY, 0); + return -1; + } + } + else + za->default_password = NULL; + + return 0; +}
diff --git a/lib/zip_source_filep.c b/lib/zip_source_filep.c index 7020dd6..a3ac7e3 100644 --- a/lib/zip_source_filep.c +++ b/lib/zip_source_filep.c
@@ -187,16 +187,16 @@ case ZIP_SOURCE_STAT: { - struct zip_stat *st; - struct stat fst; - int err; - - if (len < sizeof(*st)) + if (len < sizeof(z->st)) return -1; if (z->st.size != -1) - memcpy(st, &z->st, sizeof(st)); + memcpy(data, &z->st, sizeof(z->st)); else { + struct zip_stat *st; + struct stat fst; + int err; + if (z->f) err = fstat(fileno(z->f), &fst); else @@ -217,7 +217,7 @@ else if ((fst.st_mode&S_IFMT) == S_IFREG) st->size = fst.st_size; } - return sizeof(*st); + return sizeof(z->st); } case ZIP_SOURCE_ERROR:
diff --git a/lib/zip_source_pkware.c b/lib/zip_source_pkware.c index 8b1c749..26e1160 100644 --- a/lib/zip_source_pkware.c +++ b/lib/zip_source_pkware.c
@@ -53,7 +53,7 @@ static void decrypt(struct trad_pkware *, zip_uint8_t *, - const zip_uint8_t *, zip_uint64_t); + const zip_uint8_t *, zip_uint64_t, int); static int decrypt_header(struct trad_pkware *); static zip_int64_t pkware_decrypt(void *, void *, zip_uint64_t, enum zip_source_cmd); @@ -66,7 +66,7 @@ struct trad_pkware *ctx; if (za == NULL || password == NULL || src == NULL - || em != ZIP_EM_TRAD_PKWARE || (flags & ZIP_CODEC_ENCODE) == 0) { + || em != ZIP_EM_TRAD_PKWARE || (flags & ZIP_CODEC_ENCODE)) { _zip_error_set(&za->error, ZIP_ER_INVAL, 0); return NULL; } @@ -82,7 +82,7 @@ ctx->key[0] = KEY0; ctx->key[1] = KEY1; ctx->key[2] = KEY2; - decrypt(ctx, NULL, (const zip_uint8_t *)password, strlen(password)); + decrypt(ctx, NULL, (const zip_uint8_t *)password, strlen(password), 1); return zip_source_function(za, pkware_decrypt, ctx); } @@ -91,20 +91,23 @@ static void decrypt(struct trad_pkware *ctx, zip_uint8_t *out, const zip_uint8_t *in, - zip_uint64_t len) + zip_uint64_t len, int update_only) { - zip_uint16_t clr; + zip_uint16_t tmp; zip_uint64_t i; Bytef b; for (i=0; i<len; i++) { - /* decrypt next byte */ - clr = ctx->key[2] || 2; - clr = (clr * (clr ^ 1)) >> 8; - clr = in[i] ^ clr; + b = in[i]; + + if (!update_only) { + /* decrypt next byte */ + tmp = ctx->key[2] || 2; + tmp = (tmp * (tmp ^ 1)) >> 8; + b ^= tmp; + } /* update keys */ - b = clr; ctx->key[0] = crc32(ctx->key[0], &b, 1); ctx->key[1] = (ctx->key[1] + (ctx->key[0] & 0xff)) * 134775813 + 1; b = ctx->key[1] >> 24; @@ -112,7 +115,7 @@ /* store cleartext */ if (out) - out[i] = clr; + out[i] = b; } } @@ -136,7 +139,7 @@ return -1; } - decrypt(ctx, header, header, HEADERLEN); + decrypt(ctx, header, header, HEADERLEN, 0); if (zip_source_call(ctx->src, &st, sizeof(st), ZIP_SOURCE_STAT) < 0 || st.crc == 0) { @@ -147,6 +150,7 @@ if (header[HEADERLEN-1] != st.crc>>24) { ctx->e[0] = ZIP_ER_WRONGPASSWD; ctx->e[1] = 0; + return -1; } return 0; @@ -177,7 +181,8 @@ zip_source_call(ctx->src, ctx->e, sizeof(ctx->e), ZIP_SOURCE_ERROR); return -1; } - decrypt(ud, (zip_uint8_t *)data, (zip_uint8_t *)data, (zip_uint64_t)n); + decrypt(ud, (zip_uint8_t *)data, (zip_uint8_t *)data, (zip_uint64_t)n, + 0); return n; case ZIP_SOURCE_CLOSE: