engine/snapshot/migration/
v2.rs1use super::*;
5
6const KEY_SIZE: usize = 32;
8pub type Key = [u8; KEY_SIZE];
10
11const NONCE_SIZE: usize = XChaCha20Poly1305::NONCE_LENGTH;
13pub type Nonce = [u8; NONCE_SIZE];
15
16const VERSION_V2: [u8; 2] = [0x2, 0x0];
17
18pub(crate) fn read<I: Read>(input: &mut I, key: &Key, associated_data: &[u8]) -> Result<Zeroizing<Vec<u8>>, Error> {
21 let mut ephemeral_pk = [0; x25519::PUBLIC_KEY_LENGTH];
23 input.read_exact(&mut ephemeral_pk)?;
25
26 let mut key_bytes = [0u8; x25519::SECRET_KEY_LENGTH];
28 key_bytes.clone_from_slice(key);
29
30 let ephemeral_pk = x25519::PublicKey::from_bytes(ephemeral_pk);
32
33 let sk = x25519::SecretKey::from_bytes(key_bytes);
35 let pk = sk.public_key();
36
37 let shared = sk.diffie_hellman(&ephemeral_pk);
39
40 let nonce = {
42 let mut i = ephemeral_pk.to_bytes().to_vec();
43 i.extend_from_slice(&pk.to_bytes());
44 let res = blake2b::Blake2b256::digest(&i).to_vec();
45 let v: Nonce = res[0..NONCE_SIZE].try_into().expect("slice with incorrect length");
46 v
47 };
48
49 let mut tag = [0; XChaCha20Poly1305::TAG_LENGTH];
51 input.read_exact(&mut tag)?;
52
53 let mut ct = Vec::new();
55 input.read_to_end(&mut ct)?;
56
57 let mut pt = Zeroizing::new(vec![0; ct.len()]);
59
60 XChaCha20Poly1305::try_decrypt(&shared.to_bytes(), &nonce, associated_data, &mut pt, &ct, &tag)
62 .map_err(|_| Error::DecryptFailed)?;
63
64 Ok(pt)
65}
66
67#[allow(dead_code)]
70pub(crate) fn write<O: Write>(plain: &[u8], output: &mut O, key: &Key, associated_data: &[u8]) -> Result<(), Error> {
71 let ephemeral_key = x25519::SecretKey::generate()?;
73
74 let ephemeral_pk = ephemeral_key.public_key();
76
77 let ephemeral_pk_bytes = ephemeral_pk.to_bytes();
78
79 output.write_all(&ephemeral_pk_bytes)?;
81
82 let mut key_bytes = [0u8; x25519::SECRET_KEY_LENGTH];
84 key_bytes.clone_from_slice(key);
85
86 let pk = x25519::SecretKey::from_bytes(key_bytes).public_key();
88
89 let pk_bytes = pk.to_bytes();
90
91 let shared = ephemeral_key.diffie_hellman(&pk);
93
94 let nonce = {
96 let mut i = ephemeral_pk.to_bytes().to_vec();
97 i.extend_from_slice(&pk_bytes);
98 let res = blake2b::Blake2b256::digest(&i).to_vec();
99 let v: Nonce = res[0..NONCE_SIZE].try_into().expect("slice with incorrect length");
100 v
101 };
102
103 let mut tag = [0; XChaCha20Poly1305::TAG_LENGTH];
105
106 let mut ct = vec![0; plain.len()];
108
109 XChaCha20Poly1305::try_encrypt(&shared.to_bytes(), &nonce, associated_data, plain, &mut ct, &mut tag)?;
111
112 output.write_all(&tag)?;
114 output.write_all(&ct)?;
115
116 Ok(())
117}
118
119pub(crate) fn read_snapshot(path: &Path, key: &[u8; 32], aad: &[u8]) -> Result<Zeroizing<Vec<u8>>, Error> {
132 let mut f: File = OpenOptions::new().read(true).open(path)?;
133
134 const MIN_LEN: u64 =
136 (MAGIC.len() + VERSION_V2.len() + x25519::PUBLIC_KEY_LENGTH + XChaCha20Poly1305::TAG_LENGTH) as u64;
137 guard(f.metadata()?.len() >= MIN_LEN, Error::BadSnapshotFormat)?;
138
139 let mut magic = [0u8; 5];
141 f.read_exact(&mut magic)?;
142 guard(magic == MAGIC, Error::BadSnapshotFormat)?;
143
144 let mut version = [0u8; 2];
146 f.read_exact(&mut version)?;
147 guard(version == VERSION_V2, Error::BadSnapshotVersion)?;
148
149 let pt = Zeroizing::new(read(&mut f, key, aad)?);
150
151 decompress(&pt).map(Zeroizing::new).map_err(|_| Error::DecompressFailed)
152}