age-crypto 0.2.0

A safe, ergonomic Rust wrapper around the age encryption library with strong typing, comprehensive error handling, and passphrase support.
Documentation
#![allow(unsafe_code)]
use std::ffi::{CStr, CString};
use std::os::raw::c_char;
use std::ptr;
use std::slice;
#[unsafe(no_mangle)]
pub unsafe extern "C" fn age_last_error_message() -> *mut c_char {
    ptr::null_mut()
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn age_free_string(s: *mut c_char) {
    unsafe {
        if !s.is_null() {
            drop(CString::from_raw(s));
        }
    }
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn age_free_bytes(data: *mut u8, len: usize) {
    unsafe {
        if !data.is_null() && len > 0 {
            drop(Vec::from_raw_parts(data, len, len));
        }
    }
}
fn handle_error_to_code(err: crate::Error) -> i32 {
    eprintln!("Age Crypto Error: {}", err);
    -1
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn age_encrypt(
    plaintext: *const u8,
    plaintext_len: usize,
    recipients: *const *const c_char,
    recipients_count: usize,
    out_data: *mut *mut u8,
    out_len: *mut usize,
) -> i32 {
    let plaintext = unsafe { slice::from_raw_parts(plaintext, plaintext_len) };
    let mut recips = Vec::new();
    let ptr_slice = unsafe { slice::from_raw_parts(recipients, recipients_count) };
    for &p in ptr_slice {
        let c_str = unsafe { CStr::from_ptr(p) };
        match c_str.to_str() {
            Ok(s) => recips.push(s),
            Err(_) => return -2,
        }
    }
    match crate::encrypt(plaintext, &recips) {
        Ok(data) => {
            let mut buf: Vec<u8> = data.into();
            unsafe {
                *out_data = buf.as_mut_ptr();
                *out_len = buf.len();
            }
            std::mem::forget(buf);
            0
        }
        Err(e) => handle_error_to_code(e),
    }
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn age_encrypt_armor(
    plaintext: *const u8,
    plaintext_len: usize,
    recipients: *const *const c_char,
    recipients_count: usize,
    out_str: *mut *mut c_char,
) -> i32 {
    let plaintext = unsafe { slice::from_raw_parts(plaintext, plaintext_len) };
    let mut recips = Vec::new();
    let ptr_slice = unsafe { slice::from_raw_parts(recipients, recipients_count) };
    for &p in ptr_slice {
        let c_str = unsafe { CStr::from_ptr(p) };
        match c_str.to_str() {
            Ok(s) => recips.push(s),
            Err(_) => return -2,
        }
    }
    match crate::encrypt_armor(plaintext, &recips) {
        Ok(data) => {
            let s = data.to_string();
            match CString::new(s) {
                Ok(c_s) => {
                    unsafe { *out_str = c_s.into_raw() };
                    0
                }
                Err(_) => -3,
            }
        }
        Err(e) => handle_error_to_code(e),
    }
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn age_encrypt_with_passphrase(
    plaintext: *const u8,
    plaintext_len: usize,
    passphrase: *const c_char,
    out_data: *mut *mut u8,
    out_len: *mut usize,
) -> i32 {
    let plaintext = unsafe { slice::from_raw_parts(plaintext, plaintext_len) };
    let pass = unsafe { CStr::from_ptr(passphrase) };
    let pass_str = match pass.to_str() {
        Ok(s) => s,
        Err(_) => return -2,
    };
    match crate::encrypt_with_passphrase(plaintext, pass_str) {
        Ok(data) => {
            let mut buf: Vec<u8> = data.into();
            unsafe {
                *out_data = buf.as_mut_ptr();
                *out_len = buf.len();
            }
            std::mem::forget(buf);
            0
        }
        Err(e) => handle_error_to_code(e),
    }
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn age_encrypt_with_passphrase_armor(
    plaintext: *const u8,
    plaintext_len: usize,
    passphrase: *const c_char,
    out_str: *mut *mut c_char,
) -> i32 {
    let plaintext = unsafe { slice::from_raw_parts(plaintext, plaintext_len) };
    let pass = unsafe { CStr::from_ptr(passphrase) };
    let pass_str = match pass.to_str() {
        Ok(s) => s,
        Err(_) => return -2,
    };
    match crate::encrypt_with_passphrase_armor(plaintext, pass_str) {
        Ok(data) => {
            let s = data.to_string();
            match CString::new(s) {
                Ok(c_s) => {
                    unsafe { *out_str = c_s.into_raw() };
                    0
                }
                Err(_) => -3,
            }
        }
        Err(e) => handle_error_to_code(e),
    }
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn age_decrypt(
    ciphertext: *const u8,
    ciphertext_len: usize,
    secret_key: *const c_char,
    out_data: *mut *mut u8,
    out_len: *mut usize,
) -> i32 {
    let ciphertext = unsafe { slice::from_raw_parts(ciphertext, ciphertext_len) };
    let key = unsafe { CStr::from_ptr(secret_key) };
    let key_str = match key.to_str() {
        Ok(s) => s,
        Err(_) => return -2,
    };
    match crate::decrypt(ciphertext, key_str) {
        Ok(mut data) => {
            unsafe {
                *out_data = data.as_mut_ptr();
                *out_len = data.len();
            }
            std::mem::forget(data);
            0
        }
        Err(e) => handle_error_to_code(e),
    }
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn age_decrypt_armor(
    armored_str: *const c_char,
    secret_key: *const c_char,
    out_data: *mut *mut u8,
    out_len: *mut usize,
) -> i32 {
    let armored = unsafe { CStr::from_ptr(armored_str) };
    let armored_s = match armored.to_str() {
        Ok(s) => s,
        Err(_) => return -2,
    };
    let key = unsafe { CStr::from_ptr(secret_key) };
    let key_str = match key.to_str() {
        Ok(s) => s,
        Err(_) => return -2,
    };
    match crate::decrypt_armor(armored_s, key_str) {
        Ok(mut data) => {
            unsafe {
                *out_data = data.as_mut_ptr();
                *out_len = data.len();
            }
            std::mem::forget(data);
            0
        }
        Err(e) => handle_error_to_code(e),
    }
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn age_decrypt_with_passphrase(
    ciphertext: *const u8,
    ciphertext_len: usize,
    passphrase: *const c_char,
    out_data: *mut *mut u8,
    out_len: *mut usize,
) -> i32 {
    let ciphertext = unsafe { slice::from_raw_parts(ciphertext, ciphertext_len) };
    let pass = unsafe { CStr::from_ptr(passphrase) };
    let pass_str = match pass.to_str() {
        Ok(s) => s,
        Err(_) => return -2,
    };
    match crate::decrypt_with_passphrase(ciphertext, pass_str) {
        Ok(mut data) => {
            unsafe {
                *out_data = data.as_mut_ptr();
                *out_len = data.len();
            }
            std::mem::forget(data);
            0
        }
        Err(e) => handle_error_to_code(e),
    }
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn age_decrypt_with_passphrase_armor(
    armored_str: *const c_char,
    passphrase: *const c_char,
    out_data: *mut *mut u8,
    out_len: *mut usize,
) -> i32 {
    let armored = unsafe { CStr::from_ptr(armored_str) };
    let armored_s = match armored.to_str() {
        Ok(s) => s,
        Err(_) => return -2,
    };
    let pass = unsafe { CStr::from_ptr(passphrase) };
    let pass_str = match pass.to_str() {
        Ok(s) => s,
        Err(_) => return -2,
    };
    match crate::decrypt_with_passphrase_armor(armored_s, pass_str) {
        Ok(mut data) => {
            unsafe {
                *out_data = data.as_mut_ptr();
                *out_len = data.len();
            }
            std::mem::forget(data);
            0
        }
        Err(e) => handle_error_to_code(e),
    }
}