... | ... |
@@ -53,10 +53,139 @@ |
53 | 53 |
#define UNZIP_PRIVATE |
54 | 54 |
#include "unzip.h" |
55 | 55 |
|
56 |
+#define ZIP_CRC32(r,c,b,l) \ |
|
57 |
+ do { \ |
|
58 |
+ r = crc32(~c,b,l); \ |
|
59 |
+ r = ~r; \ |
|
60 |
+ } while(0) |
|
61 |
+ |
|
62 |
+ |
|
56 | 63 |
static int wrap_inflateinit2(void *a, int b) { |
57 | 64 |
return inflateInit2(a, b); |
58 | 65 |
} |
59 | 66 |
|
67 |
+/* zip update keys, taken from zip specification */ |
|
68 |
+static inline void zupdatekey(uint32_t key[3], unsigned char input) |
|
69 |
+{ |
|
70 |
+ unsigned char tmp[1]; |
|
71 |
+ unsigned long crctmp; |
|
72 |
+ |
|
73 |
+ tmp[0] = input; |
|
74 |
+ ZIP_CRC32(key[0], key[0], tmp, 1); |
|
75 |
+ |
|
76 |
+ key[1] = key[1] + (key[0] & 0xff); |
|
77 |
+ key[1] = key[1] * 134775813 + 1; |
|
78 |
+ |
|
79 |
+ tmp[0] = key[1] >> 24; |
|
80 |
+ ZIP_CRC32(key[2], key[2], tmp, 1); |
|
81 |
+} |
|
82 |
+ |
|
83 |
+/* zip init keys */ |
|
84 |
+static inline void zinitkey(uint32_t key[3], struct cli_pwdict *password) |
|
85 |
+{ |
|
86 |
+ int i; |
|
87 |
+ |
|
88 |
+ /* intialize keys, these are specified but the zip specification */ |
|
89 |
+ key[0] = 305419896L; |
|
90 |
+ key[1] = 591751049L; |
|
91 |
+ key[2] = 878082192L; |
|
92 |
+ |
|
93 |
+ /* update keys with password */ |
|
94 |
+ for (i = 0; i < password->length; i++) |
|
95 |
+ zupdatekey(key, password->passwd[i]); |
|
96 |
+} |
|
97 |
+ |
|
98 |
+/* zip decrypt byte */ |
|
99 |
+static inline unsigned char zdecryptbyte(uint32_t key[3]) |
|
100 |
+{ |
|
101 |
+ unsigned short temp; |
|
102 |
+ temp = key[2] | 2; |
|
103 |
+ return ((temp * (temp ^ 1)) >> 8); |
|
104 |
+} |
|
105 |
+ |
|
106 |
+/* zip decrypt, CL_EPARSE = could not apply a password, csize includes the decryption header */ |
|
107 |
+/* TODO - search for strong encryption header (0x0017) and handle them */ |
|
108 |
+static inline int zdecrypt(const uint8_t *src, uint32_t csize, uint32_t usize, const uint8_t *lh, unsigned int *fu, cli_ctx *ctx, char *tmpd, zip_cb zcb) |
|
109 |
+{ |
|
110 |
+ int i, ret, v = 0; |
|
111 |
+ uint32_t key[3]; |
|
112 |
+ uint8_t eh[12]; /* encryption header buffer */ |
|
113 |
+ struct cli_pwdict *password; |
|
114 |
+ |
|
115 |
+ if (!ctx || !ctx->engine) |
|
116 |
+ return CL_ENULLARG; |
|
117 |
+ |
|
118 |
+ /* TODO - dconf going here */ |
|
119 |
+ |
|
120 |
+ password = ctx->engine->pw_dict; |
|
121 |
+ |
|
122 |
+ while (password) { |
|
123 |
+ if ((password->container != CL_TYPE_ANY) && (password->container != CL_TYPE_ZIP)) { |
|
124 |
+ if ((password->container > CL_TYPE_ZIP) && (password->container > CL_TYPE_ANY)) |
|
125 |
+ break; |
|
126 |
+ password = password->next; |
|
127 |
+ continue; |
|
128 |
+ } |
|
129 |
+ |
|
130 |
+ zinitkey(key, password); |
|
131 |
+ |
|
132 |
+ /* decrypting the encryption header */ |
|
133 |
+ memcpy(eh, src, SIZEOF_EH); |
|
134 |
+ |
|
135 |
+ for (i = 0; i < SIZEOF_EH; i++) { |
|
136 |
+ eh[i] ^= zdecryptbyte(key); |
|
137 |
+ zupdatekey(key, eh[i]); |
|
138 |
+ } |
|
139 |
+ |
|
140 |
+ /* verify that the password is correct */ |
|
141 |
+ if (LH_version > 20) { /* higher than 2.0 */ |
|
142 |
+ uint16_t a = eh[SIZEOF_EH-1]; |
|
143 |
+ |
|
144 |
+ if (LH_flags & F_USEDD) { |
|
145 |
+ cli_dbgmsg("verify(%u): 0x%02x 0x%x (moddate)\n", LH_version, a, LH_mtime); |
|
146 |
+ if (a == ((LH_mtime >> 8) & 0xff)) |
|
147 |
+ v = 1; |
|
148 |
+ } else { |
|
149 |
+ cli_dbgmsg("verify(%u): 0x%02x 0x%x (crc32)\n", LH_version, a, LH_crc32); |
|
150 |
+ if (a == ((LH_crc32 >> 24) & 0xff)) |
|
151 |
+ v = 1; |
|
152 |
+ } |
|
153 |
+ } else { |
|
154 |
+ uint16_t a = eh[SIZEOF_EH-1], b = eh[SIZEOF_EH-2]; |
|
155 |
+ |
|
156 |
+ if (LH_flags & F_USEDD) { |
|
157 |
+ cli_dbgmsg("verify(%u): 0x0000%02x%02x 0x%x (moddate)\n", LH_version, a, b, LH_mtime); |
|
158 |
+ if ((b | (a << 8)) == (LH_mtime & 0xffff)) |
|
159 |
+ v = 1; |
|
160 |
+ } else { |
|
161 |
+ cli_dbgmsg("verify(%u): 0x0000%02x%02x 0x%x (crc32)\n", LH_version, eh[SIZEOF_EH-1], eh[SIZEOF_EH-2], LH_crc32); |
|
162 |
+ if ((b | (a << 8)) == ((LH_crc32 >> 16) & 0xffff)) |
|
163 |
+ v = 1; |
|
164 |
+ } |
|
165 |
+ } |
|
166 |
+ |
|
167 |
+ if (v) { |
|
168 |
+ cli_dbgmsg("zdecrypt: password [%s] matches\n", password->name); |
|
169 |
+#if 0 |
|
170 |
+ /* decrypt data to new fmap -> buffer */ |
|
171 |
+ |
|
172 |
+ /* call unz on decrypted output */ |
|
173 |
+ ret = unz(); |
|
174 |
+ |
|
175 |
+ /* clean-up and return */ |
|
176 |
+ return ret; |
|
177 |
+#else |
|
178 |
+ v = 0; |
|
179 |
+#endif |
|
180 |
+ } |
|
181 |
+ |
|
182 |
+ password = password->next; |
|
183 |
+ } |
|
184 |
+ |
|
185 |
+ cli_dbgmsg("cli_unzip: lh - skipping encrypted file, no valid passwords\n"); |
|
186 |
+ return CL_SUCCESS; |
|
187 |
+} |
|
188 |
+ |
|
60 | 189 |
static int unz(const uint8_t *src, uint32_t csize, uint32_t usize, uint16_t method, uint16_t flags, unsigned int *fu, cli_ctx *ctx, char *tmpd, zip_cb zcb) { |
61 | 190 |
char name[1024], obuf[BUFSIZ]; |
62 | 191 |
char *tempfile = name; |
... | ... |
@@ -389,7 +518,8 @@ static unsigned int lhdr(fmap_t *map, uint32_t loff,uint32_t zsize, unsigned int |
389 | 389 |
return 0; |
390 | 390 |
} |
391 | 391 |
if(LH_flags & F_ENCR) { |
392 |
- cli_dbgmsg("cli_unzip: lh - skipping encrypted file\n"); |
|
392 |
+ if(fmap_need_ptr_once(map, zip, csize)) |
|
393 |
+ *ret = zdecrypt(zip, csize, usize, lh, fu, ctx, tmpd, zcb); |
|
393 | 394 |
} else { |
394 | 395 |
if(fmap_need_ptr_once(map, zip, csize)) |
395 | 396 |
*ret = unz(zip, csize, usize, LH_method, LH_flags, fu, ctx, tmpd, zcb); |
... | ... |
@@ -160,6 +160,8 @@ enum ALGO { |
160 | 160 |
#define CH_eattrib ((uint32_t)cli_readint32((uint8_t *)(ch)+38)) |
161 | 161 |
#define CH_off ((uint32_t)cli_readint32((uint8_t *)(ch)+42)) |
162 | 162 |
#define SIZEOF_CH 46 |
163 |
+ |
|
164 |
+#define SIZEOF_EH 12 |
|
163 | 165 |
#endif /* UNZIP_PRIVATE */ |
164 | 166 |
|
165 | 167 |
#endif /* __UNZIP_H */ |