Goal
I've been hacking on chunk encryption for weeks now. Today I'll take stock and see what I've done and where I am and what I still need to do.
Plan
- Make a new branch.
- Make sure the test suite passes. If not, fix it.
- Review the new branch, and rebase it to make sure it tells a coherent, sensible story.
- Review the test suite: am I missing verification of any important functionality? Can the test cases be improved? Are verification scenarios easy to understand?
- What am I missing from being able to say I have chunk encryption? At least rudimentary?
- What can I merge into the
main
branch now?
Notes
- Make new branch,
ciphertext-rebase
. - Ran tests:
make
. - Review all commits compared to
main
.- add
chunk encrypt
andchunk decrypt
placeholders, with round trip scenario- this can be merged with the actual implementations; no point in having a placeholder commit
- add encoding kind for encrypted chunks and versioned encrypted
chunks
- do we need both plaintext and encrypted encoding methods?
- do we need separate versioning of plaintext and encrypted chunks?
- add
--clear-encoding
- rename
InspectedChunk
toInspectedCleartextChunk
- also inspect encrypted chunks
- rename cookie constants to avoid using numbers for the kind, using
names instead:
COOKIE_0
=>COOKIE_JSON
- add separate cookies for encrypted chunks
- drop unused inspection code
- add empty
cipher::aead
module - add AEAD cipher engine and a trait for cipher engines
- add a stupid cipher engine
- add dependencies for AEAD cipher engine
- rename encryption methods to cryptography, not encoding
- update doc in
src/chunk.rs
- add a type for chunk metadata to combine chunk id and label
- use chunk metadata type instead of separate id and label fields
- refactor encryption subcommand
- add
chunk encrypt --method
option - drop
EncryptedChunk::encrypt
argumentkey
, it's not used
- add
- first I want to rebase things to join into one the commits that add the encryption subcommand
- did some other tidying up of the branch; it's not ideal, but tolerable
- tests still pass
- next, be consistent in terminology "plaintext" (not "cleartext") and "ciphertext"
- reviewing existing tests
- there's a round trip acceptance scenario for encryption
- and one for inspecting an encrypted chunk
- the round trip could verify the encrypted chunk does not contain any of the plaintext
- the inspection could verify that it works without a key
- added to the round trip scenario a verification that encrypted chunk doesn't have plaintext data, but this fails, because it does
- ah yes, I have made an AEAD cipher engine, but I'm not actually using it yet
- I'm getting entangled again. The API I've created is too
complicated. I need to simplify it to make it easier to use the
correct way. I have today tried to brute force myself into something
that works, but it's too difficult. I don't want to write enterprise
software. Problems with the current code:
- the
cipher
module needs to have anenum
for cipher engines, and engine-independent ways to handle keys and errors, or otherwise hide the different implementations; the API caller should not need to deal with the details - there's no real point in having two kinds of plain text encoding forms, JSON and Postcard; I'm not really ever going to use anything but the Postcard, and carrying the superfluous JSON encoding is just more work for now and makes the API harder to use
- having separate plain text and encrypted encoding methods also makes API harder to use
- having a way to produce plain text chunks isn't really useful, either; I'm never going to want that in production code
- the
- The API for producing an encrypted chunk should probably be something like:
// Dummny values
let key = b"secret";
let data = b"binary chunk data as if read from a file";
let labed = b"data-chunk";
let engine = CipherEngine::new(cipher_kind, key);
let encrypted = Chunk::encrypt(&engine, data, label)?;
let decrypted = encrypted.decrypt(&engine, label)?;
println!("id={}", chunk.id());
println!("label={}", chunk.label());
println!("ciphertext={:?}", chunk.as_bytes());
assert_eq!(chunk.label(), label);
assert!(!chunk.as_bytes().to_vec().contains(), data);
- In other words, at the API level, the caller should not need to concern themselves with anything that isn't necessary. If I need to expose details later, then I'll deal with that later. The import part is not that the API exposes them, but that file formats allow for extension and expansion and any likely kind of future variant.
Summary
- I got entangled again today and didn't reach my goal. However I think I found clarity about why this is happening: I've been building an API that exposes all the complexity of handling all possible future needs, and that's just going to be too much work for me, for a hobby project.
- With this clarity, I'll try again next time.
Comments?
If you have feedback on this development session, please use the following fediverse thread: https://toot.liw.fi/@liw/114450344530545052,