Skip to content

Instantly share code, notes, and snippets.

@ssghost
Created May 10, 2024 02:44
Show Gist options
  • Save ssghost/454ae9f976732146ae8f7c614ac0332b to your computer and use it in GitHub Desktop.
Save ssghost/454ae9f976732146ae8f7c614ac0332b to your computer and use it in GitHub Desktop.
use std::fs::{File, remove_file};
use std::io::{Read, Write};
use orion::hazardous::{
aead::xchacha20poly1305::{seal, open, Nonce, SecretKey},
mac::poly1305::POLY1305_OUTSIZE,
stream::xchacha20::XCHACHA_NONCESIZE,
};
use orion::hazardous::stream::chacha20::CHACHA_KEYSIZE;
use orion::kdf::{derive_key, Password, Salt};
use rand_core::{OsRng, RngCore};
fn get_random(dest: &mut [u8]) {
RngCore::fill_bytes(&mut OsRng, dest);
}
fn nonce() -> Vec<u8> {
let mut randoms: [u8; 24] = [0; 24];
get_random(&mut randoms);
return randoms.to_vec();
}
fn auth_tag() -> Vec<u8> {
let mut randoms: [u8; 32] = [0; 32];
get_random(&mut randoms);
return randoms.to_vec();
}
fn simple_split_encrypted(cipher_text: &[u8]) -> (Vec<u8>, Vec<u8>) {
return (
cipher_text[..CHACHA_KEYSIZE].to_vec(),
cipher_text[CHACHA_KEYSIZE..].to_vec(),
)
}
fn create_key(password: String, nonce: Vec<u8>) -> SecretKey {
let password = Password::from_slice(password.as_bytes()).unwrap();
let salt = Salt::from_slice(nonce.as_slice()).unwrap();
let kdf_key = derive_key(&password, &salt, 15, 1024, CHACHA_KEYSIZE as u32).unwrap();
let key = SecretKey::from_slice(kdf_key.unprotected_as_bytes()).unwrap();
return key;
}
fn encrypt_core(
dist: &mut File,
contents: Vec<u8>,
key: &SecretKey,
nonce: Nonce,
) {
let ad = auth_tag();
let output_len = match contents.len().checked_add(POLY1305_OUTSIZE + ad.len()) {
Some(min_output_len) => min_output_len,
None => panic!("Plaintext is too long"),
};
let mut output = vec![0u8; output_len];
output[..CHACHA_KEYSIZE].copy_from_slice(ad.as_ref());
seal(&key, &nonce, contents.as_slice(), Some(ad.clone().as_slice()), &mut output[CHACHA_KEYSIZE..]).unwrap();
dist.write(&output.as_slice()).unwrap();
}
fn decrypt_core(
dist: &mut File,
contents: Vec<u8>,
key: &SecretKey,
nonce: Nonce
) {
let split = simple_split_encrypted(contents.as_slice());
let mut output = vec![0u8; split.1.len() - POLY1305_OUTSIZE];
open(&key, &nonce, split.1.as_slice(), Some(split.0.as_slice()), &mut output).unwrap();
dist.write(&output.as_slice()).unwrap();
}
const CHUNK_SIZE: usize = 128; // The size of the chunks you wish to split the stream into.
pub fn encrypt_large_file(
file_path: &str,
output_path: &str,
password: String
) -> Result<(), orion::errors::UnknownCryptoError> {
let mut source_file = File::open(file_path).expect("Failed to open input file");
let mut dist = File::create(output_path).expect("Failed to create output file");
let mut src = Vec::new();
source_file.read_to_end(&mut src).expect("Failed to read input file");
let nonce = nonce();
dist.write(nonce.as_slice()).unwrap();
let key = create_key(password, nonce.clone());
let nonce = Nonce::from_slice(nonce.as_slice()).unwrap();
for (n_chunk, src_chunk) in src.chunks(CHUNK_SIZE).enumerate() {
encrypt_core(&mut dist, src_chunk.to_vec(), &key, nonce)
}
Ok(())
}
pub fn decrypt_large_file(
file_path: &str,
output_path: &str,
password: String
) -> Result<(), orion::errors::UnknownCryptoError> {
let mut input_file = File::open(file_path).expect("Failed to open input file");
let mut output_file = File::create(output_path).expect("Failed to create output file");
let mut src: Vec<u8> = Vec::new();
input_file.read_to_end(&mut src).expect("Failed to read input file");
let nonce = src[..XCHACHA_NONCESIZE].to_vec();
src = src[XCHACHA_NONCESIZE..].to_vec();
let key = create_key(password, nonce.clone());
let nonce = Nonce::from_slice(nonce.as_slice()).unwrap();
for (n_chunk, src_chunk) in src.chunks(CHUNK_SIZE + CHACHA_KEYSIZE + POLY1305_OUTSIZE).enumerate() {
decrypt_core(&mut output_file, src_chunk.to_vec(), &key, nonce);
}
Ok(())
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment