Mercurial > embed
comparison libzip/lib/zip_source_pkware.c @ 4:2306f4b04790
libzip: import 1.1.2
author | David Demelier <markand@malikania.fr> |
---|---|
date | Wed, 24 Feb 2016 21:19:28 +0100 |
parents | |
children | 056ee6b5913e |
comparison
equal
deleted
inserted
replaced
3:543b0653ea27 | 4:2306f4b04790 |
---|---|
1 /* | |
2 zip_source_pkware.c -- Traditional PKWARE de/encryption routines | |
3 Copyright (C) 2009-2015 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 <libzip@nih.at> | |
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 | |
35 #include <stdlib.h> | |
36 #include <string.h> | |
37 | |
38 #include "zipint.h" | |
39 | |
40 struct trad_pkware { | |
41 zip_error_t error; | |
42 zip_uint32_t key[3]; | |
43 }; | |
44 | |
45 #define HEADERLEN 12 | |
46 #define KEY0 305419896 | |
47 #define KEY1 591751049 | |
48 #define KEY2 878082192 | |
49 | |
50 | |
51 static void decrypt(struct trad_pkware *, zip_uint8_t *, | |
52 const zip_uint8_t *, zip_uint64_t, int); | |
53 static int decrypt_header(zip_source_t *, struct trad_pkware *); | |
54 static zip_int64_t pkware_decrypt(zip_source_t *, void *, void *, | |
55 zip_uint64_t, zip_source_cmd_t); | |
56 static void pkware_free(struct trad_pkware *); | |
57 | |
58 | |
59 zip_source_t * | |
60 zip_source_pkware(zip_t *za, zip_source_t *src, | |
61 zip_uint16_t em, int flags, const char *password) | |
62 { | |
63 struct trad_pkware *ctx; | |
64 zip_source_t *s2; | |
65 | |
66 if (password == NULL || src == NULL || em != ZIP_EM_TRAD_PKWARE) { | |
67 zip_error_set(&za->error, ZIP_ER_INVAL, 0); | |
68 return NULL; | |
69 } | |
70 if (flags & ZIP_CODEC_ENCODE) { | |
71 zip_error_set(&za->error, ZIP_ER_ENCRNOTSUPP, 0); | |
72 return NULL; | |
73 } | |
74 | |
75 if ((ctx=(struct trad_pkware *)malloc(sizeof(*ctx))) == NULL) { | |
76 zip_error_set(&za->error, ZIP_ER_MEMORY, 0); | |
77 return NULL; | |
78 } | |
79 | |
80 zip_error_init(&ctx->error); | |
81 | |
82 ctx->key[0] = KEY0; | |
83 ctx->key[1] = KEY1; | |
84 ctx->key[2] = KEY2; | |
85 decrypt(ctx, NULL, (const zip_uint8_t *)password, strlen(password), 1); | |
86 | |
87 if ((s2=zip_source_layered(za, src, pkware_decrypt, ctx)) == NULL) { | |
88 pkware_free(ctx); | |
89 return NULL; | |
90 } | |
91 | |
92 return s2; | |
93 } | |
94 | |
95 | |
96 static void | |
97 decrypt(struct trad_pkware *ctx, zip_uint8_t *out, const zip_uint8_t *in, | |
98 zip_uint64_t len, int update_only) | |
99 { | |
100 zip_uint16_t tmp; | |
101 zip_uint64_t i; | |
102 Bytef b; | |
103 | |
104 for (i=0; i<len; i++) { | |
105 b = in[i]; | |
106 | |
107 if (!update_only) { | |
108 /* decrypt next byte */ | |
109 tmp = (zip_uint16_t)(ctx->key[2] | 2); | |
110 tmp = (zip_uint16_t)(((zip_uint32_t)tmp * (tmp ^ 1)) >> 8); | |
111 b ^= (Bytef)tmp; | |
112 } | |
113 | |
114 /* store cleartext */ | |
115 if (out) | |
116 out[i] = b; | |
117 | |
118 /* update keys */ | |
119 ctx->key[0] = (zip_uint32_t)crc32(ctx->key[0] ^ 0xffffffffUL, &b, 1) ^ 0xffffffffUL; | |
120 ctx->key[1] = (ctx->key[1] + (ctx->key[0] & 0xff)) * 134775813 + 1; | |
121 b = (Bytef)(ctx->key[1] >> 24); | |
122 ctx->key[2] = (zip_uint32_t)crc32(ctx->key[2] ^ 0xffffffffUL, &b, 1) ^ 0xffffffffUL; | |
123 } | |
124 } | |
125 | |
126 | |
127 static int | |
128 decrypt_header(zip_source_t *src, struct trad_pkware *ctx) | |
129 { | |
130 zip_uint8_t header[HEADERLEN]; | |
131 struct zip_stat st; | |
132 zip_int64_t n; | |
133 unsigned short dostime, dosdate; | |
134 | |
135 if ((n=zip_source_read(src, header, HEADERLEN)) < 0) { | |
136 _zip_error_set_from_source(&ctx->error, src); | |
137 return -1; | |
138 } | |
139 | |
140 if (n != HEADERLEN) { | |
141 zip_error_set(&ctx->error, ZIP_ER_EOF, 0); | |
142 return -1; | |
143 } | |
144 | |
145 decrypt(ctx, header, header, HEADERLEN, 0); | |
146 | |
147 if (zip_source_stat(src, &st) < 0) { | |
148 /* stat failed, skip password validation */ | |
149 return 0; | |
150 } | |
151 | |
152 _zip_u2d_time(st.mtime, &dostime, &dosdate); | |
153 | |
154 if (header[HEADERLEN-1] != st.crc>>24 && header[HEADERLEN-1] != dostime>>8) { | |
155 zip_error_set(&ctx->error, ZIP_ER_WRONGPASSWD, 0); | |
156 return -1; | |
157 } | |
158 | |
159 return 0; | |
160 } | |
161 | |
162 | |
163 static zip_int64_t | |
164 pkware_decrypt(zip_source_t *src, void *ud, void *data, | |
165 zip_uint64_t len, zip_source_cmd_t cmd) | |
166 { | |
167 struct trad_pkware *ctx; | |
168 zip_int64_t n; | |
169 | |
170 ctx = (struct trad_pkware *)ud; | |
171 | |
172 switch (cmd) { | |
173 case ZIP_SOURCE_OPEN: | |
174 if (decrypt_header(src, ctx) < 0) | |
175 return -1; | |
176 return 0; | |
177 | |
178 case ZIP_SOURCE_READ: | |
179 if ((n=zip_source_read(src, data, len)) < 0) { | |
180 _zip_error_set_from_source(&ctx->error, src); | |
181 return -1; | |
182 } | |
183 | |
184 decrypt((struct trad_pkware *)ud, (zip_uint8_t *)data, (zip_uint8_t *)data, (zip_uint64_t)n, 0); | |
185 return n; | |
186 | |
187 case ZIP_SOURCE_CLOSE: | |
188 return 0; | |
189 | |
190 case ZIP_SOURCE_STAT: | |
191 { | |
192 zip_stat_t *st; | |
193 | |
194 st = (zip_stat_t *)data; | |
195 | |
196 st->encryption_method = ZIP_EM_NONE; | |
197 st->valid |= ZIP_STAT_ENCRYPTION_METHOD; | |
198 /* TODO: deduce HEADERLEN from size for uncompressed */ | |
199 if (st->valid & ZIP_STAT_COMP_SIZE) | |
200 st->comp_size -= HEADERLEN; | |
201 | |
202 return 0; | |
203 } | |
204 | |
205 case ZIP_SOURCE_SUPPORTS: | |
206 return zip_source_make_command_bitmap(ZIP_SOURCE_OPEN, ZIP_SOURCE_READ, ZIP_SOURCE_CLOSE, ZIP_SOURCE_STAT, ZIP_SOURCE_ERROR, ZIP_SOURCE_FREE, -1); | |
207 | |
208 case ZIP_SOURCE_ERROR: | |
209 return zip_error_to_data(&ctx->error, data, len); | |
210 | |
211 case ZIP_SOURCE_FREE: | |
212 pkware_free(ctx); | |
213 return 0; | |
214 | |
215 default: | |
216 zip_error_set(&ctx->error, ZIP_ER_INVAL, 0); | |
217 return -1; | |
218 } | |
219 } | |
220 | |
221 | |
222 static void | |
223 pkware_free(struct trad_pkware *ctx) | |
224 { | |
225 free(ctx); | |
226 } |