Coverage Report

Created: 2025-12-03 06:06

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-2023 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
#include "zip_crypto.h"
40
41
struct winzip_aes {
42
    char *password;
43
    zip_uint16_t encryption_method;
44
45
    zip_uint64_t data_length;
46
    zip_uint64_t current_position;
47
48
    zip_winzip_aes_t *aes_ctx;
49
    zip_error_t error;
50
};
51
52
53
static int decrypt_header(zip_source_t *src, struct winzip_aes *ctx);
54
static void winzip_aes_free(struct winzip_aes *);
55
static zip_int64_t winzip_aes_decrypt(zip_source_t *src, void *ud, void *data, zip_uint64_t len, zip_source_cmd_t cmd);
56
static struct winzip_aes *winzip_aes_new(zip_uint16_t encryption_method, const char *password, zip_error_t *error);
57
58
59
zip_source_t *
60
497
zip_source_winzip_aes_decode(zip_t *za, zip_source_t *src, zip_uint16_t encryption_method, int flags, const char *password) {
61
497
    zip_source_t *s2;
62
497
    zip_stat_t st;
63
497
    zip_uint64_t aux_length;
64
497
    struct winzip_aes *ctx;
65
66
497
    if ((encryption_method != ZIP_EM_AES_128 && encryption_method != ZIP_EM_AES_192 && encryption_method != ZIP_EM_AES_256) || password == NULL || src == NULL) {
67
0
        zip_error_set(&za->error, ZIP_ER_INVAL, 0);
68
0
        return NULL;
69
0
    }
70
497
    if (flags & ZIP_CODEC_ENCODE) {
71
0
        zip_error_set(&za->error, ZIP_ER_ENCRNOTSUPP, 0);
72
0
        return NULL;
73
0
    }
74
75
497
    if (zip_source_stat(src, &st) != 0) {
76
0
        zip_error_set_from_source(&za->error, src);
77
0
        return NULL;
78
0
    }
79
80
497
    aux_length = WINZIP_AES_PASSWORD_VERIFY_LENGTH + SALT_LENGTH(encryption_method) + HMAC_LENGTH;
81
82
497
    if ((st.valid & ZIP_STAT_COMP_SIZE) == 0 || st.comp_size < aux_length) {
83
11
        zip_error_set(&za->error, ZIP_ER_OPNOTSUPP, 0);
84
11
        return NULL;
85
11
    }
86
87
486
    if ((ctx = winzip_aes_new(encryption_method, password, &za->error)) == NULL) {
88
0
        return NULL;
89
0
    }
90
91
486
    ctx->data_length = st.comp_size - aux_length;
92
93
486
    if ((s2 = zip_source_layered(za, src, winzip_aes_decrypt, ctx)) == NULL) {
94
0
        winzip_aes_free(ctx);
95
0
        return NULL;
96
0
    }
97
98
486
    return s2;
99
486
}
100
101
102
static int
103
451
decrypt_header(zip_source_t *src, struct winzip_aes *ctx) {
104
451
    zip_uint8_t header[WINZIP_AES_MAX_HEADER_LENGTH];
105
451
    zip_uint8_t password_verification[WINZIP_AES_PASSWORD_VERIFY_LENGTH];
106
451
    unsigned int headerlen;
107
451
    zip_int64_t n;
108
109
451
    headerlen = WINZIP_AES_PASSWORD_VERIFY_LENGTH + SALT_LENGTH(ctx->encryption_method);
110
451
    if ((n = zip_source_read(src, header, headerlen)) < 0) {
111
28
        zip_error_set_from_source(&ctx->error, src);
112
28
        return -1;
113
28
    }
114
115
423
    if (n != headerlen) {
116
19
        zip_error_set(&ctx->error, ZIP_ER_EOF, 0);
117
19
        return -1;
118
19
    }
119
120
404
    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) {
121
0
        return -1;
122
0
    }
123
404
    if (memcmp(password_verification, header + SALT_LENGTH(ctx->encryption_method), WINZIP_AES_PASSWORD_VERIFY_LENGTH) != 0) {
124
85
        _zip_winzip_aes_free(ctx->aes_ctx);
125
85
        ctx->aes_ctx = NULL;
126
85
        zip_error_set(&ctx->error, ZIP_ER_WRONGPASSWD, 0);
127
85
        return -1;
128
85
    }
129
319
    return 0;
130
404
}
131
132
133
static bool
134
105
verify_hmac(zip_source_t *src, struct winzip_aes *ctx) {
135
105
    unsigned char computed[ZIP_CRYPTO_SHA1_LENGTH], from_file[HMAC_LENGTH];
136
105
    if (zip_source_read(src, from_file, HMAC_LENGTH) < HMAC_LENGTH) {
137
17
        zip_error_set_from_source(&ctx->error, src);
138
17
        return false;
139
17
    }
140
141
88
    if (!_zip_winzip_aes_finish(ctx->aes_ctx, computed)) {
142
0
        zip_error_set(&ctx->error, ZIP_ER_INTERNAL, 0);
143
0
        return false;
144
0
    }
145
88
    _zip_winzip_aes_free(ctx->aes_ctx);
146
88
    ctx->aes_ctx = NULL;
147
148
88
    if (memcmp(from_file, computed, HMAC_LENGTH) != 0) {
149
74
        zip_error_set(&ctx->error, ZIP_ER_CRC, 0);
150
74
        return false;
151
74
    }
152
153
14
    return true;
154
88
}
155
156
157
static zip_int64_t
158
4.53k
winzip_aes_decrypt(zip_source_t *src, void *ud, void *data, zip_uint64_t len, zip_source_cmd_t cmd) {
159
4.53k
    struct winzip_aes *ctx;
160
4.53k
    zip_int64_t n;
161
162
4.53k
    ctx = (struct winzip_aes *)ud;
163
164
4.53k
    switch (cmd) {
165
451
    case ZIP_SOURCE_OPEN:
166
451
        if (decrypt_header(src, ctx) < 0) {
167
132
            return -1;
168
132
        }
169
319
        ctx->current_position = 0;
170
319
        return 0;
171
172
2.11k
    case ZIP_SOURCE_READ:
173
2.11k
        if (len > ctx->data_length - ctx->current_position) {
174
250
            len = ctx->data_length - ctx->current_position;
175
250
        }
176
177
2.11k
        if (len == 0) {
178
105
            if (!verify_hmac(src, ctx)) {
179
91
                return -1;
180
91
            }
181
14
            return 0;
182
105
        }
183
184
2.00k
        if ((n = zip_source_read(src, data, len)) < 0) {
185
208
            zip_error_set_from_source(&ctx->error, src);
186
208
            return -1;
187
208
        }
188
1.80k
        ctx->current_position += (zip_uint64_t)n;
189
190
1.80k
        if (!_zip_winzip_aes_decrypt(ctx->aes_ctx, (zip_uint8_t *)data, (zip_uint64_t)n)) {
191
0
            zip_error_set(&ctx->error, ZIP_ER_INTERNAL, 0);
192
0
            return -1;
193
0
        }
194
195
1.80k
        return n;
196
197
319
    case ZIP_SOURCE_CLOSE:
198
319
        return 0;
199
200
253
    case ZIP_SOURCE_STAT: {
201
253
        zip_stat_t *st;
202
203
253
        st = (zip_stat_t *)data;
204
205
253
        st->encryption_method = ZIP_EM_NONE;
206
253
        st->valid |= ZIP_STAT_ENCRYPTION_METHOD;
207
253
        if (st->valid & ZIP_STAT_COMP_SIZE) {
208
253
            st->comp_size -= 12 + SALT_LENGTH(ctx->encryption_method);
209
253
        }
210
211
253
        return 0;
212
1.80k
    }
213
214
486
    case ZIP_SOURCE_SUPPORTS:
215
486
        return zip_source_make_command_bitmap(ZIP_SOURCE_OPEN, ZIP_SOURCE_READ, ZIP_SOURCE_CLOSE, ZIP_SOURCE_STAT, ZIP_SOURCE_ERROR, ZIP_SOURCE_FREE, ZIP_SOURCE_SUPPORTS_REOPEN, -1);
216
217
431
    case ZIP_SOURCE_ERROR:
218
431
        return zip_error_to_data(&ctx->error, data, len);
219
220
486
    case ZIP_SOURCE_FREE:
221
486
        winzip_aes_free(ctx);
222
486
        return 0;
223
224
0
    default:
225
0
        return zip_source_pass_to_lower_layer(src, data, len, cmd);
226
4.53k
    }
227
4.53k
}
228
229
230
static void
231
486
winzip_aes_free(struct winzip_aes *ctx) {
232
486
    if (ctx == NULL) {
233
0
        return;
234
0
    }
235
236
486
    _zip_crypto_clear(ctx->password, strlen(ctx->password));
237
486
    free(ctx->password);
238
486
    zip_error_fini(&ctx->error);
239
486
    _zip_winzip_aes_free(ctx->aes_ctx);
240
486
    free(ctx);
241
486
}
242
243
244
static struct winzip_aes *
245
486
winzip_aes_new(zip_uint16_t encryption_method, const char *password, zip_error_t *error) {
246
486
    struct winzip_aes *ctx;
247
248
486
    if ((ctx = (struct winzip_aes *)malloc(sizeof(*ctx))) == NULL) {
249
0
        zip_error_set(error, ZIP_ER_MEMORY, 0);
250
0
        return NULL;
251
0
    }
252
253
486
    if ((ctx->password = strdup(password)) == NULL) {
254
0
        zip_error_set(error, ZIP_ER_MEMORY, 0);
255
0
        free(ctx);
256
0
        return NULL;
257
0
    }
258
259
486
    ctx->encryption_method = encryption_method;
260
486
    ctx->aes_ctx = NULL;
261
262
486
    zip_error_init(&ctx->error);
263
264
486
    return ctx;
265
486
}