Coverage Report

Created: 2023-03-26 06:14

/src/minizip-ng/mz_strm_wzaes.c
Line
Count
Source (jump to first uncovered line)
1
/* mz_strm_wzaes.c -- Stream for WinZip AES 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-2010 Brian Gladman, Worcester, UK
7
8
   This program is distributed under the terms of the same license as zlib.
9
   See the accompanying LICENSE file for the full text of the license.
10
*/
11
12
#include "mz.h"
13
#include "mz_crypt.h"
14
#include "mz_strm.h"
15
#include "mz_strm_wzaes.h"
16
17
/***************************************************************************/
18
19
1.71k
#define MZ_AES_KEYING_ITERATIONS    (1000)
20
3.36k
#define MZ_AES_SALT_LENGTH(MODE)    (4 * (MODE & 3) + 4)
21
#define MZ_AES_SALT_LENGTH_MAX      (16)
22
1.72k
#define MZ_AES_PW_LENGTH_MAX        (128)
23
11.9k
#define MZ_AES_PW_VERIFY_SIZE       (2)
24
1.64k
#define MZ_AES_AUTHCODE_SIZE        (10)
25
26
/***************************************************************************/
27
28
static mz_stream_vtbl mz_stream_wzaes_vtbl = {
29
    mz_stream_wzaes_open,
30
    mz_stream_wzaes_is_open,
31
    mz_stream_wzaes_read,
32
    mz_stream_wzaes_write,
33
    mz_stream_wzaes_tell,
34
    mz_stream_wzaes_seek,
35
    mz_stream_wzaes_close,
36
    mz_stream_wzaes_error,
37
    mz_stream_wzaes_create,
38
    mz_stream_wzaes_delete,
39
    mz_stream_wzaes_get_prop_int64,
40
    mz_stream_wzaes_set_prop_int64
41
};
42
43
/***************************************************************************/
44
45
typedef struct mz_stream_wzaes_s {
46
    mz_stream       stream;
47
    int32_t         mode;
48
    int32_t         error;
49
    int16_t         initialized;
50
    uint8_t         buffer[UINT16_MAX];
51
    int64_t         total_in;
52
    int64_t         max_total_in;
53
    int64_t         total_out;
54
    int16_t         encryption_mode;
55
    const char      *password;
56
    void            *aes;
57
    uint32_t        crypt_pos;
58
    uint8_t         crypt_block[MZ_AES_BLOCK_SIZE];
59
    void            *hmac;
60
    uint8_t         nonce[MZ_AES_BLOCK_SIZE];
61
} mz_stream_wzaes;
62
63
/***************************************************************************/
64
65
1.72k
int32_t mz_stream_wzaes_open(void *stream, const char *path, int32_t mode) {
66
1.72k
    mz_stream_wzaes *wzaes = (mz_stream_wzaes *)stream;
67
1.72k
    uint16_t salt_length = 0;
68
1.72k
    uint16_t password_length = 0;
69
1.72k
    uint16_t key_length = 0;
70
1.72k
    uint8_t kbuf[2 * MZ_AES_KEY_LENGTH_MAX + MZ_AES_PW_VERIFY_SIZE];
71
1.72k
    uint8_t verify[MZ_AES_PW_VERIFY_SIZE];
72
1.72k
    uint8_t verify_expected[MZ_AES_PW_VERIFY_SIZE];
73
1.72k
    uint8_t salt_value[MZ_AES_SALT_LENGTH_MAX];
74
1.72k
    const char *password = path;
75
76
1.72k
    wzaes->total_in = 0;
77
1.72k
    wzaes->total_out = 0;
78
1.72k
    wzaes->initialized = 0;
79
80
1.72k
    if (mz_stream_is_open(wzaes->stream.base) != MZ_OK)
81
0
        return MZ_OPEN_ERROR;
82
83
1.72k
    if (!password)
84
1.72k
        password = wzaes->password;
85
1.72k
    if (!password)
86
0
        return MZ_PARAM_ERROR;
87
1.72k
    password_length = (uint16_t)strlen(password);
88
1.72k
    if (password_length > MZ_AES_PW_LENGTH_MAX)
89
0
        return MZ_PARAM_ERROR;
90
91
1.72k
    if (wzaes->encryption_mode < 1 || wzaes->encryption_mode > 3)
92
11
        return MZ_PARAM_ERROR;
93
94
1.71k
    salt_length = MZ_AES_SALT_LENGTH(wzaes->encryption_mode);
95
96
1.71k
    if (mode & MZ_OPEN_MODE_WRITE) {
97
0
        mz_crypt_rand(salt_value, salt_length);
98
1.71k
    } else if (mode & MZ_OPEN_MODE_READ) {
99
1.71k
        if (mz_stream_read(wzaes->stream.base, salt_value, salt_length) != salt_length)
100
7
            return MZ_READ_ERROR;
101
1.71k
    }
102
103
1.71k
    key_length = MZ_AES_KEY_LENGTH(wzaes->encryption_mode);
104
105
    /* Derive the encryption and authentication keys and the password verifier */
106
1.71k
    mz_crypt_pbkdf2((uint8_t *)password, password_length, salt_value, salt_length,
107
1.71k
        MZ_AES_KEYING_ITERATIONS, kbuf, 2 * key_length + MZ_AES_PW_VERIFY_SIZE);
108
109
    /* Initialize the encryption nonce and buffer pos */
110
1.71k
    wzaes->crypt_pos = MZ_AES_BLOCK_SIZE;
111
1.71k
    memset(wzaes->nonce, 0, sizeof(wzaes->nonce));
112
113
    /* Initialize for encryption using key 1 */
114
1.71k
    mz_crypt_aes_reset(wzaes->aes);
115
1.71k
    mz_crypt_aes_set_mode(wzaes->aes, wzaes->encryption_mode);
116
1.71k
    mz_crypt_aes_set_encrypt_key(wzaes->aes, kbuf, key_length);
117
118
    /* Initialize for authentication using key 2 */
119
1.71k
    mz_crypt_hmac_reset(wzaes->hmac);
120
1.71k
    mz_crypt_hmac_set_algorithm(wzaes->hmac, MZ_HASH_SHA1);
121
1.71k
    mz_crypt_hmac_init(wzaes->hmac, kbuf + key_length, key_length);
122
123
1.71k
    memcpy(verify, kbuf + (2 * key_length), MZ_AES_PW_VERIFY_SIZE);
124
125
1.71k
    if (mode & MZ_OPEN_MODE_WRITE) {
126
0
        if (mz_stream_write(wzaes->stream.base, salt_value, salt_length) != salt_length)
127
0
            return MZ_WRITE_ERROR;
128
129
0
        wzaes->total_out += salt_length;
130
131
0
        if (mz_stream_write(wzaes->stream.base, verify, MZ_AES_PW_VERIFY_SIZE) != MZ_AES_PW_VERIFY_SIZE)
132
0
            return MZ_WRITE_ERROR;
133
134
0
        wzaes->total_out += MZ_AES_PW_VERIFY_SIZE;
135
1.71k
    } else if (mode & MZ_OPEN_MODE_READ) {
136
1.71k
        wzaes->total_in += salt_length;
137
138
1.71k
        if (mz_stream_read(wzaes->stream.base, verify_expected, MZ_AES_PW_VERIFY_SIZE) != MZ_AES_PW_VERIFY_SIZE)
139
2
            return MZ_READ_ERROR;
140
141
1.70k
        wzaes->total_in += MZ_AES_PW_VERIFY_SIZE;
142
143
1.70k
        if (memcmp(verify_expected, verify, MZ_AES_PW_VERIFY_SIZE) != 0)
144
61
            return MZ_PASSWORD_ERROR;
145
1.70k
    }
146
147
1.64k
    wzaes->mode = mode;
148
1.64k
    wzaes->initialized = 1;
149
150
1.64k
    return MZ_OK;
151
1.71k
}
152
153
4.72k
int32_t mz_stream_wzaes_is_open(void *stream) {
154
4.72k
    mz_stream_wzaes *wzaes = (mz_stream_wzaes *)stream;
155
4.72k
    if (!wzaes->initialized)
156
0
        return MZ_OPEN_ERROR;
157
4.72k
    return MZ_OK;
158
4.72k
}
159
160
1.21k
static int32_t mz_stream_wzaes_ctr_encrypt(void *stream, uint8_t *buf, int32_t size) {
161
1.21k
    mz_stream_wzaes *wzaes = (mz_stream_wzaes *)stream;
162
1.21k
    uint32_t pos = wzaes->crypt_pos;
163
1.21k
    uint32_t i = 0;
164
1.21k
    int32_t err = MZ_OK;
165
166
1.01M
    while (i < (uint32_t)size) {
167
1.01M
        if (pos == MZ_AES_BLOCK_SIZE) {
168
63.8k
            uint32_t j = 0;
169
170
            /* Increment encryption nonce */
171
63.8k
            while (j < 8 && !++wzaes->nonce[j])
172
0
                j += 1;
173
174
            /* Encrypt the nonce to form next xor buffer */
175
63.8k
            memcpy(wzaes->crypt_block, wzaes->nonce, MZ_AES_BLOCK_SIZE);
176
63.8k
            mz_crypt_aes_encrypt(wzaes->aes, wzaes->crypt_block, sizeof(wzaes->crypt_block));
177
63.8k
            pos = 0;
178
63.8k
        }
179
180
1.01M
        buf[i++] ^= wzaes->crypt_block[pos++];
181
1.01M
    }
182
183
1.21k
    wzaes->crypt_pos = pos;
184
1.21k
    return err;
185
1.21k
}
186
187
1.53k
int32_t mz_stream_wzaes_read(void *stream, void *buf, int32_t size) {
188
1.53k
    mz_stream_wzaes *wzaes = (mz_stream_wzaes *)stream;
189
1.53k
    int64_t max_total_in = 0;
190
1.53k
    int32_t bytes_to_read = size;
191
1.53k
    int32_t read = 0;
192
193
1.53k
    max_total_in = wzaes->max_total_in - MZ_AES_FOOTER_SIZE;
194
1.53k
    if ((int64_t)bytes_to_read > (max_total_in - wzaes->total_in))
195
320
        bytes_to_read = (int32_t)(max_total_in - wzaes->total_in);
196
197
1.53k
    read = mz_stream_read(wzaes->stream.base, buf, bytes_to_read);
198
199
1.53k
    if (read > 0) {
200
1.21k
        mz_crypt_hmac_update(wzaes->hmac, (uint8_t *)buf, read);
201
1.21k
        mz_stream_wzaes_ctr_encrypt(stream, (uint8_t *)buf, read);
202
203
1.21k
        wzaes->total_in += read;
204
1.21k
    }
205
206
1.53k
    return read;
207
1.53k
}
208
209
0
int32_t mz_stream_wzaes_write(void *stream, const void *buf, int32_t size) {
210
0
    mz_stream_wzaes *wzaes = (mz_stream_wzaes *)stream;
211
0
    const uint8_t *buf_ptr = (const uint8_t *)buf;
212
0
    int32_t bytes_to_write = sizeof(wzaes->buffer);
213
0
    int32_t total_written = 0;
214
0
    int32_t written = 0;
215
216
0
    if (size < 0)
217
0
        return MZ_PARAM_ERROR;
218
219
0
    do {
220
0
        if (bytes_to_write > (size - total_written))
221
0
            bytes_to_write = (size - total_written);
222
223
0
        memcpy(wzaes->buffer, buf_ptr, bytes_to_write);
224
0
        buf_ptr += bytes_to_write;
225
226
0
        mz_stream_wzaes_ctr_encrypt(stream, (uint8_t *)wzaes->buffer, bytes_to_write);
227
0
        mz_crypt_hmac_update(wzaes->hmac, wzaes->buffer, bytes_to_write);
228
229
0
        written = mz_stream_write(wzaes->stream.base, wzaes->buffer, bytes_to_write);
230
0
        if (written < 0)
231
0
            return written;
232
233
0
        total_written += written;
234
0
    } while (total_written < size && written > 0);
235
236
0
    wzaes->total_out += total_written;
237
0
    return total_written;
238
0
}
239
240
0
int64_t mz_stream_wzaes_tell(void *stream) {
241
0
    mz_stream_wzaes *wzaes = (mz_stream_wzaes *)stream;
242
0
    return mz_stream_tell(wzaes->stream.base);
243
0
}
244
245
0
int32_t mz_stream_wzaes_seek(void *stream, int64_t offset, int32_t origin) {
246
0
    mz_stream_wzaes *wzaes = (mz_stream_wzaes *)stream;
247
0
    return mz_stream_seek(wzaes->stream.base, offset, origin);
248
0
}
249
250
0
int32_t mz_stream_wzaes_close(void *stream) {
251
0
    mz_stream_wzaes *wzaes = (mz_stream_wzaes *)stream;
252
0
    uint8_t expected_hash[MZ_AES_AUTHCODE_SIZE];
253
0
    uint8_t computed_hash[MZ_HASH_SHA1_SIZE];
254
255
0
    mz_crypt_hmac_end(wzaes->hmac, computed_hash, sizeof(computed_hash));
256
257
0
    if (wzaes->mode & MZ_OPEN_MODE_WRITE) {
258
0
        if (mz_stream_write(wzaes->stream.base, computed_hash, MZ_AES_AUTHCODE_SIZE) != MZ_AES_AUTHCODE_SIZE)
259
0
            return MZ_WRITE_ERROR;
260
261
0
        wzaes->total_out += MZ_AES_AUTHCODE_SIZE;
262
0
    } else if (wzaes->mode & MZ_OPEN_MODE_READ) {
263
0
        if (mz_stream_read(wzaes->stream.base, expected_hash, MZ_AES_AUTHCODE_SIZE) != MZ_AES_AUTHCODE_SIZE)
264
0
            return MZ_READ_ERROR;
265
266
0
        wzaes->total_in += MZ_AES_AUTHCODE_SIZE;
267
268
        /* If entire entry was not read this will fail */
269
0
        if (memcmp(computed_hash, expected_hash, MZ_AES_AUTHCODE_SIZE) != 0)
270
0
            return MZ_CRC_ERROR;
271
0
    }
272
273
0
    wzaes->initialized = 0;
274
0
    return MZ_OK;
275
0
}
276
277
0
int32_t mz_stream_wzaes_error(void *stream) {
278
0
    mz_stream_wzaes *wzaes = (mz_stream_wzaes *)stream;
279
0
    return wzaes->error;
280
0
}
281
282
1.72k
void mz_stream_wzaes_set_password(void *stream, const char *password) {
283
1.72k
    mz_stream_wzaes *wzaes = (mz_stream_wzaes *)stream;
284
1.72k
    wzaes->password = password;
285
1.72k
}
286
287
1.72k
void mz_stream_wzaes_set_encryption_mode(void *stream, int16_t encryption_mode) {
288
1.72k
    mz_stream_wzaes *wzaes = (mz_stream_wzaes *)stream;
289
1.72k
    wzaes->encryption_mode = encryption_mode;
290
1.72k
}
291
292
3.29k
int32_t mz_stream_wzaes_get_prop_int64(void *stream, int32_t prop, int64_t *value) {
293
3.29k
    mz_stream_wzaes *wzaes = (mz_stream_wzaes *)stream;
294
3.29k
    switch (prop) {
295
0
    case MZ_STREAM_PROP_TOTAL_IN:
296
0
        *value = wzaes->total_in;
297
0
        break;
298
0
    case MZ_STREAM_PROP_TOTAL_OUT:
299
0
        *value = wzaes->total_out;
300
0
        break;
301
0
    case MZ_STREAM_PROP_TOTAL_IN_MAX:
302
0
        *value = wzaes->max_total_in;
303
0
        break;
304
1.64k
    case MZ_STREAM_PROP_HEADER_SIZE:
305
1.64k
        *value = MZ_AES_SALT_LENGTH((int64_t)wzaes->encryption_mode) + MZ_AES_PW_VERIFY_SIZE;
306
1.64k
        break;
307
1.64k
    case MZ_STREAM_PROP_FOOTER_SIZE:
308
1.64k
        *value = MZ_AES_AUTHCODE_SIZE;
309
1.64k
        break;
310
0
    default:
311
0
        return MZ_EXIST_ERROR;
312
3.29k
    }
313
3.29k
    return MZ_OK;
314
3.29k
}
315
316
1.64k
int32_t mz_stream_wzaes_set_prop_int64(void *stream, int32_t prop, int64_t value) {
317
1.64k
    mz_stream_wzaes *wzaes = (mz_stream_wzaes *)stream;
318
1.64k
    switch (prop) {
319
1.64k
    case MZ_STREAM_PROP_TOTAL_IN_MAX:
320
1.64k
        wzaes->max_total_in = value;
321
1.64k
        break;
322
0
    default:
323
0
        return MZ_EXIST_ERROR;
324
1.64k
    }
325
1.64k
    return MZ_OK;
326
1.64k
}
327
328
1.72k
void *mz_stream_wzaes_create(void **stream) {
329
1.72k
    mz_stream_wzaes *wzaes = NULL;
330
331
1.72k
    wzaes = (mz_stream_wzaes *)calloc(1, sizeof(mz_stream_wzaes));
332
1.72k
    if (wzaes) {
333
1.72k
        wzaes->stream.vtbl = &mz_stream_wzaes_vtbl;
334
1.72k
        wzaes->encryption_mode = MZ_AES_ENCRYPTION_MODE_256;
335
336
1.72k
        mz_crypt_hmac_create(&wzaes->hmac);
337
1.72k
        mz_crypt_aes_create(&wzaes->aes);
338
1.72k
    }
339
1.72k
    if (stream)
340
1.72k
        *stream = wzaes;
341
342
1.72k
    return wzaes;
343
1.72k
}
344
345
1.72k
void mz_stream_wzaes_delete(void **stream) {
346
1.72k
    mz_stream_wzaes *wzaes = NULL;
347
1.72k
    if (!stream)
348
0
        return;
349
1.72k
    wzaes = (mz_stream_wzaes *)*stream;
350
1.72k
    if (wzaes) {
351
1.72k
        mz_crypt_aes_delete(&wzaes->aes);
352
1.72k
        mz_crypt_hmac_delete(&wzaes->hmac);
353
1.72k
        free(wzaes);
354
1.72k
    }
355
1.72k
    *stream = NULL;
356
1.72k
}
357
358
0
void *mz_stream_wzaes_get_interface(void) {
359
0
    return (void *)&mz_stream_wzaes_vtbl;
360
0
}