separate KDF (not a proper KDF for now)
This commit is contained in:
@@ -0,0 +1,26 @@
|
|||||||
|
//! Password-to-key derivation.
|
||||||
|
//!
|
||||||
|
//! This currently uses SHA3-256 directly and truncates the result to 24 bytes
|
||||||
|
//! because `KeccakAead` accepts keys up to 24 bytes.
|
||||||
|
//!
|
||||||
|
//! This is not a proper password-based KDF. There is currently no salt,
|
||||||
|
//! work factor, memory hardness, or iteration count.
|
||||||
|
|
||||||
|
use crate::keccak::sha3_256;
|
||||||
|
|
||||||
|
/// Length of the key produced for `KeccakAead`.
|
||||||
|
pub const DERIVED_KEY_LEN: usize = 24;
|
||||||
|
|
||||||
|
/// Derive a 24-byte encryption key from a password.
|
||||||
|
///
|
||||||
|
/// The password is encoded as UTF-8 and hashed using the project's
|
||||||
|
/// SHA3-256 implementation. The first 24 bytes of the digest are used
|
||||||
|
/// as the AEAD key.
|
||||||
|
pub fn derive_file_key(password: &str) -> [u8; DERIVED_KEY_LEN] {
|
||||||
|
let digest = sha3_256(password.as_bytes());
|
||||||
|
|
||||||
|
let mut key = [0u8; DERIVED_KEY_LEN];
|
||||||
|
key.copy_from_slice(&digest[..DERIVED_KEY_LEN]);
|
||||||
|
|
||||||
|
key
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
mod kdf;
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test;
|
||||||
|
|
||||||
|
pub use kdf::derive_file_key;
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
use super::*;
|
||||||
|
use crate::kdf::kdf::DERIVED_KEY_LEN;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn key_has_expected_length() {
|
||||||
|
assert_eq!(DERIVED_KEY_LEN, 24);
|
||||||
|
|
||||||
|
let key = derive_file_key("test password");
|
||||||
|
assert_eq!(key.len(), DERIVED_KEY_LEN);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn same_password_same_key() {
|
||||||
|
let a = derive_file_key("correct horse battery staple");
|
||||||
|
let b = derive_file_key("correct horse battery staple");
|
||||||
|
|
||||||
|
assert_eq!(a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn different_passwords_produce_different_keys() {
|
||||||
|
let a = derive_file_key("password1");
|
||||||
|
let b = derive_file_key("password2");
|
||||||
|
|
||||||
|
assert_ne!(a, b);
|
||||||
|
}
|
||||||
+16
-18
@@ -4,12 +4,14 @@ use std::path::PathBuf;
|
|||||||
use clap::{Parser, Subcommand};
|
use clap::{Parser, Subcommand};
|
||||||
|
|
||||||
mod file_crypt;
|
mod file_crypt;
|
||||||
|
mod kdf;
|
||||||
mod keccak;
|
mod keccak;
|
||||||
mod keccak_aead;
|
mod keccak_aead;
|
||||||
|
|
||||||
use file_crypt::{MAX_KEY_LEN, decrypt_file, encrypt_file};
|
use file_crypt::{decrypt_file, encrypt_file};
|
||||||
|
use kdf::derive_file_key;
|
||||||
|
|
||||||
/// File encryption utility using KeccakAead.
|
/// Encrypt and decrypt files using KeccakAead.
|
||||||
#[derive(Parser, Debug)]
|
#[derive(Parser, Debug)]
|
||||||
#[command(
|
#[command(
|
||||||
name = "filecrypt-rs",
|
name = "filecrypt-rs",
|
||||||
@@ -54,18 +56,6 @@ enum Command {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Derive the fixed-length AEAD key from a password.
|
|
||||||
///
|
|
||||||
/// SHA-3-256 produces 32 bytes, while `KeccakAead` currently accepts keys from 16 through 24 bytes. Therefore we use the first 24 bytes.
|
|
||||||
fn derive_key(password: &str) -> [u8; MAX_KEY_LEN] {
|
|
||||||
let digest = keccak::sha3_256(password.as_bytes());
|
|
||||||
|
|
||||||
let mut key = [0u8; MAX_KEY_LEN];
|
|
||||||
key.copy_from_slice(&digest[..MAX_KEY_LEN]);
|
|
||||||
|
|
||||||
key
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() -> Result<(), Box<dyn Error>> {
|
fn main() -> Result<(), Box<dyn Error>> {
|
||||||
let cli = Cli::parse();
|
let cli = Cli::parse();
|
||||||
|
|
||||||
@@ -75,11 +65,15 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||||||
output,
|
output,
|
||||||
password,
|
password,
|
||||||
} => {
|
} => {
|
||||||
let key = derive_key(&password);
|
let key = derive_file_key(&password);
|
||||||
|
|
||||||
encrypt_file(&input, &output, &key)?;
|
encrypt_file(&input, &output, &key)?;
|
||||||
|
|
||||||
println!("Encrypted '{}' -> '{}'", input.display(), output.display());
|
println!(
|
||||||
|
"Encrypted '{}' -> '{}'",
|
||||||
|
input.display(),
|
||||||
|
output.display()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Command::Decrypt {
|
Command::Decrypt {
|
||||||
@@ -87,11 +81,15 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||||||
output,
|
output,
|
||||||
password,
|
password,
|
||||||
} => {
|
} => {
|
||||||
let key = derive_key(&password);
|
let key = derive_file_key(&password);
|
||||||
|
|
||||||
decrypt_file(&input, &output, &key)?;
|
decrypt_file(&input, &output, &key)?;
|
||||||
|
|
||||||
println!("Decrypted '{}' -> '{}'", input.display(), output.display());
|
println!(
|
||||||
|
"Decrypted '{}' -> '{}'",
|
||||||
|
input.display(),
|
||||||
|
output.display()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user