"Fossies" - the Fresh Open Source Software Archive

Member "libzip-1.6.0/lib/zip_source_winzip_aes_decode.c" (24 Jan 2020, 7543 Bytes) of package /linux/misc/libzip-1.6.0.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "zip_source_winzip_aes_decode.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 1.5.2_vs_1.6.0.

    1 /*
    2   zip_source_winzip_aes_decode.c -- Winzip AES decryption routines
    3   Copyright (C) 2009-2019 Dieter Baron and Thomas Klausner
    4 
    5   This file is part of libzip, a library to manipulate ZIP archives.
    6   The authors can be contacted at <libzip@nih.at>
    7 
    8   Redistribution and use in source and binary forms, with or without
    9   modification, are permitted provided that the following conditions
   10   are met:
   11   1. Redistributions of source code must retain the above copyright
   12   notice, this list of conditions and the following disclaimer.
   13   2. Redistributions in binary form must reproduce the above copyright
   14   notice, this list of conditions and the following disclaimer in
   15   the documentation and/or other materials provided with the
   16   distribution.
   17   3. The names of the authors may not be used to endorse or promote
   18   products derived from this software without specific prior
   19   written permission.
   20 
   21   THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS
   22   OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
   23   WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   24   ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
   25   DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   26   DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
   27   GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   28   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
   29   IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
   30   OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
   31   IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   32 */
   33 
   34 
   35 #include <stdlib.h>
   36 #include <string.h>
   37 
   38 #include "zipint.h"
   39 
   40 struct winzip_aes {
   41     char *password;
   42     zip_uint16_t encryption_method;
   43 
   44     zip_uint64_t data_length;
   45     zip_uint64_t current_position;
   46 
   47     zip_winzip_aes_t *aes_ctx;
   48     zip_error_t error;
   49 };
   50 
   51 
   52 static int decrypt_header(zip_source_t *src, struct winzip_aes *ctx);
   53 static void winzip_aes_free(struct winzip_aes *);
   54 static zip_int64_t winzip_aes_decrypt(zip_source_t *src, void *ud, void *data, zip_uint64_t len, zip_source_cmd_t cmd);
   55 static struct winzip_aes *winzip_aes_new(zip_uint16_t encryption_method, const char *password, zip_error_t *error);
   56 
   57 
   58 zip_source_t *
   59 zip_source_winzip_aes_decode(zip_t *za, zip_source_t *src, zip_uint16_t encryption_method, int flags, const char *password) {
   60     zip_source_t *s2;
   61     zip_stat_t st;
   62     zip_uint64_t aux_length;
   63     struct winzip_aes *ctx;
   64 
   65     if ((encryption_method != ZIP_EM_AES_128 && encryption_method != ZIP_EM_AES_192 && encryption_method != ZIP_EM_AES_256) || password == NULL || src == NULL) {
   66     zip_error_set(&za->error, ZIP_ER_INVAL, 0);
   67     return NULL;
   68     }
   69     if (flags & ZIP_CODEC_ENCODE) {
   70     zip_error_set(&za->error, ZIP_ER_ENCRNOTSUPP, 0);
   71     return NULL;
   72     }
   73 
   74     if (zip_source_stat(src, &st) != 0) {
   75     _zip_error_set_from_source(&za->error, src);
   76     return NULL;
   77     }
   78 
   79     aux_length = WINZIP_AES_PASSWORD_VERIFY_LENGTH + SALT_LENGTH(encryption_method) + HMAC_LENGTH;
   80 
   81     if ((st.valid & ZIP_STAT_COMP_SIZE) == 0 || st.comp_size < aux_length) {
   82     zip_error_set(&za->error, ZIP_ER_OPNOTSUPP, 0);
   83     return NULL;
   84     }
   85 
   86     if ((ctx = winzip_aes_new(encryption_method, password, &za->error)) == NULL) {
   87     return NULL;
   88     }
   89 
   90     ctx->data_length = st.comp_size - aux_length;
   91 
   92     if ((s2 = zip_source_layered(za, src, winzip_aes_decrypt, ctx)) == NULL) {
   93     winzip_aes_free(ctx);
   94     return NULL;
   95     }
   96 
   97     return s2;
   98 }
   99 
  100 
  101 static int
  102 decrypt_header(zip_source_t *src, struct winzip_aes *ctx) {
  103     zip_uint8_t header[WINZIP_AES_MAX_HEADER_LENGTH];
  104     zip_uint8_t password_verification[WINZIP_AES_PASSWORD_VERIFY_LENGTH];
  105     unsigned int headerlen;
  106     zip_int64_t n;
  107 
  108     headerlen = WINZIP_AES_PASSWORD_VERIFY_LENGTH + SALT_LENGTH(ctx->encryption_method);
  109     if ((n = zip_source_read(src, header, headerlen)) < 0) {
  110     _zip_error_set_from_source(&ctx->error, src);
  111     return -1;
  112     }
  113 
  114     if (n != headerlen) {
  115     zip_error_set(&ctx->error, ZIP_ER_EOF, 0);
  116     return -1;
  117     }
  118 
  119     if ((ctx->aes_ctx = _zip_winzip_aes_new((zip_uint8_t *)ctx->password, strlen(ctx->password), header, ctx->encryption_method, password_verification, &ctx->error)) == NULL) {
  120     return -1;
  121     }
  122     if (memcmp(password_verification, header + SALT_LENGTH(ctx->encryption_method), WINZIP_AES_PASSWORD_VERIFY_LENGTH) != 0) {
  123     _zip_winzip_aes_free(ctx->aes_ctx);
  124     ctx->aes_ctx = NULL;
  125     zip_error_set(&ctx->error, ZIP_ER_WRONGPASSWD, 0);
  126     return -1;
  127     }
  128     return 0;
  129 }
  130 
  131 
  132 static bool
  133 verify_hmac(zip_source_t *src, struct winzip_aes *ctx) {
  134     unsigned char computed[SHA1_LENGTH], from_file[HMAC_LENGTH];
  135     if (zip_source_read(src, from_file, HMAC_LENGTH) < HMAC_LENGTH) {
  136     _zip_error_set_from_source(&ctx->error, src);
  137     return false;
  138     }
  139 
  140     if (!_zip_winzip_aes_finish(ctx->aes_ctx, computed)) {
  141     zip_error_set(&ctx->error, ZIP_ER_INTERNAL, 0);
  142     return false;
  143     }
  144     _zip_winzip_aes_free(ctx->aes_ctx);
  145     ctx->aes_ctx = NULL;
  146 
  147     if (memcmp(from_file, computed, HMAC_LENGTH) != 0) {
  148     zip_error_set(&ctx->error, ZIP_ER_CRC, 0);
  149     return false;
  150     }
  151 
  152     return true;
  153 }
  154 
  155 
  156 static zip_int64_t
  157 winzip_aes_decrypt(zip_source_t *src, void *ud, void *data, zip_uint64_t len, zip_source_cmd_t cmd) {
  158     struct winzip_aes *ctx;
  159     zip_int64_t n;
  160 
  161     ctx = (struct winzip_aes *)ud;
  162 
  163     switch (cmd) {
  164     case ZIP_SOURCE_OPEN:
  165     if (decrypt_header(src, ctx) < 0) {
  166         return -1;
  167     }
  168     ctx->current_position = 0;
  169     return 0;
  170 
  171     case ZIP_SOURCE_READ:
  172     if (len > ctx->data_length - ctx->current_position) {
  173         len = ctx->data_length - ctx->current_position;
  174     }
  175 
  176     if (len == 0) {
  177         if (!verify_hmac(src, ctx)) {
  178         return -1;
  179         }
  180         return 0;
  181     }
  182 
  183     if ((n = zip_source_read(src, data, len)) < 0) {
  184         _zip_error_set_from_source(&ctx->error, src);
  185         return -1;
  186     }
  187     ctx->current_position += (zip_uint64_t)n;
  188 
  189     if (!_zip_winzip_aes_decrypt(ctx->aes_ctx, (zip_uint8_t *)data, (zip_uint64_t)n)) {
  190         zip_error_set(&ctx->error, ZIP_ER_INTERNAL, 0);
  191         return -1;
  192     }
  193 
  194     return n;
  195 
  196     case ZIP_SOURCE_CLOSE:
  197     return 0;
  198 
  199     case ZIP_SOURCE_STAT: {
  200     zip_stat_t *st;
  201 
  202     st = (zip_stat_t *)data;
  203 
  204     st->encryption_method = ZIP_EM_NONE;
  205     st->valid |= ZIP_STAT_ENCRYPTION_METHOD;
  206     if (st->valid & ZIP_STAT_COMP_SIZE) {
  207         st->comp_size -= 12 + SALT_LENGTH(ctx->encryption_method);
  208     }
  209 
  210     return 0;
  211     }
  212 
  213     case ZIP_SOURCE_SUPPORTS:
  214     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);
  215 
  216     case ZIP_SOURCE_ERROR:
  217     return zip_error_to_data(&ctx->error, data, len);
  218 
  219     case ZIP_SOURCE_FREE:
  220     winzip_aes_free(ctx);
  221     return 0;
  222 
  223     default:
  224     zip_error_set(&ctx->error, ZIP_ER_INVAL, 0);
  225     return -1;
  226     }
  227 }
  228 
  229 
  230 static void
  231 winzip_aes_free(struct winzip_aes *ctx) {
  232     if (ctx == NULL) {
  233     return;
  234     }
  235 
  236     _zip_crypto_clear(ctx->password, strlen(ctx->password));
  237     free(ctx->password);
  238     zip_error_fini(&ctx->error);
  239     _zip_winzip_aes_free(ctx->aes_ctx);
  240     free(ctx);
  241 }
  242 
  243 
  244 static struct winzip_aes *
  245 winzip_aes_new(zip_uint16_t encryption_method, const char *password, zip_error_t *error) {
  246     struct winzip_aes *ctx;
  247 
  248     if ((ctx = (struct winzip_aes *)malloc(sizeof(*ctx))) == NULL) {
  249     zip_error_set(error, ZIP_ER_MEMORY, 0);
  250     return NULL;
  251     }
  252 
  253     if ((ctx->password = strdup(password)) == NULL) {
  254     zip_error_set(error, ZIP_ER_MEMORY, 0);
  255     free(ctx);
  256     return NULL;
  257     }
  258 
  259     ctx->encryption_method = encryption_method;
  260     ctx->aes_ctx = NULL;
  261 
  262     zip_error_init(&ctx->error);
  263 
  264     return ctx;
  265 }