Cipherpack v1.2.0-dirty
A Cryprographic Stream Processor
Test01CipherpackSingle.java
Go to the documentation of this file.
1/**
2 * Author: Sven Gothel <sgothel@jausoft.com>
3 * Copyright (c) 2022 Gothel Software e.K.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining
6 * a copy of this software and associated documentation files (the
7 * "Software"), to deal in the Software without restriction, including
8 * without limitation the rights to use, copy, modify, merge, publish,
9 * distribute, sublicense, and/or sell copies of the Software, and to
10 * permit persons to whom the Software is furnished to do so, subject to
11 * the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be
14 * included in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25package test.org.cipherpack;
26
27import java.io.File;
28import java.io.FileInputStream;
29import java.io.FileOutputStream;
30import java.io.IOException;
31import java.io.InputStream;
32import java.io.OutputStream;
33import java.nio.charset.Charset;
34import java.nio.file.Path;
35import java.nio.file.Paths;
36import java.time.Instant;
37import java.time.temporal.ChronoUnit;
38import java.util.ArrayList;
39import java.util.Arrays;
40import java.util.List;
41
42import org.cipherpack.CPFactory;
43import org.cipherpack.Cipherpack;
44import org.cipherpack.CipherpackListener;
45import org.cipherpack.CryptoConfig;
46import org.cipherpack.PackHeader;
47import org.jau.fs.CopyOptions;
48import org.jau.fs.FileStats;
49import org.jau.fs.FileUtil;
50import org.jau.fs.TraverseOptions;
51import org.jau.io.ByteInStream;
52import org.jau.io.ByteInStreamUtil;
53import org.jau.io.ByteInStream_Feed;
54import org.jau.io.ByteInStream_File;
55import org.jau.io.ByteInStream_URL;
56import org.jau.io.PrintUtil;
57import org.jau.sys.Clock;
58import org.jau.util.BasicTypes;
59import org.junit.AfterClass;
60import org.junit.Assert;
61import org.junit.FixMethodOrder;
62import org.junit.Test;
63import org.junit.runners.MethodSorters;
64
65@FixMethodOrder(MethodSorters.NAME_ASCENDING)
66public class Test01CipherpackSingle extends data_test {
67 static final boolean DEBUG = false;
68
69 static final String plaintext_version = "0";
70 static final String plaintext_version_parent = "0";
71
72 static final int IDX_0B = 0;
73 static final int IDX_1B = 1;
74 static final int IDX_11kiB = 2;
75 static final int IDX_xbuffersz = 3;
76 static final int IDX_xbuffersz_minus_tag = 4;
77 static final int IDX_xbuffersz_plus_tag = 5;
78 static final int IDX_65MiB = 6;
79
80 static List<String> fname_plaintext_lst = new ArrayList<String>();
81 static List<String> fname_encrypted_lst = new ArrayList<String>();
82 static List<String> fname_decrypted_lst = new ArrayList<String>();
83
84 static boolean remove_file(final String name) {
85 final File file = new File( name );
86 try {
87 if( file.exists() ) {
88 if( !file.delete() ) {
89 PrintUtil.println(System.err, "Remove.1: Failed deletion of existing file "+name);
90 return false;
91 }
92 }
93 return true;
94 } catch (final Exception ex) {
95 PrintUtil.println(System.err, "Remove.2: Failed deletion of existing file "+name+": "+ex.getMessage());
96 ex.printStackTrace();
97 }
98 return false;
99 }
100 static void add_test_file(final String name, final long size) {
101 Assert.assertTrue( remove_file(name) );
102 Assert.assertTrue( remove_file(name+".enc") );
103 Assert.assertTrue( remove_file(name+".enc.dec") );
104 {
105 final String one_line = "Hello World, this is a test and I like it. Exactly 100 characters long. 0123456780 abcdefghjklmnop..";
106 final Charset charset = Charset.forName("ASCII");
107 final byte[] one_line_bytes = one_line.getBytes(charset);
108
109 final File file = new File( name );
110 Assert.assertFalse( file.exists() );
111
112 try( final OutputStream out = new FileOutputStream(file); ) {
113
114 long written=0;
115 for(; written+one_line_bytes.length <= size; written+=+one_line_bytes.length) {
116 out.write( one_line_bytes );
117 }
118 for(; size-written > 0; ++written ) {
119 out.write( (byte)'_' );
120 }
121 } catch (final Exception ex) {
122 PrintUtil.println(System.err, "Write test file: Failed "+name+": "+ex.getMessage());
123 ex.printStackTrace();
124 }
125 }
126 final FileStats stats = new FileStats(name);
127 Assert.assertTrue( stats.is_file() );
128 Assert.assertEquals( size, stats.size() );
129 fname_plaintext_lst.add(name);
130 fname_encrypted_lst.add(name+".enc");
131 fname_decrypted_lst.add(name+".enc.dec");
132 }
133
134 static {
136 final int buffer_size = 16384;
137 int i=0;
138
139 // Zero size .. Single finish chunk of less than buffer_size including the 16 bytes TAG
140 add_test_file("test_cipher_0"+(i++)+"_0B.bin", 0);
141
142 // Zero size .. Single finish chunk of less than buffer_size including the 16 bytes TAG
143 add_test_file("test_cipher_0"+(i++)+"_1B.bin", 1);
144
145 // Single finish chunk of less than buffer_size including the 16 bytes TAG
146 add_test_file("test_cipher_0"+(i++)+"_11kiB.bin", 1024*11+1);
147
148 // Will end up in a finish chunk of just 16 bytes TAG
149 final long xbuffersz = 4 * buffer_size;
150 add_test_file("test_cipher_0"+(i++)+"_xbuffsz_"+(xbuffersz/1024)+"kiB.bin", xbuffersz);
151
152 // Will end up in a finish chunk of buffer_size including the 16 bytes TAG
153 final long xbuffersz_minus = 4 * buffer_size - 16;
154 add_test_file("test_cipher_0"+(i++)+"_xbuffsz_"+(xbuffersz/1024)+"kiB_sub16.bin", xbuffersz_minus);
155
156 // Will end up in a finish chunk of 1 byte + 16 bytes TAG
157 final long xbuffersz_plus = 4 * buffer_size + 1;
158 add_test_file("test_cipher_0"+(i++)+"_xbuffsz_"+(xbuffersz/1024)+"kiB_add1.bin", xbuffersz_plus);
159
160 // 65MB big file: Will end up in a finish chunk of 1 byte + 16 bytes TAG, 4160 chunks @ 16384
161 add_test_file("test_cipher_0"+(i++)+"_65MiB.bin", 1024*1024*65+1);
162 }
163
164 static boolean system(final String[] command) {
165 Process proc = null;
166 try{
167 proc = Runtime.getRuntime().exec(command);
168 proc.waitFor();
169 return true;
170 }
171 catch(final Exception ex)
172 {
173 if(proc!=null) {
174 proc.destroy();
175 }
176 ex.printStackTrace();
177 }
178 return false;
179 }
180
181 static final String mini_httpd_exe() {
182 final String os_name = System.getProperty("os.name");
183 if( "FreeBSD".equals(os_name) ) {
184 return "/usr/local/sbin/mini_httpd";
185 } else {
186 return "/usr/sbin/mini_httpd";
187 }
188 }
189
190 @AfterClass
191 public static void httpd_stop() {
192 if( org.jau.io.UriTk.protocol_supported("http:") ) {
193 Assert.assertTrue( system(new String[]{"killall", "mini_httpd"}) );
194 }
195 }
196
197 static void httpd_start() {
198 if( org.jau.io.UriTk.protocol_supported("http:") ) {
199 Assert.assertTrue( system(new String[]{"killall", "mini_httpd"}) );
200 final Path path = Paths.get("");
201 final String directoryName = path.toAbsolutePath().toString();
202 final String[] cmd = new String[]{mini_httpd_exe(), "-p", "8080", "-l", directoryName+"/mini_httpd.log"};
203 PrintUtil.fprintf_td(System.err, "%s\n", Arrays.toString(cmd));
204 Assert.assertTrue( system(cmd) );
205 }
206 }
207
208 public static void hash_retest(final String hashAlgo,
209 final String origFile, final byte[] hashValue_p1,
210 final String hashedDescryptedFile, final byte[] hashValue_p2)
211 {
212 Assert.assertArrayEquals(hashValue_p1, hashValue_p2);
213
214 final String suffix = Cipherpack.HashUtil.fileSuffix(hashAlgo);
215 final String outFile = hashedDescryptedFile + "." + suffix;
216 FileUtil.remove(outFile, TraverseOptions.none);
217
218 Assert.assertTrue( Cipherpack.HashUtil.appendToFile(outFile, hashedDescryptedFile, hashAlgo, hashValue_p2) );
219
220 final ByteInStream origIn = ByteInStreamUtil.to_ByteInStream(origFile);
221 Assert.assertNotNull( origIn );
222 final Instant t0 = Clock.getMonotonicTime();
223 final byte[] origHashValue = Cipherpack.HashUtil.calc(hashAlgo, origIn);
224 Assert.assertNotNull( origHashValue );
225 Assert.assertArrayEquals(hashValue_p2, origHashValue);
226
227 final Instant t1 = Clock.getMonotonicTime();
228 final long td_ms = t0.until(t1, ChronoUnit.MILLIS);
229 ByteInStreamUtil.print_stats("Hash '"+hashAlgo+"'", origIn.content_size(), td_ms);
230 PrintUtil.fprintf_td(System.err, "\n");
231 }
232
233 public static void hash_retest(final String hashAlgo,
234 final String origFile,
235 final String hashedDescryptedFile, final byte[] hashValue_p2)
236 {
237 final String suffix = Cipherpack.HashUtil.fileSuffix(hashAlgo);
238 final String outFile = hashedDescryptedFile + "." + suffix;
239 FileUtil.remove(outFile, TraverseOptions.none);
240
241 Assert.assertTrue( Cipherpack.HashUtil.appendToFile(outFile, hashedDescryptedFile, hashAlgo, hashValue_p2) );
242
243 final ByteInStream origIn = ByteInStreamUtil.to_ByteInStream(origFile);
244 Assert.assertNotNull( origIn );
245 final Instant t0 = Clock.getMonotonicTime();
246 final byte[] origHashValue = Cipherpack.HashUtil.calc(hashAlgo, origIn);
247 Assert.assertNotNull( origHashValue );
248 Assert.assertArrayEquals(hashValue_p2, origHashValue);
249
250 final Instant t1 = Clock.getMonotonicTime();
251 final long td_ms = t0.until(t1, ChronoUnit.MILLIS);
252 ByteInStreamUtil.print_stats("Hash '"+hashAlgo+"'", origIn.content_size(), td_ms);
253 PrintUtil.fprintf_td(System.err, "\n");
254 }
255
256 CipherpackListener silentListener = new CipherpackListener();
257
258 @Test(timeout = 120000)
259 public final void test00_enc_dec_file_single() {
261 final List<String> enc_pub_keys = Arrays.asList(enc_pub_key1_fname, enc_pub_key2_fname, enc_pub_key3_fname);
262 final List<String> sign_pub_keys = Arrays.asList(sign_pub_key1_fname, sign_pub_key2_fname, sign_pub_key3_fname);
263 {
264 final int file_idx = IDX_11kiB;
265 final LoggingCipherpackListener enc_listener = new LoggingCipherpackListener("test00.enc");
266 final LoggingCipherpackListener dec_listener = new LoggingCipherpackListener("test00.dec");
267 final String _path = fname_plaintext_lst.get(file_idx); // 'test_cipher_02_11kiB.bin'
268 PrintUtil.fprintf_td(System.err, "test00_enc_dec_file_single(: path '%s', len %d\n", _path, _path.length());
269 final ByteInStream_File source = new ByteInStream_File(_path);
271 enc_pub_keys,
272 sign_sec_key1_fname, sign_sec_key_passphrase,
273 source,
274 fname_plaintext_lst.get(file_idx), "test00_enc_dec_file_single", plaintext_version, plaintext_version_parent,
275 enc_listener, Cipherpack.default_hash_algo(), fname_encrypted_lst.get(file_idx));
276 PrintUtil.fprintf_td(System.err, "test00_enc_dec_file_single: Encrypted %s to %s\n", fname_plaintext_lst.get(file_idx), fname_encrypted_lst.get(file_idx));
277 PrintUtil.fprintf_td(System.err, "test00_enc_dec_file_single: %s\n", ph1.toString(true, true));
278 Assert.assertTrue( ph1.isValid() );
279 enc_listener.check_counter_end();
280
281 final ByteInStream_File enc_stream = new ByteInStream_File(fname_encrypted_lst.get(file_idx));
282 final PackHeader ph2 = Cipherpack.checkSignThenDecrypt(sign_pub_keys, dec_sec_key1_fname, dec_sec_key_passphrase,
283 enc_stream,
284 dec_listener, ph1.plaintext_hash_algo, fname_decrypted_lst.get(file_idx));
285 PrintUtil.fprintf_td(System.err, "test00_enc_dec_file_single: Decypted %s to %s\n", fname_encrypted_lst.get(file_idx), fname_decrypted_lst.get(file_idx));
286 PrintUtil.fprintf_td(System.err, "test00_enc_dec_file_single: %s\n", ph2.toString(true, true));
287 Assert.assertTrue( ph2.isValid() );
288 dec_listener.check_counter_end();
289 }
290 }
291
292 public static void main(final String args[]) {
293 org.junit.runner.JUnitCore.main(Test01CipherpackSingle.class.getName());
294 }
295}
Cipherpack Factory, called by automatically to load the native library.
Definition: CPFactory.java:47
static void checkInitialized()
Definition: CPFactory.java:269
Listener for events occurring while processing a cipherpack message via encryptThenSign() and checkSi...
Hash utility functions to produce a hash file compatible to sha256sum as well as to produce the hash ...
static boolean appendToFile(final String outFileName, final String hashedFile, final String hashAlgo, final byte[] hashValue)
Append the hash signature to the text file out_file.
static byte[] calc(final String algo, final ByteInStream source)
Return the calculated hash value using given algo name and byte input stream.
static String fileSuffix(final String algo)
Return a lower-case file suffix used to store a sha256sum compatible hash signature w/o dot and w/o d...
static PackHeader encryptThenSign(final CryptoConfig crypto_cfg, final List< String > enc_pub_keys, final String sign_sec_key_fname, final ByteBuffer passphrase, final ByteInStream source, final String target_path, final String subject, final String plaintext_version, final String plaintext_version_parent, final CipherpackListener listener, final String plaintext_hash_algo, final String destination_fname)
Encrypt then sign the source producing a cipherpack stream passed to the CipherpackListener if opt-in...
static PackHeader checkSignThenDecrypt(final List< String > sign_pub_keys, final String dec_sec_key_fname, final ByteBuffer passphrase, final ByteInStream source, final CipherpackListener listener, final String plaintext_hash_algo, final String destination_fname)
Verify signature then decrypt the source passing to the CipherpackListener if opt-in and also optiona...
static final String default_hash_algo()
Name of default hash algo for the plaintext message, e.g.
CryptoConfig, contains crypto algorithms settings given at encryption wired via the Cipherpack Data S...
static CryptoConfig getDefault()
Returns default CryptoConfig.
Cipherpack header less encrypted keys or signatures as described in Cipherpack Data Stream.
Definition: PackHeader.java:40
String toString(final boolean show_crypto_algos, final boolean force_all_fingerprints)
Return a string representation.
final boolean isValid()
final String plaintext_hash_algo
Optional hash algorithm for the plaintext message, produced for convenience and not wired.
Definition: PackHeader.java:78
static void hash_retest(final String hashAlgo, final String origFile, final byte[] hashValue_p1, final String hashedDescryptedFile, final byte[] hashValue_p2)
static void hash_retest(final String hashAlgo, final String origFile, final String hashedDescryptedFile, final byte[] hashValue_p2)