You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
124 lines
3.6 KiB
124 lines
3.6 KiB
|
1 day ago
|
// 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<String> _ids(int n) => [for (var i = 0; i < n; i++) 'holder $i'];
|
||
|
|
|
||
|
|
/// The recipes of the samples.
|
||
|
|
List<Json> interopSamples() {
|
||
|
|
final out = <Json>[];
|
||
|
|
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,
|
||
|
|
);
|
||
|
|
}
|