mirror of
https://github.com/spacedriveapp/spacedrive.git
synced 2026-04-28 10:28:09 -04:00
* rebase: `crates/crypto` into current `main` * refactor: remove `mnemonic` module * feat: disable secure erase temporarily * fix: tsc * fix: tsc due to unused import * fix: remove `cli` crypto info * deps: update * chore: remove dead comment * refactor: remove `bincode` feature * refactor: give `keyring` a dedicated feature so it's not reliant on `sys` as well * fix: remove `aes-gcm` as it's no longer supported * refactor: remove dead comment * fix: update `keyring` imports * refactor: change tests to `aes-256-gcm` * feat: make `Key` a `Box<>` internally to ensure it's heap allocated (and fix tests) * chore: clippy * fix: hashing tests now that `const` keys aren't available this will be cleaned up with test vectors and `include_bytes!()` * chore: clippy * refactor: remove dead code * test: bring back `encrypt_with_invalid_nonce` test * fix: secret service keyring * fix: `zbus` build issues * doc: update comment for clearer reasoning * fix: cargo fmt * fix: use bytes directly * deps: update lockfile * fix: secret service keyring * fix: comment out windows keyring for now * fix: use session keyring if no keyring backend * fix: completely remove keyring module if no keyring is available for that OS * fix: clippy * fix: move iimport to correct conditional compilation * fix: fmt
120 lines
3.2 KiB
Rust
120 lines
3.2 KiB
Rust
use sd_crypto::{
|
|
crypto::{Decryptor, Encryptor},
|
|
encoding::Header,
|
|
hashing::Hasher,
|
|
types::{
|
|
Algorithm, DerivationContext, HashingAlgorithm, Key, MagicBytes, Params, Salt, SecretKey,
|
|
},
|
|
Protected,
|
|
};
|
|
use std::io::{Cursor, Read, Seek, Write};
|
|
|
|
const MAGIC_BYTES: MagicBytes<6> = MagicBytes::new(*b"crypto");
|
|
|
|
const HEADER_KEY_CONTEXT: DerivationContext =
|
|
DerivationContext::new("crypto 2023-03-21 11:24:53 example header key context");
|
|
|
|
const HEADER_OBJECT_CONTEXT: DerivationContext =
|
|
DerivationContext::new("crypto 2023-03-21 11:25:08 example header object context");
|
|
|
|
const ALGORITHM: Algorithm = Algorithm::XChaCha20Poly1305;
|
|
const HASHING_ALGORITHM: HashingAlgorithm = HashingAlgorithm::Argon2id(Params::Standard);
|
|
|
|
const OBJECT_DATA: [u8; 15] = *b"a nice mountain";
|
|
|
|
fn encrypt<R, W>(reader: &mut R, writer: &mut W)
|
|
where
|
|
R: Read,
|
|
W: Write + Seek,
|
|
{
|
|
let password = Protected::new(b"password".to_vec());
|
|
|
|
// This needs to be generated here, otherwise we won't have access to it for encryption
|
|
let master_key = Key::generate();
|
|
|
|
// These should ideally be done by a key management system
|
|
let content_salt = Salt::generate();
|
|
let hashed_password =
|
|
Hasher::hash_password(HASHING_ALGORITHM, &password, content_salt, &SecretKey::Null)
|
|
.unwrap();
|
|
|
|
// Create the header for the encrypted file
|
|
let mut header = Header::new(ALGORITHM);
|
|
|
|
// Create a keyslot to be added to the header
|
|
header
|
|
.add_keyslot(
|
|
HASHING_ALGORITHM,
|
|
content_salt,
|
|
&hashed_password,
|
|
&master_key,
|
|
HEADER_KEY_CONTEXT,
|
|
)
|
|
.unwrap();
|
|
|
|
header
|
|
.add_object(
|
|
"FileMetadata",
|
|
HEADER_OBJECT_CONTEXT,
|
|
&master_key,
|
|
&OBJECT_DATA,
|
|
)
|
|
.unwrap();
|
|
|
|
// Write the header to the file
|
|
header.to_writer(writer, MAGIC_BYTES).unwrap();
|
|
|
|
// Use the nonce created by the header to initialize an encryptor
|
|
let encryptor = Encryptor::new(&master_key, &header.nonce, header.algorithm).unwrap();
|
|
|
|
// Encrypt the data from the reader, and write it to the writer
|
|
// Use AAD so the header can be authenticated against every block of data
|
|
encryptor
|
|
.encrypt_streams(reader, writer, header.generate_aad())
|
|
.unwrap();
|
|
}
|
|
|
|
fn decrypt<R, W>(reader: &mut R, writer: &mut W) -> Vec<u8>
|
|
where
|
|
R: Read + Seek,
|
|
W: Write,
|
|
{
|
|
let password = Protected::new(b"password".to_vec());
|
|
|
|
// Deserialize the header from the encrypted file
|
|
let (header, aad) = Header::from_reader(reader, MAGIC_BYTES).unwrap();
|
|
|
|
let (master_key, index) = header
|
|
.decrypt_master_key_with_password(&password, HEADER_KEY_CONTEXT)
|
|
.unwrap();
|
|
|
|
println!("key is in slot: {index}");
|
|
|
|
let decryptor = Decryptor::new(&master_key, &header.nonce, header.algorithm).unwrap();
|
|
|
|
// Decrypt data the from the reader, and write it to the writer
|
|
decryptor.decrypt_streams(reader, writer, aad).unwrap();
|
|
|
|
// Decrypt the object
|
|
let object = header
|
|
.decrypt_object("FileMetadata", HEADER_OBJECT_CONTEXT, &master_key)
|
|
.unwrap();
|
|
|
|
object.into_inner()
|
|
}
|
|
|
|
fn main() {
|
|
// Open both the source and the output file
|
|
let mut source = Cursor::new(vec![5u8; 256]);
|
|
let mut dest = Cursor::new(vec![]);
|
|
let mut source_comparison = Cursor::new(vec![]);
|
|
|
|
encrypt(&mut source, &mut dest);
|
|
|
|
dest.rewind().unwrap();
|
|
|
|
let object_data = decrypt(&mut dest, &mut source_comparison);
|
|
|
|
assert_eq!(&object_data, &OBJECT_DATA);
|
|
}
|