// The recipes of the interoperability of the writer of capsules, stage 6b: // capsules that this library writes and Go opens // (tool/capsule_interop_dart_samples.dart, tool/capsule_interop_go_verdicts.go, // test/vectors/capsule_interop.json). They are in the form of the recipes of // capsule_writer.json (capsule_writer_support.dart), with `random` seeded, // for a capsule that the tests write again and compare, or secure, for one // written with the CSPRNG of the platform, as an application writes it, // which only Go's verdicts describe. They read no file. import 'dart:typed_data'; import 'package:datekeys/datekeys.dart'; import 'capsule_writer_support.dart'; const _words = ['faro', 'nube', 'trigo', 'menta', 'barco', 'lince']; List _ids(int n) => [for (var i = 0; i < n; i++) 'holder $i']; /// The recipes of the samples. List interopSamples() { final out = []; for (final random in ['seeded', 'secure']) { Json s(String name, Json r) => { 'name': '$name ($random)', 'seed': 'capsule interop $name', 'random': random, 'round': 1000, ...r, }; out.addAll([ s('time_only, one file', { 'files': [ {'path': 'nota.txt', 'text': 'Hola.\n'}, ], 'node': true, }), s('time_only, a comment alone, bloque256, area of 512', { 'comment': 'Una línea.\r\nOtra.', 'author': 'Ana López', 'padding': 1, 'test_vectors': true, 'test_area_len': 512, 'node': true, }), s('time_and_key, a portable key and a note', { 'policy': 'time_and_key', 'portable': true, 'note': 'Para Ana', 'files': [ {'path': 'a.txt', 'text': 'a'}, {'path': 'b/c.txt', 'text': ''}, ], }), s('time_and_key, fourteen recipients, words and a portable key', { 'policy': 'time_and_key', 'identities': _ids(14), 'words': _words, 'portable': true, 'round': 1001, 'files': [ {'path': 'x.bin', 'pattern': 70000}, ], 'node': false, }), s('three MiB in three files, with mtimes', { 'files': [ { 'path': 'grande.bin', 'pattern': 3 << 20, 'mtime': [1727712000, 5], }, { 'path': 'fotos/b.jpg', 'pattern': 65536, 'mtime': [-1, 0], }, {'path': 'fotos/a.jpg', 'pattern': 65535}, ], 'node': false, }), s('two hundred small files and extensions', { 'files': [ for (var i = 0; i < 200; i++) {'path': 'd${i % 7}/f$i.txt', 'text': 'file $i\n'}, ], 'critical': [ {'id': 'org.example.crit', 'version': 1, 'data': '01'}, ], 'control_noncritical': [ {'id': 'org.example.c', 'version': 2}, ], 'head_noncritical': [ {'id': 'org.example.h', 'version': 1, 'data': 'ff'}, ], 'node': false, }), ]); } return out; } /// The capsule of the sample [s] and its .dkk, if any: written with the /// seeded source of its seed, or with [secureRandom]. Future<({Uint8List dkc, Uint8List? dkk, EncryptResult result})> writeSample( Json s, ) async { final random = s['random'] == 'seeded' ? seeded(s['seed']! as String) : secureRandom; final sink = CapsuleSink(); final res = await encryptFiles( sink, sourcesOf(s), optionsOf(s, random, Hooks(s, const {})), ); final k = res.portableKey; return ( dkc: sink.bytes, dkk: k == null ? null : encodeAccessKey(k), result: res, ); }