Imported Upstream version 1.3.2
[platform/upstream/libzip.git] / lib / zip_source_winzip_aes_encode.c
1 /*
2   zip_source_winzip_aes.c -- Winzip AES de/encryption routines
3   Copyright (C) 2009-2016 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 #include "gladman-fcrypt.h"
41
42 #define MAX_HEADER_LENGTH (16+PWD_VER_LENGTH)
43 #define HMAC_LENGTH 10
44
45 static unsigned int salt_length[] = { 0, 8, 12, 16 };
46
47 struct winzip_aes {
48     char *password;
49     unsigned int mode;
50     zip_uint16_t encryption_method;
51
52     zip_uint8_t data[MAX_HEADER_LENGTH];
53     zip_buffer_t *buffer;
54
55     fcrypt_ctx fcrypt_ctx;
56     bool eof;
57     zip_error_t error;
58 };
59
60
61 static int encrypt_header(zip_source_t *src, struct winzip_aes *ctx);
62 static void winzip_aes_free(struct winzip_aes *);
63 static zip_int64_t winzip_aes_encrypt(zip_source_t *src, void *ud, void *data, zip_uint64_t len, zip_source_cmd_t cmd);
64 static struct winzip_aes * winzip_aes_new(unsigned int mode, zip_uint16_t encryption_method, const char *password);
65
66
67 zip_source_t *
68 zip_source_winzip_aes_encode(zip_t *za, zip_source_t *src, zip_uint16_t encryption_method, int flags, const char *password)
69 {
70     zip_source_t *s2;
71     unsigned int mode = 0;
72     struct winzip_aes *ctx;
73
74     switch (encryption_method) {
75     case ZIP_EM_AES_128:
76         mode = 1;
77         break;
78     case ZIP_EM_AES_192:
79         mode = 2;
80         break;
81     case ZIP_EM_AES_256:
82         mode = 3;
83         break;
84     }
85         
86     if (password == NULL || src == NULL || mode == 0) {
87         zip_error_set(&za->error, ZIP_ER_INVAL, 0);
88         return NULL;
89     }
90
91     if (strlen(password) > UINT_MAX) {
92         zip_error_set(&za->error, ZIP_ER_INVAL, 0); /* TODO: better error code? (password too long) */
93         return NULL;
94     }
95
96     if ((ctx = winzip_aes_new(mode, encryption_method, password)) == NULL) {
97         zip_error_set(&za->error, ZIP_ER_MEMORY, 0);
98         return NULL;
99     }
100
101     if ((s2 = zip_source_layered(za, src, winzip_aes_encrypt, ctx)) == NULL) {
102         winzip_aes_free(ctx);
103         return NULL;
104     }
105
106     return s2;
107 }
108
109
110 static int
111 encrypt_header(zip_source_t *src, struct winzip_aes *ctx)
112 {
113     if (!zip_random(ctx->data, (zip_uint16_t)salt_length[ctx->mode])) {
114         zip_error_set(&ctx->error, ZIP_ER_INTERNAL, 0);
115         return -1;
116     }   
117     
118     if (_zip_fcrypt_init(ctx->mode, (unsigned char *)ctx->password, (unsigned int)strlen(ctx->password), ctx->data, ctx->data+salt_length[ctx->mode], &ctx->fcrypt_ctx) != 0) {
119         zip_error_set(&ctx->error, ZIP_ER_MEMORY, 0);
120         return -1;
121     }
122
123     if ((ctx->buffer = _zip_buffer_new(ctx->data, salt_length[ctx->mode] + PWD_VER_LENGTH)) == NULL) {
124         zip_error_set(&ctx->error, ZIP_ER_MEMORY, 0);
125         return -1;
126     }
127     
128     return 0;
129 }
130
131
132 static zip_int64_t
133 winzip_aes_encrypt(zip_source_t *src, void *ud, void *data, zip_uint64_t length, zip_source_cmd_t cmd)
134 {
135     struct winzip_aes *ctx;
136     zip_int64_t ret;
137     zip_uint64_t buffer_n, offset, n;
138
139     ctx = (struct winzip_aes *)ud;
140
141     switch (cmd) {
142     case ZIP_SOURCE_OPEN:
143         ctx->eof = false;
144         if (encrypt_header(src, ctx) < 0) {
145             return -1;
146         }
147         return 0;
148
149     case ZIP_SOURCE_READ:
150         buffer_n = 0;
151         
152         if (ctx->buffer) {
153             buffer_n = _zip_buffer_read(ctx->buffer, data, length);
154
155             data = (zip_uint8_t *)data + buffer_n;
156             length -= buffer_n;
157             
158             if (_zip_buffer_eof(ctx->buffer)) {
159                 _zip_buffer_free(ctx->buffer);
160                 ctx->buffer = NULL;
161             }
162         }
163
164         if (ctx->eof) {
165             return (zip_int64_t)buffer_n;
166         }
167
168         if ((ret = zip_source_read(src, data, length)) < 0) {
169             _zip_error_set_from_source(&ctx->error, src);
170             return -1;
171         }
172
173         n = (zip_uint64_t)ret;
174         for (offset = 0; offset < n; offset += ZIP_MIN(n - offset, UINT_MAX)) {
175             _zip_fcrypt_encrypt((zip_uint8_t *)data + offset, (unsigned int)ZIP_MIN(n - offset, UINT_MAX), &ctx->fcrypt_ctx);
176         }
177
178         if (n < length) {
179             ctx->eof = true;
180             _zip_fcrypt_end(ctx->data, &ctx->fcrypt_ctx);
181             if ((ctx->buffer = _zip_buffer_new(ctx->data, HMAC_LENGTH)) == NULL) {
182                 zip_error_set(&ctx->error, ZIP_ER_MEMORY, 0);
183                 /* TODO: return partial read? */
184                 return -1;
185             }
186         }
187
188         return (zip_int64_t)(buffer_n + n);
189
190     case ZIP_SOURCE_CLOSE:
191         return 0;
192
193     case ZIP_SOURCE_STAT:
194     {
195         zip_stat_t *st;
196
197         st = (zip_stat_t *)data;
198         st->encryption_method = ctx->encryption_method;
199         st->valid |= ZIP_STAT_ENCRYPTION_METHOD;
200         if (st->valid & ZIP_STAT_COMP_SIZE) {
201             st->comp_size += 12 + salt_length[ctx->mode];
202         }
203         
204         return 0;
205     }
206             
207     case ZIP_SOURCE_SUPPORTS:
208         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);
209
210     case ZIP_SOURCE_ERROR:
211         return zip_error_to_data(&ctx->error, data, length);
212
213     case ZIP_SOURCE_FREE:
214         winzip_aes_free(ctx);
215         return 0;
216
217     default:
218         zip_error_set(&ctx->error, ZIP_ER_INVAL, 0);
219         return -1;
220     }
221 }
222
223
224 static void
225 winzip_aes_free(struct winzip_aes *ctx)
226 {
227     if (ctx == NULL) {
228         return;
229     }
230
231     _zip_crypto_clear(&ctx->fcrypt_ctx, sizeof(ctx->fcrypt_ctx));
232     _zip_crypto_clear(ctx->password, strlen(ctx->password));
233     free(ctx->password);
234     zip_error_fini(&ctx->error);
235     _zip_buffer_free(ctx->buffer);
236     free(ctx);
237 }
238
239
240 static struct winzip_aes *
241 winzip_aes_new(unsigned int mode, zip_uint16_t encryption_method, const char *password) {
242     struct winzip_aes *ctx;
243     
244     if ((ctx = (struct winzip_aes *)malloc(sizeof(*ctx))) == NULL) {
245         return NULL;
246     }
247     
248     if ((ctx->password = strdup(password)) == NULL) {
249         free(ctx);
250         return NULL;
251     }
252
253     ctx->mode = mode;
254     ctx->encryption_method = encryption_method;
255     ctx->buffer = NULL;
256
257     zip_error_init(&ctx->error);
258
259     ctx->eof = false;
260     return ctx;
261 }