Coverage Report

Created: 2026-02-26 06:41

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libzip/lib/zip_source_pkware_encode.c
Line
Count
Source
1
/*
2
  zip_source_pkware_encode.c -- Traditional PKWARE encryption routines
3
  Copyright (C) 2009-2025 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
#include "zipint.h"
35
36
37
#include <stdlib.h>
38
#include <string.h>
39
40
struct trad_pkware {
41
    char *password;
42
    zip_pkware_keys_t keys;
43
    zip_buffer_t *buffer;
44
    bool eof;
45
    zip_dostime_t dostime;
46
    zip_error_t error;
47
};
48
49
50
static int encrypt_header(zip_source_t *, struct trad_pkware *);
51
static zip_int64_t pkware_encrypt(zip_source_t *, void *, void *, zip_uint64_t, zip_source_cmd_t);
52
static void trad_pkware_free(struct trad_pkware *);
53
static struct trad_pkware *trad_pkware_new(const char *password, zip_error_t *error);
54
55
zip_source_t *
56
490
zip_source_pkware_encode(zip_t *za, zip_source_t *src, zip_uint16_t em, int flags, const char *password) {
57
490
    struct trad_pkware *ctx;
58
490
    zip_source_t *s2;
59
60
490
    if (password == NULL || src == NULL || em != ZIP_EM_TRAD_PKWARE) {
61
0
        zip_error_set(&za->error, ZIP_ER_INVAL, 0);
62
0
        return NULL;
63
0
    }
64
490
    if (!(flags & ZIP_CODEC_ENCODE)) {
65
0
        zip_error_set(&za->error, ZIP_ER_ENCRNOTSUPP, 0);
66
0
        return NULL;
67
0
    }
68
69
490
    if ((ctx = trad_pkware_new(password, &za->error)) == NULL) {
70
0
        zip_error_set(&za->error, ZIP_ER_MEMORY, 0);
71
0
        return NULL;
72
0
    }
73
74
490
    if (zip_source_get_dos_time(src, &ctx->dostime) <= 0) {
75
490
        zip_stat_t st;
76
77
490
        if (zip_source_stat(src, &st) < 0) {
78
0
            zip_error_set_from_source(&za->error, src);
79
0
            trad_pkware_free(ctx);
80
0
            return NULL;
81
0
        }
82
490
        if (_zip_u2d_time((st.valid & ZIP_STAT_MTIME) ? st.mtime : time(NULL), &ctx->dostime, &za->error) < 0) {
83
0
            trad_pkware_free(ctx);
84
0
            return NULL;
85
0
        }
86
490
    }
87
88
490
    if ((s2 = zip_source_layered(za, src, pkware_encrypt, ctx)) == NULL) {
89
0
        trad_pkware_free(ctx);
90
0
        return NULL;
91
0
    }
92
93
490
    return s2;
94
490
}
95
96
97
static int
98
490
encrypt_header(zip_source_t *src, struct trad_pkware *ctx) {
99
490
    zip_uint8_t *header;
100
101
490
    if ((ctx->buffer = _zip_buffer_new(NULL, ZIP_CRYPTO_PKWARE_HEADERLEN)) == NULL) {
102
0
        zip_error_set(&ctx->error, ZIP_ER_MEMORY, 0);
103
0
        return -1;
104
0
    }
105
106
490
    header = _zip_buffer_data(ctx->buffer);
107
108
    /* generate header from random bytes and mtime
109
       see appnote.iz, XIII. Decryption, Step 2, last paragraph */
110
490
    if (!zip_secure_random(header, ZIP_CRYPTO_PKWARE_HEADERLEN - 1)) {
111
0
        zip_error_set(&ctx->error, ZIP_ER_INTERNAL, 0);
112
0
        _zip_buffer_free(ctx->buffer);
113
0
        ctx->buffer = NULL;
114
0
        return -1;
115
0
    }
116
490
    header[ZIP_CRYPTO_PKWARE_HEADERLEN - 1] = (zip_uint8_t)((ctx->dostime.time >> 8) & 0xff);
117
118
490
    _zip_pkware_encrypt(&ctx->keys, header, header, ZIP_CRYPTO_PKWARE_HEADERLEN);
119
120
490
    return 0;
121
490
}
122
123
124
static zip_int64_t
125
14.6k
pkware_encrypt(zip_source_t *src, void *ud, void *data, zip_uint64_t length, zip_source_cmd_t cmd) {
126
14.6k
    struct trad_pkware *ctx;
127
14.6k
    zip_int64_t n;
128
14.6k
    zip_uint64_t buffer_n;
129
130
14.6k
    ctx = (struct trad_pkware *)ud;
131
132
14.6k
    switch (cmd) {
133
490
    case ZIP_SOURCE_OPEN:
134
490
        ctx->eof = false;
135
136
        /* initialize keys */
137
490
        _zip_pkware_keys_reset(&ctx->keys);
138
490
        _zip_pkware_encrypt(&ctx->keys, NULL, (const zip_uint8_t *)ctx->password, strlen(ctx->password));
139
140
490
        if (encrypt_header(src, ctx) < 0) {
141
0
            return -1;
142
0
        }
143
490
        return 0;
144
145
11.2k
    case ZIP_SOURCE_READ:
146
11.2k
        buffer_n = 0;
147
148
11.2k
        if (ctx->buffer) {
149
            /* write header values to data */
150
490
            buffer_n = _zip_buffer_read(ctx->buffer, data, length);
151
490
            data = (zip_uint8_t *)data + buffer_n;
152
490
            length -= buffer_n;
153
154
490
            if (_zip_buffer_eof(ctx->buffer)) {
155
490
                _zip_buffer_free(ctx->buffer);
156
490
                ctx->buffer = NULL;
157
490
            }
158
490
        }
159
160
11.2k
        if (ctx->eof) {
161
469
            return (zip_int64_t)buffer_n;
162
469
        }
163
164
10.7k
        if ((n = zip_source_read(src, data, length)) < 0) {
165
0
            zip_error_set_from_source(&ctx->error, src);
166
0
            return -1;
167
0
        }
168
169
10.7k
        _zip_pkware_encrypt(&ctx->keys, (zip_uint8_t *)data, (zip_uint8_t *)data, (zip_uint64_t)n);
170
171
10.7k
        if ((zip_uint64_t)n < length) {
172
490
            ctx->eof = true;
173
490
        }
174
175
10.7k
        return (zip_int64_t)buffer_n + n;
176
177
490
    case ZIP_SOURCE_CLOSE:
178
490
        _zip_buffer_free(ctx->buffer);
179
490
        ctx->buffer = NULL;
180
490
        return 0;
181
182
490
    case ZIP_SOURCE_STAT: {
183
490
        zip_stat_t *st;
184
185
490
        st = (zip_stat_t *)data;
186
490
        st->encryption_method = ZIP_EM_TRAD_PKWARE;
187
490
        st->valid |= ZIP_STAT_ENCRYPTION_METHOD;
188
490
        if (st->valid & ZIP_STAT_COMP_SIZE) {
189
490
            st->comp_size += ZIP_CRYPTO_PKWARE_HEADERLEN;
190
490
        }
191
192
490
        return 0;
193
10.7k
    }
194
195
980
    case ZIP_SOURCE_GET_FILE_ATTRIBUTES: {
196
980
        zip_file_attributes_t *attributes = (zip_file_attributes_t *)data;
197
980
        if (length < sizeof(*attributes)) {
198
0
            zip_error_set(&ctx->error, ZIP_ER_INVAL, 0);
199
0
            return -1;
200
0
        }
201
980
        attributes->valid |= ZIP_FILE_ATTRIBUTES_VERSION_NEEDED | ZIP_FILE_ATTRIBUTES_GENERAL_PURPOSE_BIT_FLAGS;
202
980
        attributes->version_needed = 20;
203
980
        attributes->general_purpose_bit_flags = ZIP_GPBF_DATA_DESCRIPTOR;
204
980
        attributes->general_purpose_bit_mask = ZIP_GPBF_DATA_DESCRIPTOR;
205
206
980
        return 0;
207
980
    }
208
209
0
    case ZIP_SOURCE_GET_DOS_TIME:
210
0
        if (length < sizeof(ctx->dostime)) {
211
0
            zip_error_set(&ctx->error, ZIP_ER_INVAL, 0);
212
0
            return -1;
213
0
        }
214
0
        (void)memcpy_s(data, sizeof(ctx->dostime), &ctx->dostime, sizeof(ctx->dostime));
215
0
        return sizeof(ctx->dostime);
216
217
490
    case ZIP_SOURCE_SUPPORTS:
218
490
        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_GET_FILE_ATTRIBUTES, ZIP_SOURCE_GET_DOS_TIME, -1);
219
220
0
    case ZIP_SOURCE_ERROR:
221
0
        return zip_error_to_data(&ctx->error, data, length);
222
223
490
    case ZIP_SOURCE_FREE:
224
490
        trad_pkware_free(ctx);
225
490
        return 0;
226
227
0
    default:
228
0
        return zip_source_pass_to_lower_layer(src, data, length, cmd);
229
14.6k
    }
230
14.6k
}
231
232
233
static struct trad_pkware *
234
490
trad_pkware_new(const char *password, zip_error_t *error) {
235
490
    struct trad_pkware *ctx;
236
237
490
    if ((ctx = (struct trad_pkware *)malloc(sizeof(*ctx))) == NULL) {
238
0
        zip_error_set(error, ZIP_ER_MEMORY, 0);
239
0
        return NULL;
240
0
    }
241
242
490
    if ((ctx->password = strdup(password)) == NULL) {
243
0
        zip_error_set(error, ZIP_ER_MEMORY, 0);
244
0
        free(ctx);
245
0
        return NULL;
246
0
    }
247
490
    ctx->buffer = NULL;
248
490
    zip_error_init(&ctx->error);
249
250
490
    return ctx;
251
490
}
252
253
254
static void
255
490
trad_pkware_free(struct trad_pkware *ctx) {
256
490
    if (ctx == NULL) {
257
0
        return;
258
0
    }
259
260
490
    free(ctx->password);
261
490
    _zip_buffer_free(ctx->buffer);
262
490
    zip_error_fini(&ctx->error);
263
490
    free(ctx);
264
490
}