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