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.
86 lines
3.7 KiB
86 lines
3.7 KiB
// The writers: encryptFiles writes a .dkc of capsule format 3, with, when
|
|
// asked, a portable .dkk (spec §61, §62, §62.1), as capsule.EncryptFiles of
|
|
// the Go reference at spec-v0.11; encrypt, as capsule.Encrypt, writes format
|
|
// 2 only for a generator of test vectors, which these options cannot ask
|
|
// for. Their random values all come from crypto.getRandomValues (§62.1 rule
|
|
// 5); the core of writer.ts, which takes them from its caller, is imported
|
|
// only here and by the helpers of the tests. Loaded on demand: index.ts does
|
|
// not re-export it.
|
|
|
|
import { cryptoWords } from './random.ts';
|
|
import {
|
|
type Draws,
|
|
type EncryptOptions,
|
|
type Encrypted,
|
|
type EncryptSource,
|
|
type FileSource,
|
|
MAX_MEMORY_DKC,
|
|
writeCapsule,
|
|
writeFiles,
|
|
} from './writer.ts';
|
|
import { newX25519Identity } from './x25519.ts';
|
|
|
|
export type { EncryptOptions, Encrypted, EncryptSource, FileSource };
|
|
export { MAX_MEMORY_DKC };
|
|
|
|
/**
|
|
* Writes a .dkc of format 3 holding `files`, and the comment and declared
|
|
* author of `opts`. It needs no network: the round is resolved locally, and
|
|
* tlock uses only the pinned public key.
|
|
*
|
|
* It reads each file twice, and writes nothing before the second reading.
|
|
* First it checks the paths and the texts with the rules of the reader,
|
|
* measures L with a head whose salt and SHA-256 are zero, as long as the
|
|
* final one, and hashes each file. Then it seals the control, with L, and
|
|
* streams PAYLOAD_AGE, reading each file again: a file whose size or SHA-256
|
|
* has changed makes it fail (§62.1 rule 18). The files go in the byte order
|
|
* of their paths, whatever the order given (R8), without the empty folders,
|
|
* which a path cannot name. The security area is the empty one of this
|
|
* library, which does not sign, in an area of 32 KiB, whatever the capsule
|
|
* holds (rule 13); `opts.publicNote` goes in PUBLIC_HEADER (§24.1).
|
|
*
|
|
* Without `opts.output` the .dkc is returned in memory, up to
|
|
* MAX_MEMORY_DKC; with it, the .dkc is streamed into the output, closed only
|
|
* once the capsule is complete and checked and aborted on any failure. The
|
|
* checks, codes and texts are those of capsule.EncryptFiles, in its order;
|
|
* `opts.length` is for encrypt, and L is the length of BODY.
|
|
*/
|
|
export function encryptFiles(files: readonly FileSource[], opts: EncryptOptions): Promise<Encrypted> {
|
|
return writeFiles(files, opts, cryptoDraws());
|
|
}
|
|
|
|
/**
|
|
* capsule.Encrypt, which writes a .dkc of format 2 only for a generator of
|
|
* test vectors (§62.1 rule 1, §70): no option of a caller asks for it, so it
|
|
* fails with the text of Go, and its output, if any, is aborted. Capsules
|
|
* are written with encryptFiles. The tests write format 2 with the helpers of
|
|
* testing/encrypt.ts, which pass the core what only they may ask.
|
|
*/
|
|
export function encrypt(src: EncryptSource, opts: EncryptOptions): Promise<Encrypted> {
|
|
return writeCapsule(src, opts, cryptoDraws());
|
|
}
|
|
|
|
/**
|
|
* The FileSource of a File or another Blob: its path in the capsule, its
|
|
* size, its modification time, File.lastModified unless given, and its
|
|
* stream, read twice.
|
|
*/
|
|
export function fileSource(path: string, blob: Blob, mtime?: number): FileSource {
|
|
const lastModified = mtime ?? (blob instanceof File ? blob.lastModified : undefined);
|
|
return { path, size: blob.size, ...(lastModified === undefined ? {} : { mtime: lastModified }), open: () => blob.stream() };
|
|
}
|
|
|
|
// Every random value of the writer from crypto.getRandomValues.
|
|
function cryptoDraws(): Draws {
|
|
const bytes = (n: number) => (): Uint8Array => crypto.getRandomValues(new Uint8Array(n));
|
|
return {
|
|
capsuleId: bytes(16),
|
|
payloadIdentity: newX25519Identity,
|
|
accessIdentity: newX25519Identity,
|
|
dummy: newX25519Identity,
|
|
words: cryptoWords(),
|
|
credentialId: bytes(16),
|
|
salt: bytes(32),
|
|
};
|
|
}
|