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