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/age_writer_support.dart

113 lines
3.9 KiB

// Helpers of the tests of the age writer: the recipients and identities of
// the cases of test/vectors/age_writer.json and age_interop.json, the
// identity of OUTER_TIME_AGE, which the reader keeps private, a file written
// in pieces and the lengths of the stanzas of a header. They read no file.
import 'dart:typed_data';
import 'package:datekeys/datekeys.dart';
import 'package:datekeys/src/age.dart';
import 'package:datekeys/src/age_writer.dart';
import 'package:datekeys/src/agewrap.dart';
import 'package:datekeys/src/bytes.dart' show utf8Bytes;
import 'package:datekeys/src/recipient.dart';
import 'package:datekeys/src/sha256.dart';
import 'package:datekeys/src/tlock.dart';
import 'random_support.dart';
export 'age_support.dart' show pattern;
export 'random_support.dart';
/// The published Quicknet signatures of rounds 1000 and 1001, those of the
/// fixtures.
const releases = {
1000: 'b44679b9a59af2ec876b1a6b1ad52ea9b1615fc3982b19576350f93447cb1125e342b73a8dd2bacbe47e4b6b63ed5e39',
1001: 'b33bf3667cbd5a82de3a24b4e0e9fe5513cc1a0e840368c6e31f5fcfa79bea03f73896b25883abf2853d10337fb8fa41',
};
/// The X25519 identity of a label: its raw secret is SHA-256("identity " +
/// label), as in the generators.
X25519Identity labelIdentity(String label) =>
X25519Identity(sha256(utf8Bytes('identity $label')));
/// The recipient of a case: `{x25519: age1…}`, `{scrypt: passphrase,
/// work_factor: n}` or `{tlock: round}`, for Quicknet.
AgeRecipient recipientOf(Json spec) {
final x = spec['x25519'] as String?;
if (x != null) return X25519Recipient.parse(x);
final pass = spec['scrypt'] as String?;
if (pass != null) {
return ScryptRecipient(pass, workFactor: spec['work_factor']! as int);
}
return TimeRecipient(quicknet(), spec['tlock']! as int);
}
/// The identity that opens what [spec] wraps, when the case knows it: the
/// X25519 identity it names, the passphrase with its work factor as the
/// maximum, or the tlock identity of a round whose release is known.
AgeIdentity? identityOf(Json spec) {
final id = spec['identity'] as String?;
if (id != null) return X25519Identity.parse(id);
final pass = spec['scrypt'] as String?;
if (pass != null) {
return ScryptIdentity(pass, maxWorkFactor: spec['work_factor']! as int);
}
final round = spec['tlock'] as int?;
final sig = releases[round];
if (round == null || sig == null) return null;
return TimeIdentity(quicknet(), round, Release(round, fromHex(sig)));
}
/// The identity of OUTER_TIME_AGE, as Go's agewrap.TimeIdentity: the
/// stanza rule of the file, then the tlock stanza opened with the release.
/// open.dart has its own, private.
final class TimeIdentity implements AgeIdentity {
TimeIdentity(this._p, this._round, this._release);
final Profile _p;
final int _round;
final Release _release;
@override
Uint8List unwrap(List<AgeStanza> stanzas) {
checkTimeStanzas(
stanzas,
round: _round,
chainHashHex: _p.chainHashHex,
profileId: _p.id,
);
final s = stanzas.single;
return unwrapTlockStanza(_p, _round, _release, s.args, s.body);
}
}
/// The file that [AgeEncryptor] writes when the plaintext arrives in pieces
/// of the sizes that [step] gives, in turn.
Uint8List encryptInPieces(
Uint8List plaintext,
List<AgeRecipient> recipients,
RandomSource random,
List<int> steps,
) {
final e = AgeEncryptor(recipients, random: random);
final out = BytesBuilder(copy: false)
..add(e.header)
..add(e.nonce);
var k = 0;
for (var i = 0; i < plaintext.length;) {
final n = steps[k++ % steps.length];
final end = i + n < plaintext.length ? i + n : plaintext.length;
e.add(plaintext, i, end).forEach(out.add);
i = end;
}
out.add(e.close());
return out.takeBytes();
}
/// The marshalled length of each stanza of [header], an age header.
List<int> stanzaLengths(Uint8List header) => [
for (final s in parseAgeHeader(header).stanzas)
marshalAgeHeaderWithoutMac([s]).length - 22 - 3,
];

Powered by TurnKey Linux.