Coverage Report

Created: 2026-10-08 06:29

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libzip/lib/zip_source_winzip_aes_decode.c
Line
Count
Source
1
/*
2
  zip_source_winzip_aes_decode.c -- Winzip AES decryption routines
3
  Copyright (C) 2009-2024 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 <info@libzip.org>
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
#include "zip_crypto.h"
41
42
struct winzip_aes {
43
    char *password;
44
    zip_uint16_t encryption_method;
45
46
    zip_uint64_t data_length;
47
    zip_uint64_t current_position;
48
49
    zip_winzip_aes_t *aes_ctx;
50
    bool hmac_verify_failed;
51
    bool hmac_verified;
52
    zip_error_t error;
53
};
54
55
56
static int decrypt_header(zip_source_t *src, struct winzip_aes *ctx);
57
static void winzip_aes_free(struct winzip_aes *);
58
static zip_int64_t winzip_aes_decrypt(zip_source_t *src, void *ud, void *data, zip_uint64_t len, zip_source_cmd_t cmd);
59
static struct winzip_aes *winzip_aes_new(zip_uint16_t encryption_method, const char *password, zip_error_t *error);
60
61
62
8.86k
zip_source_t *zip_source_winzip_aes_decode(zip_t *za, zip_source_t *src, zip_uint16_t encryption_method, int flags, const char *password) {
63
8.86k
    zip_source_t *s2;
64
8.86k
    zip_stat_t st;
65
8.86k
    zip_uint64_t aux_length;
66
8.86k
    struct winzip_aes *ctx;
67
68
8.86k
    if ((encryption_method != ZIP_EM_AES_128 && encryption_method != ZIP_EM_AES_192 && encryption_method != ZIP_EM_AES_256) || password == NULL || src == NULL) {
69
0
        zip_error_set(&za->error, ZIP_ER_INVAL, 0);
70
0
        return NULL;
71
0
    }
72
8.86k
    if (flags & ZIP_CODEC_ENCODE) {
73
0
        zip_error_set(&za->error, ZIP_ER_ENCRNOTSUPP, 0);
74
0
        return NULL;
75
0
    }
76
77
8.86k
    if (zip_source_stat(src, &st) != 0) {
78
0
        zip_error_set_from_source(&za->error, src);
79
0
        return NULL;
80
0
    }
81
82
8.86k
    aux_length = WINZIP_AES_PASSWORD_VERIFY_LENGTH + SALT_LENGTH(encryption_method) + HMAC_LENGTH;
83
84
8.86k
    if ((st.valid & ZIP_STAT_COMP_SIZE) == 0 || st.comp_size < aux_length) {
85
27
        zip_error_set(&za->error, ZIP_ER_OPNOTSUPP, 0);
86
27
        return NULL;
87
27
    }
88
89
8.83k
    if ((ctx = winzip_aes_new(encryption_method, password, &za->error)) == NULL) {
90
0
        return NULL;
91
0
    }
92
93
8.83k
    ctx->data_length = st.comp_size - aux_length;
94
95
8.83k
    if ((s2 = zip_source_layered(za, src, winzip_aes_decrypt, ctx)) == NULL) {
96
0
        winzip_aes_free(ctx);
97
0
        return NULL;
98
0
    }
99
100
8.83k
    return s2;
101
8.83k
}
102
103
104
8.80k
static int decrypt_header(zip_source_t *src, struct winzip_aes *ctx) {
105
8.80k
    zip_uint8_t header[WINZIP_AES_MAX_HEADER_LENGTH];
106
8.80k
    zip_uint8_t password_verification[WINZIP_AES_PASSWORD_VERIFY_LENGTH];
107
8.80k
    unsigned int headerlen;
108
8.80k
    zip_int64_t n;
109
110
8.80k
    headerlen = WINZIP_AES_PASSWORD_VERIFY_LENGTH + SALT_LENGTH(ctx->encryption_method);
111
8.80k
    if ((n = zip_source_read(src, header, headerlen)) < 0) {
112
16
        zip_error_set_from_source(&ctx->error, src);
113
16
        return -1;
114
16
    }
115
116
8.78k
    if (n != headerlen) {
117
16
        zip_error_set(&ctx->error, ZIP_ER_EOF, 0);
118
16
        return -1;
119
16
    }
120
121
8.77k
    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) {
122
0
        return -1;
123
0
    }
124
8.77k
    if (memcmp(password_verification, header + SALT_LENGTH(ctx->encryption_method), WINZIP_AES_PASSWORD_VERIFY_LENGTH) != 0) {
125
69
        _zip_winzip_aes_free(ctx->aes_ctx);
126
69
        ctx->aes_ctx = NULL;
127
69
        zip_error_set(&ctx->error, ZIP_ER_WRONGPASSWD, 0);
128
69
        return -1;
129
69
    }
130
8.70k
    return 0;
131
8.77k
}
132
133
134
25.3k
static void verify_hmac(zip_source_t *src, struct winzip_aes *ctx) {
135
25.3k
    unsigned char computed[ZIP_CRYPTO_SHA1_LENGTH], from_file[HMAC_LENGTH];
136
137
25.3k
    if (ctx->hmac_verified) {
138
16.7k
        return;
139
16.7k
    }
140
8.60k
    ctx->hmac_verified = true;
141
142
8.60k
    if (zip_source_read(src, from_file, HMAC_LENGTH) < HMAC_LENGTH) {
143
37
        zip_error_set_from_source(&ctx->error, src);
144
37
        ctx->hmac_verify_failed = true;
145
37
        return;
146
37
    }
147
148
8.57k
    if (!_zip_winzip_aes_finish(ctx->aes_ctx, computed)) {
149
0
        zip_error_set(&ctx->error, ZIP_ER_INTERNAL, 0);
150
0
        ctx->hmac_verify_failed = true;
151
0
        return;
152
0
    }
153
8.57k
    _zip_winzip_aes_free(ctx->aes_ctx);
154
8.57k
    ctx->aes_ctx = NULL;
155
156
8.57k
    if (memcmp(from_file, computed, HMAC_LENGTH) != 0) {
157
156
        zip_error_set(&ctx->error, ZIP_ER_CRC, 0);
158
156
        ctx->hmac_verify_failed = true;
159
156
        return;
160
156
    }
161
162
8.41k
    return;
163
8.57k
}
164
165
166
67.4k
static zip_int64_t winzip_aes_decrypt(zip_source_t *src, void *ud, void *data, zip_uint64_t len, zip_source_cmd_t cmd) {
167
67.4k
    struct winzip_aes *ctx;
168
67.4k
    zip_int64_t n;
169
170
67.4k
    ctx = (struct winzip_aes *)ud;
171
172
67.4k
    switch (cmd) {
173
132
    case ZIP_SOURCE_AT_EOF:
174
132
        return ctx->current_position == ctx->data_length;
175
176
8.80k
    case ZIP_SOURCE_OPEN:
177
8.80k
        ctx->hmac_verify_failed = false;
178
8.80k
        ctx->hmac_verified = false;
179
8.80k
        if (decrypt_header(src, ctx) < 0) {
180
101
            return -1;
181
101
        }
182
8.70k
        ctx->current_position = 0;
183
8.70k
        return 0;
184
185
17.0k
    case ZIP_SOURCE_READ:
186
17.0k
        len = ZIP_MIN(len, ctx->data_length - ctx->current_position);
187
188
17.0k
        if (len > 0) {
189
8.46k
            if ((n = zip_source_read(src, data, len)) < 0) {
190
92
                zip_error_set_from_source(&ctx->error, src);
191
92
                return -1;
192
92
            }
193
194
8.37k
            if (n == 0) {
195
0
                zip_error_set(&ctx->error, ZIP_ER_EOF, 0);
196
0
                return -1;
197
0
            }
198
199
8.37k
            ctx->current_position += (zip_uint64_t)n;
200
201
8.37k
            if (!_zip_winzip_aes_decrypt(ctx->aes_ctx, (zip_uint8_t *)data, (zip_uint64_t)n)) {
202
0
                zip_error_set(&ctx->error, ZIP_ER_INTERNAL, 0);
203
0
                return -1;
204
0
            }
205
8.37k
        }
206
8.60k
        else {
207
8.60k
            n = 0;
208
8.60k
        }
209
210
16.9k
        if (ctx->current_position == ctx->data_length) {
211
16.7k
            verify_hmac(src, ctx);
212
16.7k
        }
213
214
16.9k
        if (n > 0) {
215
8.37k
            return n;
216
8.37k
        }
217
8.60k
        else {
218
8.60k
            return ctx->hmac_verify_failed ? -1 : 0;
219
8.60k
        }
220
221
8.70k
    case ZIP_SOURCE_CLOSE:
222
        /* For empty files, we should verify the HMAC even if no data has been read. */
223
8.70k
        if (ctx->current_position == ctx->data_length) {
224
8.60k
            verify_hmac(src, ctx);
225
8.60k
        }
226
8.70k
        return ctx->hmac_verify_failed ? -1 : 0;
227
228
14.5k
    case ZIP_SOURCE_STAT: {
229
14.5k
        zip_stat_t *st;
230
231
14.5k
        st = (zip_stat_t *)data;
232
233
14.5k
        st->encryption_method = ZIP_EM_NONE;
234
14.5k
        st->valid |= ZIP_STAT_ENCRYPTION_METHOD;
235
14.5k
        if (st->valid & ZIP_STAT_COMP_SIZE) {
236
14.5k
            if (st->comp_size < WINZIP_AES_PASSWORD_VERIFY_LENGTH + SALT_LENGTH(ctx->encryption_method) + HMAC_LENGTH) {
237
0
                zip_error_set(&ctx->error, ZIP_ER_DATA_LENGTH, 0);
238
0
                return -1;
239
0
            }
240
14.5k
            st->comp_size -= WINZIP_AES_PASSWORD_VERIFY_LENGTH + SALT_LENGTH(ctx->encryption_method) + HMAC_LENGTH;
241
14.5k
        }
242
243
14.5k
        return 0;
244
14.5k
    }
245
246
8.83k
    case ZIP_SOURCE_SUPPORTS:
247
8.83k
        return zip_source_make_command_bitmap(ZIP_SOURCE_AT_EOF, ZIP_SOURCE_OPEN, ZIP_SOURCE_READ, ZIP_SOURCE_CLOSE, ZIP_SOURCE_STAT, ZIP_SOURCE_ERROR, ZIP_SOURCE_FREE, ZIP_SOURCE_SUPPORTS_REOPEN, -1);
248
249
579
    case ZIP_SOURCE_ERROR:
250
579
        return zip_error_to_data(&ctx->error, data, len);
251
252
8.83k
    case ZIP_SOURCE_FREE:
253
8.83k
        winzip_aes_free(ctx);
254
8.83k
        return 0;
255
256
0
    default:
257
0
        return zip_source_pass_to_lower_layer(src, data, len, cmd);
258
67.4k
    }
259
67.4k
}
260
261
262
8.83k
static void winzip_aes_free(struct winzip_aes *ctx) {
263
8.83k
    if (ctx == NULL) {
264
0
        return;
265
0
    }
266
267
8.83k
    _zip_crypto_clear(ctx->password, strlen(ctx->password));
268
8.83k
    free(ctx->password);
269
8.83k
    zip_error_fini(&ctx->error);
270
8.83k
    _zip_winzip_aes_free(ctx->aes_ctx);
271
8.83k
    free(ctx);
272
8.83k
}
273
274
275
8.83k
static struct winzip_aes *winzip_aes_new(zip_uint16_t encryption_method, const char *password, zip_error_t *error) {
276
8.83k
    struct winzip_aes *ctx;
277
278
8.83k
    if ((ctx = (struct winzip_aes *)malloc(sizeof(*ctx))) == NULL) {
279
0
        zip_error_set(error, ZIP_ER_MEMORY, 0);
280
0
        return NULL;
281
0
    }
282
283
8.83k
    if ((ctx->password = strdup(password)) == NULL) {
284
0
        zip_error_set(error, ZIP_ER_MEMORY, 0);
285
0
        free(ctx);
286
0
        return NULL;
287
0
    }
288
289
8.83k
    ctx->encryption_method = encryption_method;
290
8.83k
    ctx->aes_ctx = NULL;
291
8.83k
    ctx->hmac_verify_failed = false;
292
8.83k
    ctx->hmac_verified = false;
293
294
8.83k
    zip_error_init(&ctx->error);
295
296
8.83k
    return ctx;
297
8.83k
}