Files
k-os/crates/filecrypt/src/tests.rs

131 lines
3.6 KiB
Rust

extern crate std;
use crate::*;
use std::vec;
fn master() -> Key {
Key([7; KEY_SIZE])
}
fn rng() -> Drbg {
Drbg::new([1; KEY_SIZE])
}
fn sealed(key: &Key, index: u64, last: bool, plain: &[u8]) -> std::vec::Vec<u8> {
let mut out = vec![0u8; plain.len() + OVERHEAD];
let n = seal(key, index, last, plain, &mut out, &mut rng());
out.truncate(n);
out
}
#[test]
fn a_chunk_opens_only_as_itself() {
let key = Header::new(&mut rng()).file_key(&area_key(&master(), b"home"));
let chunk = sealed(&key, 3, true, b"hello, k-os");
let mut out = [0u8; PLAIN_CHUNK];
assert_eq!(open(&key, 3, true, &chunk, &mut out), Some(11));
assert_eq!(&out[..11], b"hello, k-os");
assert_eq!(
open(&key, 4, true, &chunk, &mut out),
None,
"moved elsewhere in the file"
);
assert_eq!(
open(&key, 3, false, &chunk, &mut out),
None,
"no longer the last: something was cut off or added"
);
let other = Header::new(&mut Drbg::new([2; KEY_SIZE])).file_key(&area_key(&master(), b"home"));
assert_eq!(
open(&other, 3, true, &chunk, &mut out),
None,
"another file's key"
);
for at in [0, 23, 24, 30, chunk.len() - 1] {
let mut bent = chunk.clone();
bent[at] ^= 1;
assert_eq!(
open(&key, 3, true, &bent, &mut out),
None,
"byte {at} changed"
);
}
}
#[test]
fn one_apps_area_key_opens_nothing_of_anothers() {
let header = Header::new(&mut rng());
let notes = header.file_key(&area_key(&master(), b"data/kos.notes"));
let chat = header.file_key(&area_key(&master(), b"data/kos.chat"));
let chunk = sealed(&notes, 0, true, b"private");
let mut out = [0u8; 16];
assert_eq!(open(&chat, 0, true, &chunk, &mut out), None);
let other_master = header.file_key(&area_key(&Key([8; KEY_SIZE]), b"data/kos.notes"));
assert_eq!(
open(&other_master, 0, true, &chunk, &mut out),
None,
"another master key (a wiped device)"
);
}
#[test]
fn every_seal_takes_a_fresh_nonce() {
let key = Key([3; KEY_SIZE]);
let mut r = rng();
let (mut a, mut b) = ([0u8; 64], [0u8; 64]);
seal(&key, 0, true, b"same", &mut a, &mut r);
seal(&key, 0, true, b"same", &mut b, &mut r);
assert_ne!(a, b);
}
#[test]
fn headers_mark_encrypted_files() {
let h = Header::new(&mut rng());
assert_eq!(Header::decode(&h.encode()), Some(h));
assert_eq!(
Header::decode(b"Welcome to k-os. This is a plaintext file."),
None
);
assert_eq!(Header::decode(b"KOSFILE"), None, "too short");
}
#[test]
fn sizes_round_trip_across_chunk_boundaries() {
for plain in [
0,
1,
100,
PLAIN_CHUNK - 1,
PLAIN_CHUNK,
PLAIN_CHUNK + 1,
3 * PLAIN_CHUNK,
3 * PLAIN_CHUNK + 7,
] {
let disk = disk_len(plain);
assert_eq!(plain_len(disk), Some(plain), "{plain}");
}
assert_eq!(chunks(0), 1, "an empty file still has its last chunk");
for cut in [0, HEADER, HEADER + OVERHEAD - 1, HEADER + CHUNK + 5] {
assert_eq!(plain_len(cut), None, "{cut} bytes is no encrypted file");
}
}
#[test]
fn the_drbg_never_repeats_and_depends_on_its_seed() {
let mut a = Drbg::new([1; KEY_SIZE]);
let (mut x, mut y) = ([0u8; 32], [0u8; 32]);
a.fill(&mut x);
a.fill(&mut y);
assert_ne!(x, y);
let mut b = Drbg::new([1; KEY_SIZE]);
let mut z = [0u8; 32];
b.fill(&mut z);
assert_eq!(
x, z,
"the same seed, the same stream (so the seed must be fresh)"
);
let mut c = Drbg::new([2; KEY_SIZE]);
c.fill(&mut z);
assert_ne!(x, z);
}