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.
dateKeys-dart/test/large_capsule.dart

168 lines
4.8 KiB

// Capsules with a large content, made from the time_only fixtures as
// whoever knows their keys can (spec §36.1): PAYLOAD_AGE sealed again over
// another plaintext with the file key that I_PAYLOAD unwraps and the nonce
// of the fixture, and in format 3 CONTROL_CBOR sealed again with the L of
// the new BODY, with FK_TIME, which the release of the fixture unwraps. The
// streaming tests and tool/open_bench.dart open them. They read no file.
library;
import 'dart:typed_data';
import 'package:datekeys/datekeys.dart';
import 'package:datekeys/src/age.dart';
import 'package:datekeys/src/body.dart';
import 'package:datekeys/src/sha256.dart';
import 'package:datekeys/src/tlock.dart';
import 'age_support.dart' show streamSeal;
export 'age_support.dart' show pattern;
/// The parts of an age file: its header, its nonce and its STREAM.
({Uint8List header, Uint8List nonce, Uint8List stream}) ageParts(
Uint8List file,
) {
final h = parseAgeHeader(file).length;
return (
header: Uint8List.sublistView(file, 0, h),
nonce: Uint8List.sublistView(file, h, h + 16),
stream: Uint8List.sublistView(file, h + 16),
);
}
/// The plaintext of the STREAM of [file] under [fileKey].
Uint8List openStream(Uint8List file, Uint8List fileKey) {
final p = ageParts(file);
final d = AgePayloadDecryptor(
hkdfSha256(fileKey, p.nonce, 'payload'.codeUnits, 32),
);
final out = BytesBuilder(copy: false);
for (final c in d.add(p.stream)) {
out.add(c);
}
out.add(d.close());
return out.takeBytes();
}
/// [file] with its STREAM sealed again over [plaintext], its header and its
/// nonce kept.
Uint8List resealStream(Uint8List file, Uint8List fileKey, Uint8List plaintext) {
final p = ageParts(file);
return concatBytes([
p.header,
p.nonce,
streamSeal(fileKey, p.nonce, plaintext),
]);
}
/// The file key of PAYLOAD_AGE of [dkc], which [payloadIdentity] unwraps.
Uint8List payloadFileKey(Uint8List dkc, Uint8List payloadIdentity) {
final payload = splitCapsule(dkc).payload;
return X25519Identity(payloadIdentity)
.unwrap(parseAgeHeader(payload).stanzas);
}
/// [dkc], a time_only fixture of format 1, with [content] as its content.
Uint8List withContent1(
Uint8List dkc,
Uint8List payloadIdentity,
Uint8List content,
) {
final s = splitCapsule(dkc);
final fk = payloadFileKey(dkc, payloadIdentity);
return concatBytes([
s.preludeBytes,
s.publicHeader,
s.sealedControl!,
resealStream(s.payload, fk, content),
]);
}
/// [dkc], a time_only fixture of format 3 opened by [release], with a BODY
/// of the files [files], each a path and its content, in the order of their
/// paths, its security area kept, and the control that declares its L.
Uint8List withFiles3(
Uint8List dkc,
Uint8List payloadIdentity,
Release release,
List<(String, Uint8List)> files,
) {
final s = splitCapsule(dkc);
final h = decodeHeader(s.publicHeader);
final p = quicknet();
final sealed = s.sealedControl!;
final tlock = parseAgeHeader(sealed).stanzas.single;
final fkTime = unwrapTlockStanza(
p,
h.dateKey.round,
release,
tlock.args,
tlock.body,
);
final control = decodeControl(
openStream(sealed, fkTime),
CapsuleFormat.format3,
);
// The BODY of the fixture, for its security area and its salt.
final fk = payloadFileKey(dkc, payloadIdentity);
final old = openStream(s.payload, fk);
final frame = parseBodyFrame(
Uint8List.sublistView(old, 0, bodyFrameSize),
control.payloadLength!,
);
final area = Uint8List.sublistView(
old,
bodyFrameSize,
bodyFrameSize + frame.areaLen,
);
final oldHead = decodeHead(
Uint8List.sublistView(
old,
bodyFrameSize + frame.areaLen,
bodyFrameSize + frame.areaLen + frame.headLen,
),
);
var end = 0;
final head = encodeHead(
Head(
salt: oldHead.salt,
files: [
for (final (path, content) in files)
HeadFile(
path: path,
size: content.length,
start: end,
end: end += content.length,
sha256: sha256(content),
),
],
),
);
final body = concatBytes([
bodyFrameBytes(BodyFrame(frame.areaLen, frame.securityLen, head.length)),
area,
head,
for (final (_, content) in files) content,
]);
final l = body.length;
final padded = paddedLength(l, control.padding!);
final newControl = encodeControl(
Control(
headerBinding: control.headerBinding,
payloadIdentity: control.payloadIdentity,
critical: control.critical,
noncritical: control.noncritical,
payloadLength: l,
padding: control.padding,
),
CapsuleFormat.format3,
);
return concatBytes([
s.preludeBytes,
s.publicHeader,
resealStream(sealed, fkTime, newControl),
resealStream(s.payload, fk, concatBytes([body, Uint8List(padded - l)])),
]);
}

Powered by TurnKey Linux.