mirror of
https://github.com/sbrow/envr.git
synced 2026-06-27 18:48:33 -04:00
140 lines
4.1 KiB
Rust
140 lines
4.1 KiB
Rust
//! Passphrase-based encryption and decryption (scrypt).
|
|
|
|
use crate::helpers::cstr_to_string;
|
|
use crate::types::{AgeBuffer, AgeResult};
|
|
use age::secrecy::SecretString;
|
|
use std::io::{Read, Write};
|
|
use std::os::raw::c_char;
|
|
|
|
/// Encrypt data using a passphrase.
|
|
///
|
|
/// # Arguments
|
|
/// * `plaintext` - Pointer to the plaintext data
|
|
/// * `plaintext_len` - Length of the plaintext
|
|
/// * `passphrase` - The passphrase string
|
|
/// * `armor` - If true, output will be ASCII-armored
|
|
/// * `output` - Pointer to receive the encrypted buffer
|
|
///
|
|
/// # Returns
|
|
/// AgeResult indicating success or failure
|
|
#[no_mangle]
|
|
pub extern "C" fn age_encrypt_passphrase(
|
|
plaintext: *const u8,
|
|
plaintext_len: usize,
|
|
passphrase: *const c_char,
|
|
armor: bool,
|
|
output: *mut AgeBuffer,
|
|
) -> AgeResult {
|
|
if plaintext.is_null() || output.is_null() {
|
|
return AgeResult::InvalidInput;
|
|
}
|
|
|
|
let plaintext = unsafe { std::slice::from_raw_parts(plaintext, plaintext_len) };
|
|
|
|
let passphrase_str = match unsafe { cstr_to_string(passphrase) } {
|
|
Ok(s) => s,
|
|
Err(e) => return e,
|
|
};
|
|
|
|
let secret = SecretString::from(passphrase_str);
|
|
let encryptor = age::Encryptor::with_user_passphrase(secret);
|
|
|
|
let mut encrypted = Vec::new();
|
|
|
|
let result = if armor {
|
|
let armor_writer = age::armor::ArmoredWriter::wrap_output(&mut encrypted, age::armor::Format::AsciiArmor)
|
|
.map_err(|_| AgeResult::ArmorError);
|
|
|
|
match armor_writer {
|
|
Ok(armor) => {
|
|
match encryptor.wrap_output(armor) {
|
|
Ok(mut writer) => {
|
|
if writer.write_all(plaintext).is_err() {
|
|
return AgeResult::EncryptionFailed;
|
|
}
|
|
match writer.finish() {
|
|
Ok(armor) => armor.finish().map_err(|_| AgeResult::ArmorError),
|
|
Err(_) => return AgeResult::EncryptionFailed,
|
|
}
|
|
}
|
|
Err(_) => return AgeResult::EncryptionFailed,
|
|
}
|
|
}
|
|
Err(e) => return e,
|
|
}
|
|
} else {
|
|
match encryptor.wrap_output(&mut encrypted) {
|
|
Ok(mut writer) => {
|
|
if writer.write_all(plaintext).is_err() {
|
|
return AgeResult::EncryptionFailed;
|
|
}
|
|
writer.finish().map_err(|_| AgeResult::EncryptionFailed)
|
|
}
|
|
Err(_) => return AgeResult::EncryptionFailed,
|
|
}
|
|
};
|
|
|
|
if result.is_err() {
|
|
return AgeResult::EncryptionFailed;
|
|
}
|
|
|
|
unsafe {
|
|
*output = AgeBuffer::from_vec(encrypted);
|
|
}
|
|
|
|
AgeResult::Success
|
|
}
|
|
|
|
/// Decrypt data using a passphrase.
|
|
///
|
|
/// # Arguments
|
|
/// * `ciphertext` - Pointer to the encrypted data
|
|
/// * `ciphertext_len` - Length of the ciphertext
|
|
/// * `passphrase` - The passphrase string
|
|
/// * `output` - Pointer to receive the decrypted buffer
|
|
///
|
|
/// # Returns
|
|
/// AgeResult indicating success or failure
|
|
#[no_mangle]
|
|
pub extern "C" fn age_decrypt_passphrase(
|
|
ciphertext: *const u8,
|
|
ciphertext_len: usize,
|
|
passphrase: *const c_char,
|
|
output: *mut AgeBuffer,
|
|
) -> AgeResult {
|
|
if ciphertext.is_null() || output.is_null() {
|
|
return AgeResult::InvalidInput;
|
|
}
|
|
|
|
let ciphertext = unsafe { std::slice::from_raw_parts(ciphertext, ciphertext_len) };
|
|
|
|
let passphrase_str = match unsafe { cstr_to_string(passphrase) } {
|
|
Ok(s) => s,
|
|
Err(e) => return e,
|
|
};
|
|
|
|
let secret = SecretString::from(passphrase_str);
|
|
let identity = age::scrypt::Identity::new(secret);
|
|
|
|
let decryptor = match age::Decryptor::new(ciphertext) {
|
|
Ok(d) => d,
|
|
Err(_) => return AgeResult::DecryptionFailed,
|
|
};
|
|
|
|
let mut decrypted = Vec::new();
|
|
let mut reader = match decryptor.decrypt(std::iter::once(&identity as &dyn age::Identity)) {
|
|
Ok(r) => r,
|
|
Err(_) => return AgeResult::DecryptionFailed,
|
|
};
|
|
|
|
if reader.read_to_end(&mut decrypted).is_err() {
|
|
return AgeResult::DecryptionFailed;
|
|
}
|
|
|
|
unsafe {
|
|
*output = AgeBuffer::from_vec(decrypted);
|
|
}
|
|
|
|
AgeResult::Success
|
|
}
|