本方法使用了 aes-gcm
与 pbkdf2
库,其中 aes-gcm
用来加密文件, pbkdf2
用来生成加密密钥
附上整个文件加解密类的实现代码: 依赖:
aes-gcm = "0.10"
pbkdf2 = { version = "0.12", features = ["simple"] }
sha2 = "0.10.8"
代码:
pub struct FileEncryption<'cipher> {
password: &'cipher str,
rounds: u32,
}
impl<'cipher> FileEncryption<'cipher> {
pub fn new(password: &'cipher str, rounds: u32) -> Self {
FileEncryption {
password,
rounds,
}
}
fn create_password(&self, file_name: &str) -> Result<[u8; 32]> {
let salt = file_name.as_bytes();
let password = self.password.as_bytes();
let mut key = [0u8; 32];
pbkdf2_hmac::<Sha256>(password, salt, self.rounds, &mut key);
Ok(key)
}
fn generate_cipher_and_nonce(&self, file_name: &str)
-> Result<(AesGcm<Aes256, U12>, GenericArray<u8, U12>)> {
let key = self.create_password(file_name)?;
let key = Key::<Aes256Gcm>::from(key);
let cipher = Aes256Gcm::new(&key);
let mut nonce = Nonce::default();
pbkdf2_hmac::<Sha256>(file_name.as_bytes(), self.password.as_bytes(), self.rounds, &mut nonce);
Ok((cipher, nonce))
}
pub fn encrypt_file(&self, file_path: &Path) -> Result<PathBuf> {
let file_name = file_path.file_name().ok_or(anyhow!(CANNOT_READ_FILE_NAME))?
.to_str().ok_or(anyhow!(CONVERT_STR_FAIL))?;
let (cipher, nonce) =
self.generate_cipher_and_nonce(file_name)?;
let mut input_file = File::open(file_path)?;
let mut buffer = Vec::new();
input_file.read_to_end(&mut buffer)?;
let ciphertext = cipher.encrypt(&nonce, &*buffer);
if let Err(e) = ciphertext {
anyhow!(e);
};
let ciphertext = ciphertext.unwrap();
let save_path = PathBuf::new().join(TEMP_PATH)
.join(format!("{}{}", file_name, ENCRYPTED_FILE_SUFFIX));
let mut output_file = File::create(&save_path)?;
output_file.write_all(&*ciphertext)?;
Ok(save_path)
}
pub fn decrypt_file(&self, file_path: &Path) -> Result<PathBuf> {
let file_name = file_path.file_name().ok_or(anyhow!(CANNOT_READ_FILE_NAME))?
.to_str().ok_or(anyhow!(CONVERT_STR_FAIL))?.replace(ENCRYPTED_FILE_SUFFIX, "");
let (cipher, nonce) = self.generate_cipher_and_nonce(&*file_name)?;
let mut input_file = File::open(file_path)?;
let mut buffer = Vec::new();
input_file.read_to_end(&mut buffer)?;
let ciphertext = cipher.decrypt(&nonce, &*buffer);
if let Err(e) = ciphertext {
anyhow!(e);
};
let ciphertext = ciphertext.unwrap();
let save_path = PathBuf::new().join(TEMP_PATH).join(file_name);
let mut output_file = File::create(&save_path)?;
output_file.write_all(&*ciphertext)?;
Ok(save_path)
}
}
大写的常量都是其他文件里定义的 &str
类型