Coverage Report

Created: 2023-03-26 06:14

/src/minizip-ng/mz_strm_pkcrypt.c
Line
Count
Source (jump to first uncovered line)
1
/* mz_strm_pkcrypt.c -- Code for traditional PKWARE encryption
2
   part of the minizip-ng project
3
4
   Copyright (C) Nathan Moinvaziri
5
      https://github.com/zlib-ng/minizip-ng
6
   Copyright (C) 1998-2005 Gilles Vollant
7
      Modifications for Info-ZIP crypting
8
      https://www.winimage.com/zLibDll/minizip.html
9
   Copyright (C) 2003 Terry Thorsen
10
11
   This code is a modified version of crypting code in Info-ZIP distribution
12
13
   Copyright (C) 1990-2000 Info-ZIP.  All rights reserved.
14
15
   This program is distributed under the terms of the same license as zlib.
16
   See the accompanying LICENSE file for the full text of the license.
17
18
   This encryption code is a direct transcription of the algorithm from
19
   Roger Schlafly, described by Phil Katz in the file appnote.txt. This
20
   file (appnote.txt) is distributed with the PKZIP program (even in the
21
   version without encryption capabilities).
22
*/
23
24
#include "mz.h"
25
#include "mz_crypt.h"
26
#include "mz_strm.h"
27
#include "mz_strm_pkcrypt.h"
28
29
/***************************************************************************/
30
31
static mz_stream_vtbl mz_stream_pkcrypt_vtbl = {
32
    mz_stream_pkcrypt_open,
33
    mz_stream_pkcrypt_is_open,
34
    mz_stream_pkcrypt_read,
35
    mz_stream_pkcrypt_write,
36
    mz_stream_pkcrypt_tell,
37
    mz_stream_pkcrypt_seek,
38
    mz_stream_pkcrypt_close,
39
    mz_stream_pkcrypt_error,
40
    mz_stream_pkcrypt_create,
41
    mz_stream_pkcrypt_delete,
42
    mz_stream_pkcrypt_get_prop_int64,
43
    mz_stream_pkcrypt_set_prop_int64
44
};
45
46
/***************************************************************************/
47
48
typedef struct mz_stream_pkcrypt_s {
49
    mz_stream       stream;
50
    int32_t         error;
51
    int16_t         initialized;
52
    uint8_t         buffer[UINT16_MAX];
53
    int64_t         total_in;
54
    int64_t         max_total_in;
55
    int64_t         total_out;
56
    uint32_t        keys[3];          /* keys defining the pseudo-random sequence */
57
    uint8_t         verify1;
58
    uint8_t         verify2;
59
    const char      *password;
60
} mz_stream_pkcrypt;
61
62
/***************************************************************************/
63
64
#define mz_stream_pkcrypt_decode(strm, c)                                   \
65
1.40M
    (mz_stream_pkcrypt_update_keys(strm,                                    \
66
1.40M
        c ^= mz_stream_pkcrypt_decrypt_byte(strm)))
67
68
#define mz_stream_pkcrypt_encode(strm, c, t)                                \
69
0
    (t = mz_stream_pkcrypt_decrypt_byte(strm),                              \
70
0
        mz_stream_pkcrypt_update_keys(strm, (uint8_t)c), (uint8_t)(t^(c)))
71
72
/***************************************************************************/
73
74
1.39M
static uint8_t mz_stream_pkcrypt_decrypt_byte(void *stream) {
75
1.39M
    mz_stream_pkcrypt *pkcrypt = (mz_stream_pkcrypt *)stream;
76
77
1.39M
    unsigned temp; /* POTENTIAL BUG:  temp*(temp^1) may overflow in an */
78
                   /* unpredictable manner on 16-bit systems; not a problem */
79
                   /* with any known compiler so far, though. */
80
81
1.39M
    temp = pkcrypt->keys[2] | 2;
82
1.39M
    return (uint8_t)(((temp * (temp ^ 1)) >> 8) & 0xff);
83
1.39M
}
84
85
1.43M
static uint8_t mz_stream_pkcrypt_update_keys(void *stream, uint8_t c) {
86
1.43M
    mz_stream_pkcrypt *pkcrypt = (mz_stream_pkcrypt *)stream;
87
1.43M
    uint8_t buf = c;
88
89
1.43M
    pkcrypt->keys[0] = (uint32_t)~mz_crypt_crc32_update(~pkcrypt->keys[0], &buf, 1);
90
91
1.43M
    pkcrypt->keys[1] += pkcrypt->keys[0] & 0xff;
92
1.43M
    pkcrypt->keys[1] *= 134775813L;
93
1.43M
    pkcrypt->keys[1] += 1;
94
95
1.43M
    buf = (uint8_t)(pkcrypt->keys[1] >> 24);
96
1.43M
    pkcrypt->keys[2] = (uint32_t)~mz_crypt_crc32_update(~pkcrypt->keys[2], &buf, 1);
97
98
1.43M
    return (uint8_t)c;
99
1.43M
}
100
101
5.20k
static void mz_stream_pkcrypt_init_keys(void *stream, const char *password) {
102
5.20k
    mz_stream_pkcrypt *pkcrypt = (mz_stream_pkcrypt *)stream;
103
104
5.20k
    pkcrypt->keys[0] = 305419896L;
105
5.20k
    pkcrypt->keys[1] = 591751049L;
106
5.20k
    pkcrypt->keys[2] = 878082192L;
107
108
41.6k
    while (*password != 0) {
109
36.4k
        mz_stream_pkcrypt_update_keys(stream, (uint8_t)*password);
110
36.4k
        password += 1;
111
36.4k
    }
112
5.20k
}
113
114
/***************************************************************************/
115
116
5.20k
int32_t mz_stream_pkcrypt_open(void *stream, const char *path, int32_t mode) {
117
5.20k
    mz_stream_pkcrypt *pkcrypt = (mz_stream_pkcrypt *)stream;
118
5.20k
    uint16_t t = 0;
119
5.20k
    int16_t i = 0;
120
5.20k
    uint8_t verify1 = 0;
121
5.20k
    uint8_t verify2 = 0;
122
5.20k
    uint8_t header[MZ_PKCRYPT_HEADER_SIZE];
123
5.20k
    const char *password = path;
124
125
5.20k
    pkcrypt->total_in = 0;
126
5.20k
    pkcrypt->total_out = 0;
127
5.20k
    pkcrypt->initialized = 0;
128
129
5.20k
    if (mz_stream_is_open(pkcrypt->stream.base) != MZ_OK)
130
0
        return MZ_OPEN_ERROR;
131
132
5.20k
    if (!password)
133
5.20k
        password = pkcrypt->password;
134
5.20k
    if (!password)
135
0
        return MZ_PARAM_ERROR;
136
137
5.20k
    mz_stream_pkcrypt_init_keys(stream, password);
138
139
5.20k
    if (mode & MZ_OPEN_MODE_WRITE) {
140
        /* First generate RAND_HEAD_LEN - 2 random bytes. */
141
0
        mz_crypt_rand(header, MZ_PKCRYPT_HEADER_SIZE - 2);
142
143
        /* Encrypt random header (last two bytes is high word of crc) */
144
0
        for (i = 0; i < MZ_PKCRYPT_HEADER_SIZE - 2; i++)
145
0
            header[i] = mz_stream_pkcrypt_encode(stream, header[i], t);
146
147
0
        header[i++] = mz_stream_pkcrypt_encode(stream, pkcrypt->verify1, t);
148
0
        header[i++] = mz_stream_pkcrypt_encode(stream, pkcrypt->verify2, t);
149
150
0
        if (mz_stream_write(pkcrypt->stream.base, header, sizeof(header)) != sizeof(header))
151
0
            return MZ_WRITE_ERROR;
152
153
0
        pkcrypt->total_out += MZ_PKCRYPT_HEADER_SIZE;
154
5.20k
    } else if (mode & MZ_OPEN_MODE_READ) {
155
5.20k
        if (mz_stream_read(pkcrypt->stream.base, header, sizeof(header)) != sizeof(header))
156
71
            return MZ_READ_ERROR;
157
158
56.4k
        for (i = 0; i < MZ_PKCRYPT_HEADER_SIZE - 2; i++)
159
51.3k
            header[i] = mz_stream_pkcrypt_decode(stream, header[i]);
160
161
5.13k
        verify1 = mz_stream_pkcrypt_decode(stream, header[i++]);
162
5.13k
        verify2 = mz_stream_pkcrypt_decode(stream, header[i++]);
163
164
        /* Older versions used 2 byte check, newer versions use 1 byte check. */
165
5.13k
        MZ_UNUSED(verify1);
166
5.13k
        if ((verify2 != 0) && (verify2 != pkcrypt->verify2))
167
41
            return MZ_PASSWORD_ERROR;
168
169
5.09k
        pkcrypt->total_in += MZ_PKCRYPT_HEADER_SIZE;
170
5.09k
    }
171
172
5.09k
    pkcrypt->initialized = 1;
173
5.09k
    return MZ_OK;
174
5.20k
}
175
176
13.9k
int32_t mz_stream_pkcrypt_is_open(void *stream) {
177
13.9k
    mz_stream_pkcrypt *pkcrypt = (mz_stream_pkcrypt *)stream;
178
13.9k
    if (!pkcrypt->initialized)
179
0
        return MZ_OPEN_ERROR;
180
13.9k
    return MZ_OK;
181
13.9k
}
182
183
4.44k
int32_t mz_stream_pkcrypt_read(void *stream, void *buf, int32_t size) {
184
4.44k
    mz_stream_pkcrypt *pkcrypt = (mz_stream_pkcrypt *)stream;
185
4.44k
    uint8_t *buf_ptr = (uint8_t *)buf;
186
4.44k
    int32_t bytes_to_read = size;
187
4.44k
    int32_t read = 0;
188
4.44k
    int32_t i = 0;
189
190
4.44k
    if ((int64_t)bytes_to_read > (pkcrypt->max_total_in - pkcrypt->total_in))
191
1.74k
        bytes_to_read = (int32_t)(pkcrypt->max_total_in - pkcrypt->total_in);
192
193
4.44k
    read = mz_stream_read(pkcrypt->stream.base, buf, bytes_to_read);
194
195
1.34M
    for (i = 0; i < read; i++)
196
1.33M
        buf_ptr[i] = mz_stream_pkcrypt_decode(stream, buf_ptr[i]);
197
198
4.44k
    if (read > 0)
199
2.64k
        pkcrypt->total_in += read;
200
201
4.44k
    return read;
202
4.44k
}
203
204
0
int32_t mz_stream_pkcrypt_write(void *stream, const void *buf, int32_t size) {
205
0
    mz_stream_pkcrypt *pkcrypt = (mz_stream_pkcrypt *)stream;
206
0
    const uint8_t *buf_ptr = (const uint8_t *)buf;
207
0
    int32_t bytes_to_write = sizeof(pkcrypt->buffer);
208
0
    int32_t total_written = 0;
209
0
    int32_t written = 0;
210
0
    int32_t i = 0;
211
0
    uint16_t t = 0;
212
213
0
    if (size < 0)
214
0
        return MZ_PARAM_ERROR;
215
216
0
    do {
217
0
        if (bytes_to_write > (size - total_written))
218
0
            bytes_to_write = (size - total_written);
219
220
0
        for (i = 0; i < bytes_to_write; i += 1) {
221
0
            pkcrypt->buffer[i] = mz_stream_pkcrypt_encode(stream, *buf_ptr, t);
222
0
            buf_ptr += 1;
223
0
        }
224
225
0
        written = mz_stream_write(pkcrypt->stream.base, pkcrypt->buffer, bytes_to_write);
226
0
        if (written < 0)
227
0
            return written;
228
229
0
        total_written += written;
230
0
    } while (total_written < size && written > 0);
231
232
0
    pkcrypt->total_out += total_written;
233
0
    return total_written;
234
0
}
235
236
0
int64_t mz_stream_pkcrypt_tell(void *stream) {
237
0
    mz_stream_pkcrypt *pkcrypt = (mz_stream_pkcrypt *)stream;
238
0
    return mz_stream_tell(pkcrypt->stream.base);
239
0
}
240
241
0
int32_t mz_stream_pkcrypt_seek(void *stream, int64_t offset, int32_t origin) {
242
0
    mz_stream_pkcrypt *pkcrypt = (mz_stream_pkcrypt *)stream;
243
0
    return mz_stream_seek(pkcrypt->stream.base, offset, origin);
244
0
}
245
246
0
int32_t mz_stream_pkcrypt_close(void *stream) {
247
0
    mz_stream_pkcrypt *pkcrypt = (mz_stream_pkcrypt *)stream;
248
0
    pkcrypt->initialized = 0;
249
0
    return MZ_OK;
250
0
}
251
252
0
int32_t mz_stream_pkcrypt_error(void *stream) {
253
0
    mz_stream_pkcrypt *pkcrypt = (mz_stream_pkcrypt *)stream;
254
0
    return pkcrypt->error;
255
0
}
256
257
5.20k
void mz_stream_pkcrypt_set_password(void *stream, const char *password) {
258
5.20k
    mz_stream_pkcrypt *pkcrypt = (mz_stream_pkcrypt *)stream;
259
5.20k
    pkcrypt->password = password;
260
5.20k
}
261
262
5.20k
void mz_stream_pkcrypt_set_verify(void *stream, uint8_t verify1, uint8_t verify2) {
263
5.20k
    mz_stream_pkcrypt *pkcrypt = (mz_stream_pkcrypt *)stream;
264
5.20k
    pkcrypt->verify1 = verify1;
265
5.20k
    pkcrypt->verify2 = verify2;
266
5.20k
}
267
268
0
void mz_stream_pkcrypt_get_verify(void *stream, uint8_t *verify1, uint8_t *verify2) {
269
0
    mz_stream_pkcrypt *pkcrypt = (mz_stream_pkcrypt *)stream;
270
0
    *verify1 = pkcrypt->verify1;
271
0
    *verify2 = pkcrypt->verify2;
272
0
}
273
274
10.1k
int32_t mz_stream_pkcrypt_get_prop_int64(void *stream, int32_t prop, int64_t *value) {
275
10.1k
    mz_stream_pkcrypt *pkcrypt = (mz_stream_pkcrypt *)stream;
276
10.1k
    switch (prop) {
277
0
    case MZ_STREAM_PROP_TOTAL_IN:
278
0
        *value = pkcrypt->total_in;
279
0
        break;
280
0
    case MZ_STREAM_PROP_TOTAL_OUT:
281
0
        *value = pkcrypt->total_out;
282
0
        break;
283
0
    case MZ_STREAM_PROP_TOTAL_IN_MAX:
284
0
        *value = pkcrypt->max_total_in;
285
0
        break;
286
5.09k
    case MZ_STREAM_PROP_HEADER_SIZE:
287
5.09k
        *value = MZ_PKCRYPT_HEADER_SIZE;
288
5.09k
        break;
289
5.09k
    case MZ_STREAM_PROP_FOOTER_SIZE:
290
5.09k
        *value = 0;
291
5.09k
        break;
292
0
    default:
293
0
        return MZ_EXIST_ERROR;
294
10.1k
    }
295
10.1k
    return MZ_OK;
296
10.1k
}
297
298
5.09k
int32_t mz_stream_pkcrypt_set_prop_int64(void *stream, int32_t prop, int64_t value) {
299
5.09k
    mz_stream_pkcrypt *pkcrypt = (mz_stream_pkcrypt *)stream;
300
5.09k
    switch (prop) {
301
5.09k
    case MZ_STREAM_PROP_TOTAL_IN_MAX:
302
5.09k
        pkcrypt->max_total_in = value;
303
5.09k
        break;
304
0
    default:
305
0
        return MZ_EXIST_ERROR;
306
5.09k
    }
307
5.09k
    return MZ_OK;
308
5.09k
}
309
310
5.20k
void *mz_stream_pkcrypt_create(void **stream) {
311
5.20k
    mz_stream_pkcrypt *pkcrypt = NULL;
312
313
5.20k
    pkcrypt = (mz_stream_pkcrypt *)calloc(1, sizeof(mz_stream_pkcrypt));
314
5.20k
    if (pkcrypt)
315
5.20k
        pkcrypt->stream.vtbl = &mz_stream_pkcrypt_vtbl;
316
5.20k
    if (stream)
317
5.20k
        *stream = pkcrypt;
318
319
5.20k
    return pkcrypt;
320
5.20k
}
321
322
5.20k
void mz_stream_pkcrypt_delete(void **stream) {
323
5.20k
    mz_stream_pkcrypt *pkcrypt = NULL;
324
5.20k
    if (!stream)
325
0
        return;
326
5.20k
    pkcrypt = (mz_stream_pkcrypt *)*stream;
327
5.20k
    if (pkcrypt)
328
5.20k
        free(pkcrypt);
329
5.20k
    *stream = NULL;
330
5.20k
}
331
332
0
void *mz_stream_pkcrypt_get_interface(void) {
333
0
    return (void *)&mz_stream_pkcrypt_vtbl;
334
0
}