xref: /freebsd/contrib/libarchive/libarchive/test/test_read_format_zip_zipx_encrypted.c (revision 185becb1e1bd2657c156f78aeb52edac05ba5fb5)
1 /*-
2  * Copyright (c) 2026 GeorgH93
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
15  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17  * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
18  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25 
26 #include "test.h"
27 
28 static const char *password = "test_password_zipx";
29 
30 /* 512 bytes of test data — large enough to exercise decompression. */
31 static const char file_data[] =
32     "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz\n"
33     "The quick brown fox jumps over the lazy dog. Pack my box with five\n"
34     "dozen liquor jugs. How vexingly quick daft zebras jump! Bright\n"
35     "vixens jump; dozy fowl quack. Jackdaws love my big sphinx of\n"
36     "quartz. The five boxing wizards jump quickly. Amazingly few\n"
37     "discotheques provide jukeboxes. Crazy Frederick bought many very\n"
38     "exquisite opal jewels. We promptly judged antique ivory buckles\n"
39     "for the next prize. Sixty zippers were quickly picked from the bag.\n";
40 static const size_t file_size = sizeof(file_data) - 1;
41 
42 struct streaming_buffer {
43 	const char *data;
44 	la_ssize_t len;
45 	size_t pos;
46 	int served;
47 };
48 
read_streaming_buffer(struct archive * a,void * _client_data,const void ** buffer)49 static la_ssize_t read_streaming_buffer(struct archive *a, void *_client_data, const void **buffer) {
50 	(void)a;
51 	struct streaming_buffer *buff = _client_data;
52 	if (buff->served) return 0;
53 	*buffer = buff->data;
54 	buff->served = 1;
55 	return buff->len;
56 }
57 
58 static void
validate_entry_read(struct archive * a,const int streaming_reader)59 validate_entry_read(struct archive *a, const int streaming_reader)
60 {
61 	struct archive_entry *ae;
62 	size_t total_read;
63 	ssize_t r;
64 	char readbuf[1024];
65 
66 	assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
67 	assertEqualString("encrypted_file.txt", archive_entry_pathname(ae));
68 	if (!streaming_reader)
69 		assertEqualInt((int)file_size, (int)archive_entry_size(ae));
70 	else
71 		assertEqualInt(archive_entry_size(ae), 0);
72 	assertEqualInt(1, archive_entry_is_data_encrypted(ae));
73 
74 	total_read = 0;
75 	for (;;) {
76 		r = archive_read_data(a, readbuf, sizeof(readbuf));
77 		if (r <= 0) {
78 			if (r < 0) {
79 				failure("archive_read_data returned %d: %s",
80 				    (int)r, archive_error_string(a));
81 				assertEqualInt(r > 0, 1);
82 			}
83 			break;
84 		}
85 		assertEqualMem(readbuf, file_data + total_read, (size_t)r);
86 		total_read += (size_t)r;
87 	}
88 	assertEqualInt((int)total_read, (int)file_size);
89 }
90 
91 static void
test_encrypted_zipx_read_mem(char * buff,size_t used)92 test_encrypted_zipx_read_mem(char* buff, size_t used)
93 {
94 	struct archive *a;
95 	struct archive_entry *ae;
96 	char readbuf[1024];
97 
98 	/* ---- Read back without password — should fail ---- */
99 	assert((a = archive_read_new()) != NULL);
100 	assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
101 	assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
102 	assertEqualIntA(a, ARCHIVE_OK, archive_read_open_memory(a, buff, used));
103 	assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
104 	assertEqualString("encrypted_file.txt", archive_entry_pathname(ae));
105 	assertEqualInt(1, archive_entry_is_data_encrypted(ae));
106 	assertEqualInt(0, archive_entry_is_metadata_encrypted(ae));
107 	assertEqualInt(ARCHIVE_FAILED, archive_read_data(a, readbuf, sizeof(readbuf)));
108 	assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
109 	assertEqualInt(ARCHIVE_OK, archive_read_free(a));
110 
111 	/* ---- Read back with correct password ---- */
112 	assert((a = archive_read_new()) != NULL);
113 	assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
114 	assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
115 	assertEqualIntA(a, ARCHIVE_OK, archive_read_add_passphrase(a, password));
116 	assertEqualIntA(a, ARCHIVE_OK, archive_read_open_memory(a, buff, used));
117 
118 	validate_entry_read(a, 0);
119 
120 	assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
121 	assertEqualInt(ARCHIVE_OK, archive_read_free(a));
122 
123 	/* ---- Seeking reader with correct password ---- */
124 	assert((a = archive_read_new()) != NULL);
125 	assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
126 	assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
127 	assertEqualIntA(a, ARCHIVE_OK, archive_read_add_passphrase(a, password));
128 	assertEqualIntA(a, ARCHIVE_OK, read_open_memory_seek(a, buff, used, 7));
129 
130 	validate_entry_read(a, 0);
131 
132 	assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
133 	assertEqualInt(ARCHIVE_OK, archive_read_free(a));
134 }
135 
136 static void
test_encrypted_zipx_read_callback(const char * buff,const size_t used)137 test_encrypted_zipx_read_callback(const char* buff, const size_t used)
138 {
139 	struct archive *a;
140 	struct streaming_buffer stream_buffer = { buff, used, 0, 0 };
141 
142 	/* ---- Read back with correct password ---- */
143 	assert((a = archive_read_new()) != NULL);
144 	assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_zip(a));
145 	assertEqualIntA(a, ARCHIVE_OK, archive_read_add_passphrase(a, password));
146 	/* NOTE: archive_read_open2 with read callback only -> NON-seekable. */
147 	assertEqualIntA(a, ARCHIVE_OK, archive_read_open2(a, &stream_buffer, NULL, read_streaming_buffer, NULL, NULL));
148 	validate_entry_read(a, 1);
149 	assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
150 	assertEqualInt(ARCHIVE_OK, archive_read_free(a));
151 }
152 
153 static void
test_encrypted_zipx(const char * compression_name,const int streaming_entry)154 test_encrypted_zipx(const char *compression_name, const int streaming_entry)
155 {
156 	struct archive *a;
157 	struct archive_entry *ae;
158 	size_t used;
159 	size_t buffsize = 1000000;
160 	char *buff;
161 
162 	buff = malloc(buffsize);
163 	assert(buff != NULL);
164 
165 	/* ---- Write encrypted zipx archive ---- */
166 	assert((a = archive_write_new()) != NULL);
167 	assertEqualIntA(a, ARCHIVE_OK, archive_write_set_format_zip(a));
168 	assertEqualIntA(a, ARCHIVE_OK, archive_write_add_filter_none(a));
169 
170 	if (ARCHIVE_OK != archive_write_set_options(a,
171 			"zip:encryption=aes256")) {
172 		skipping("This system does not have cryptographic library");
173 		archive_write_free(a);
174 		free(buff);
175 		return;
176 	}
177 
178 	if (ARCHIVE_OK != archive_write_set_options(a, compression_name)) {
179 		skipping("%s is not supported on this platform", compression_name);
180 		archive_write_free(a);
181 		free(buff);
182 		return;
183 	}
184 
185 	assertEqualIntA(a, ARCHIVE_OK, archive_write_set_passphrase(a, password));
186 	assertEqualIntA(a, ARCHIVE_OK, archive_write_set_options(a, "zip:experimental"));
187 	assertEqualIntA(a, ARCHIVE_OK, archive_write_open_memory(a, buff, buffsize, &used));
188 
189 	assert((ae = archive_entry_new()) != NULL);
190 	archive_entry_set_mtime(ae, 1, 0);
191 	archive_entry_copy_pathname(ae, "encrypted_file.txt");
192 	archive_entry_set_mode(ae, AE_IFREG | 0644);
193 	if (!streaming_entry)
194 		archive_entry_set_size(ae, file_size);
195 	assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae));
196 	assertEqualInt(file_size, archive_write_data(a, file_data, file_size));
197 	archive_entry_free(ae);
198 	assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a));
199 	assertEqualInt(ARCHIVE_OK, archive_write_free(a));
200 
201 	test_encrypted_zipx_read_mem(buff, used);
202 	test_encrypted_zipx_read_callback(buff, used);
203 
204 	free(buff);
205 }
206 
DEFINE_TEST(test_read_format_zip_deflate_encrypted)207 DEFINE_TEST(test_read_format_zip_deflate_encrypted)
208 {
209 	test_encrypted_zipx("zip:compression=deflate", 0);
210 }
211 
DEFINE_TEST(test_read_format_zip_zipx_bzip2_encrypted)212 DEFINE_TEST(test_read_format_zip_zipx_bzip2_encrypted)
213 {
214 	test_encrypted_zipx("zip:compression=bzip2", 0);
215 }
216 
DEFINE_TEST(test_read_format_zip_zipx_lzma_encrypted)217 DEFINE_TEST(test_read_format_zip_zipx_lzma_encrypted)
218 {
219 	test_encrypted_zipx("zip:compression=lzma", 0);
220 }
221 
DEFINE_TEST(test_read_format_zip_zipx_xz_encrypted)222 DEFINE_TEST(test_read_format_zip_zipx_xz_encrypted)
223 {
224 	test_encrypted_zipx("zip:compression=xz", 0);
225 }
226 
DEFINE_TEST(test_read_format_zip_zipx_zstd_encrypted)227 DEFINE_TEST(test_read_format_zip_zipx_zstd_encrypted)
228 {
229 	test_encrypted_zipx("zip:compression=zstd", 0);
230 }
231 
DEFINE_TEST(test_read_format_zip_deflate_encrypted_streaming)232 DEFINE_TEST(test_read_format_zip_deflate_encrypted_streaming)
233 {
234 	test_encrypted_zipx("zip:compression=deflate", 1);
235 }
236 
DEFINE_TEST(test_read_format_zip_zipx_bzip2_encrypted_streaming)237 DEFINE_TEST(test_read_format_zip_zipx_bzip2_encrypted_streaming)
238 {
239 	test_encrypted_zipx("zip:compression=bzip2", 1);
240 }
241 
DEFINE_TEST(test_read_format_zip_zipx_lzma_encrypted_streaming)242 DEFINE_TEST(test_read_format_zip_zipx_lzma_encrypted_streaming)
243 {
244 	test_encrypted_zipx("zip:compression=lzma", 1);
245 }
246 
DEFINE_TEST(test_read_format_zip_zipx_xz_encrypted_streaming)247 DEFINE_TEST(test_read_format_zip_zipx_xz_encrypted_streaming)
248 {
249 	test_encrypted_zipx("zip:compression=xz", 1);
250 }
251 
DEFINE_TEST(test_read_format_zip_zipx_zstd_encrypted_streaming)252 DEFINE_TEST(test_read_format_zip_zipx_zstd_encrypted_streaming)
253 {
254 	test_encrypted_zipx("zip:compression=zstd", 1);
255 }
256 
DEFINE_TEST(test_read_format_zip_ppmd8_aes256_streaming)257 DEFINE_TEST(test_read_format_zip_ppmd8_aes256_streaming)
258 {
259 	const char *refname = "test_read_format_zip_ppmd8_aes256_streaming.zipx";
260 	size_t used;
261 	char buff[600];
262 	extract_reference_file(refname);
263 	FILE *f = fopen(refname, "rb");
264 	used = fread(buff, 1, sizeof(buff), f);
265 	fclose(f);
266 	test_encrypted_zipx_read_mem(buff, used);
267 	test_encrypted_zipx_read_callback(buff, used);
268 }
269