Added language bindings for Rust.

This commit is contained in:
LoRd_MuldeR 2024-06-22 22:08:00 +02:00
parent 2505493534
commit d7f741c28c
Signed by: mulder
GPG Key ID: 2B5913365F57E03F
14 changed files with 804 additions and 0 deletions

1
.gitignore vendored
View File

@ -3,5 +3,6 @@
/**/bin /**/bin
/**/lib /**/lib
/**/obj /**/obj
/**/target
/.vs /.vs
/out /out

101
binding/rust/Cargo.lock generated Normal file
View File

@ -0,0 +1,101 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "cpufeatures"
version = "0.2.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504"
dependencies = [
"libc",
]
[[package]]
name = "getrandom"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
dependencies = [
"cfg-if",
"libc",
"wasi",
]
[[package]]
name = "hex"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
[[package]]
name = "libc"
version = "0.2.155"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
[[package]]
name = "memx"
version = "0.1.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93022fcc0eab2dc9dd134e362592e06f0b3c0aa549ae91d8b3e539e56c2a0687"
dependencies = [
"cpufeatures",
]
[[package]]
name = "ppv-lite86"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
[[package]]
name = "rand"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
dependencies = [
"libc",
"rand_chacha",
"rand_core",
]
[[package]]
name = "rand_chacha"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
dependencies = [
"ppv-lite86",
"rand_core",
]
[[package]]
name = "rand_core"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
dependencies = [
"getrandom",
]
[[package]]
name = "slunkcrypt-rs"
version = "1.0.0"
dependencies = [
"hex",
"memx",
"rand",
]
[[package]]
name = "wasi"
version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"

9
binding/rust/Cargo.toml Normal file
View File

@ -0,0 +1,9 @@
[package]
name = "slunkcrypt-rs"
version = "1.0.0"
edition = "2021"
[dev-dependencies]
hex = "0.4.3"
memx = "0.1.32"
rand = "0.8.5"

11
binding/rust/build.rs Normal file
View File

@ -0,0 +1,11 @@
/******************************************************************************/
/* SlunkCrypt, by LoRd_MuldeR <MuldeR2@GMX.de> */
/* This work has been released under the CC0 1.0 Universal license! */
/******************************************************************************/
use std::env;
fn main() {
println!(r"cargo:rustc-link-search={}/../../libslunkcrypt/lib", env::var("CARGO_MANIFEST_DIR").unwrap());
println!(r"cargo:rustc-link-lib=slunkcrypt-1");
}

View File

@ -0,0 +1,31 @@
/******************************************************************************/
/* SlunkCrypt, by LoRd_MuldeR <MuldeR2@GMX.de> */
/* This work has been released under the CC0 1.0 Universal license! */
/******************************************************************************/
use slunkcrypt_rs::{SlunkCrypt, SlunkCryptPasswd};
use hex;
use rand::{thread_rng, RngCore};
use std::mem;
fn main() {
// Create passphrase from string
const PASSPHRASE: SlunkCryptPasswd = SlunkCryptPasswd::Str("OrpheanBeholderScryDoubt");
// Fill buffer with random data (plaintext)
let mut buffer = [ 0u8; 64 ];
thread_rng().fill_bytes(&mut buffer);
println!("Plaintext: {}", hex::encode(&buffer));
// Encrypt the data in-place
let (mut context_enc, nonce) = SlunkCrypt::init_encrypt(&PASSPHRASE, None).expect("Failed to create encryption context!");
context_enc.inplace(&mut buffer).expect("Failed to encrypt data!");
mem::drop(context_enc);
println!("Encrypted: {}", hex::encode(&buffer));
// Decrypt the data in-place
let mut context_dec = SlunkCrypt::init_decrypt(&PASSPHRASE, nonce, None).expect("Failed to create decryption context!");
context_dec.inplace(&mut buffer).expect("Failed to decrypt data!");
mem::drop(context_dec);
println!("Decrypted: {}", hex::encode(&buffer));
}

185
binding/rust/src/context.rs Normal file
View File

@ -0,0 +1,185 @@
/******************************************************************************/
/* SlunkCrypt, by LoRd_MuldeR <MuldeR2@GMX.de> */
/* This work has been released under the CC0 1.0 Universal license! */
/******************************************************************************/
use std::num::NonZeroUsize;
use std::ptr;
use crate::error::{SlunkCryptError, SlunkCryptErrorKind};
use crate::functions::generate_nonce;
use crate::ffi::libslunkcrypt::{self, slunkcrypt_t, slunkparam_t, SLUNKCRYPT_SUCCESS, SLUNKCRYPT_NULL};
use crate::passwd::SlunkCryptPasswd;
/// SlunkCrypt context for encryption or decryption.
///
/// This struct wraps the "native" SlunkCrypt context. It provides functions for allocating a new encryption or decryption context as well as functions for processing, i.e. encrypting or decrypting, the next chunk of data within a specific `SlunkCrypt` context.
///
/// The wrapped "native" SlunkCrypt context is freed automatically when this struct is dropped.
///
/// # Thread safety
///
/// Separate `SlunkCrypt` contexts can safely be accessed from concurrent threads *without* the need for any kind if synchronization, provided that each context is only accessed by the *single* thread that has allocated the respective context.
///
/// # Example
/// ```
/// use slunkcrypt_rs::{SlunkCrypt, SlunkCryptPasswd};
/// use hex;
/// use rand::{thread_rng, RngCore};
/// use std::mem;
///
/// fn main() {
/// // Create passphrase from string
/// const PASSPHRASE: SlunkCryptPasswd = SlunkCryptPasswd::Str("OrpheanBeholderScryDoubt");
///
/// // Fill buffer with random data (plaintext)
/// let mut buffer = [ 0u8; 64 ];
/// thread_rng().fill_bytes(&mut buffer);
/// println!("Plaintext: {}", hex::encode(&buffer));
///
/// // Encrypt the data in-place
/// let (mut context_enc, nonce) = SlunkCrypt::init_encrypt(&PASSPHRASE, None).unwrap();
/// context_enc.inplace(&mut buffer).unwrap();
/// mem::drop(context_enc);
/// println!("Encrypted: {}", hex::encode(&buffer));
///
/// // Decrypt the data in-place
/// let mut context_dec = SlunkCrypt::init_decrypt(&PASSPHRASE, nonce, None).unwrap();
/// context_dec.inplace(&mut buffer).unwrap();
/// mem::drop(context_dec);
/// println!("Decrypted: {}", hex::encode(&buffer));
/// }
/// ```
#[derive(Debug)]
pub struct SlunkCrypt {
context: slunkcrypt_t
}
impl SlunkCrypt {
/// Create a new SlunkCrypt context and initialize it for the specified mode with the given password and the given nonce.
///
/// If successful, returns the new context; otherwise returns an [error code](SlunkCryptError).
fn new(passwd: &SlunkCryptPasswd, nonce: u64, mode: i32, threads: Option<NonZeroUsize>) -> Result<Self, SlunkCryptError> {
if passwd.len() < libslunkcrypt::SLUNKCRYPT_PWDLEN_MIN {
return Err(SlunkCryptError::new(SlunkCryptErrorKind::Invalid, "Passphrase is too short!"));
}
if passwd.len() > libslunkcrypt::SLUNKCRYPT_PWDLEN_MAX {
return Err(SlunkCryptError::new(SlunkCryptErrorKind::Invalid, "Passphrase is too long!"));
}
let param = slunkparam_t {
version: libslunkcrypt::SLUNKCRYPT_PARAM_VERSION,
thread_count: threads.map_or(usize::default(), NonZeroUsize::get),
legacy_compat: i32::default(),
debug_logging: i32::default()
};
let context: slunkcrypt_t = unsafe {
libslunkcrypt::slunkcrypt_alloc_ext(nonce, passwd.as_bytes().as_ptr() as *const u8, passwd.len(), mode, &param)
};
if context == SLUNKCRYPT_NULL {
Err(SlunkCryptError::new(SlunkCryptErrorKind::Failure, "failed to allocate slunkcrypt encryption context!"))
} else {
Ok(Self { context })
}
}
/// Create a new SlunkCrypt context and initialize it for *encryption* mode with the given password and a fresh random nonce.
///
/// If successful, returns the new context and the generated nonce; otherwise returns an [error code](SlunkCryptError).
pub fn init_encrypt(passwd: &SlunkCryptPasswd, threads: Option<NonZeroUsize>) -> Result<(Self, u64), SlunkCryptError> {
let nonce = generate_nonce()?;
match Self::new(passwd, nonce, libslunkcrypt::SLUNKCRYPT_ENCRYPT, threads) {
Ok(context) => Ok((context, nonce)),
Err(error) => Err(error)
}
}
/// Create a new SlunkCrypt context and initialize it for *decryption* mode with the given password and the given nonce.
///
/// If successful, returns the new context; otherwise returns an [error code](SlunkCryptError).
pub fn init_decrypt(passwd: &SlunkCryptPasswd, nonce: u64, threads: Option<NonZeroUsize>) -> Result<Self, SlunkCryptError> {
Self::new(passwd, nonce, libslunkcrypt::SLUNKCRYPT_DECRYPT, threads)
}
pub fn reset_encrypt(&mut self, passwd: &SlunkCryptPasswd) -> Result<u64, SlunkCryptError> {
if passwd.len() < libslunkcrypt::SLUNKCRYPT_PWDLEN_MIN {
return Err(SlunkCryptError::new(SlunkCryptErrorKind::Invalid, "Passphrase is too short!"));
}
if passwd.len() > libslunkcrypt::SLUNKCRYPT_PWDLEN_MAX {
return Err(SlunkCryptError::new(SlunkCryptErrorKind::Invalid, "Passphrase is too long!"));
}
let nonce = generate_nonce()?;
let retval = unsafe {
libslunkcrypt::slunkcrypt_reset(self.context, nonce, passwd.as_bytes().as_ptr(), passwd.len(), libslunkcrypt::SLUNKCRYPT_ENCRYPT)
};
match retval {
SLUNKCRYPT_SUCCESS => Ok(nonce),
_ => Err(SlunkCryptError::from_retval(retval, "failed to reset encryption context!"))
}
}
pub fn reset_decrypt(&mut self, passwd: &SlunkCryptPasswd, nonce: u64) -> Result<(), SlunkCryptError> {
if passwd.len() < libslunkcrypt::SLUNKCRYPT_PWDLEN_MIN {
return Err(SlunkCryptError::new(SlunkCryptErrorKind::Invalid, "Passphrase is too short!"));
}
if passwd.len() > libslunkcrypt::SLUNKCRYPT_PWDLEN_MAX {
return Err(SlunkCryptError::new(SlunkCryptErrorKind::Invalid, "Passphrase is too long!"));
}
let retval = unsafe {
libslunkcrypt::slunkcrypt_reset(self.context, nonce, passwd.as_bytes().as_ptr(), passwd.len(), libslunkcrypt::SLUNKCRYPT_DECRYPT)
};
match retval {
SLUNKCRYPT_SUCCESS => Ok(()),
_ => Err(SlunkCryptError::from_retval(retval, "failed to reset decryption context!"))
}
}
/// Process the next chunk of data. The given input data is encrypted or decrypted into the output buffer.
///
/// Does **not** modify the data in the input buffer.
///
/// If successful, returns nothing; otherwise returns an [error code](SlunkCryptError).
pub fn process(&mut self, data_in: &[u8], data_out: &mut[u8]) -> Result<(), SlunkCryptError> {
if data_out.len() < data_in.len() {
return Err(SlunkCryptError::new(SlunkCryptErrorKind::Invalid, "The output buffer is too small!"));
}
let retval = unsafe {
libslunkcrypt::slunkcrypt_process(self.context, data_in.as_ptr(), data_out.as_mut_ptr(), data_in.len())
};
match retval {
SLUNKCRYPT_SUCCESS => Ok(()),
_ => Err(SlunkCryptError::from_retval(retval, "failed to process data!"))
}
}
/// Process the next chunk of data. The given data is encrypted or decrypted *in-place*.
///
/// If successful, returns nothing; otherwise returns an [error code](SlunkCryptError).
pub fn inplace(&mut self, data: &mut[u8]) -> Result<(), SlunkCryptError> {
let retval = unsafe {
libslunkcrypt::slunkcrypt_inplace(self.context, data.as_mut_ptr(), data.len())
};
match retval {
SLUNKCRYPT_SUCCESS => Ok(()),
_ => Err(SlunkCryptError::from_retval(retval, "failed to process data!"))
}
}
}
impl Drop for SlunkCrypt {
/// Free the SlunkCrypt context and release all of its associated ressources.
fn drop(&mut self) {
if self.context != SLUNKCRYPT_NULL {
unsafe {
libslunkcrypt::slunkcrypt_free(self.context);
}
let x : *const std::ffi::c_void = ptr::null();
self.context = x as slunkcrypt_t;
}
}
}

61
binding/rust/src/error.rs Normal file
View File

@ -0,0 +1,61 @@
/******************************************************************************/
/* SlunkCrypt, by LoRd_MuldeR <MuldeR2@GMX.de> */
/* This work has been released under the CC0 1.0 Universal license! */
/******************************************************************************/
use std::os::raw::c_int;
use crate::ffi::libslunkcrypt::{SLUNKCRYPT_ABORTED, SLUNKCRYPT_FAILURE, SLUNKCRYPT_SUCCESS};
/// SlunkCrypt error type.
///
/// This struct provides information about the SlunkCrypt error that has occurred.
#[derive(Debug)]
pub struct SlunkCryptError {
kind: SlunkCryptErrorKind,
description: &'static str
}
/// SlunkCrypt error kind enumeration.
///
/// This enumeration defines the *kind* of the SlunkCrypt error that has occurred.
#[derive(Clone, Copy, Debug)]
pub enum SlunkCryptErrorKind {
/// The operation succeeded.
Success,
/// The operation was **not** executed because of invalid arguments.
Invalid,
/// The operation has failed.
Failure,
/// The operation was aborted by the user.
Aborted,
/// Unknown error. This is **not** supposed to happen.
Unknown
}
impl SlunkCryptError {
/// Creates a new error from the given kind and description.
pub(crate) fn new(kind: SlunkCryptErrorKind, description: &'static str) -> Self {
Self { kind, description }
}
/// Creates a new error from the given error code and description.
pub(crate) fn from_retval(retval: c_int, description: &'static str) -> Self {
let kind = match retval {
SLUNKCRYPT_SUCCESS => SlunkCryptErrorKind::Success,
SLUNKCRYPT_ABORTED => SlunkCryptErrorKind::Aborted,
SLUNKCRYPT_FAILURE => SlunkCryptErrorKind::Failure,
_ => SlunkCryptErrorKind::Unknown
};
Self::new(kind, description)
}
/// Returns the [*kind*](SlunkCryptErrorKind) of the SlunkCrypt error that has occurred.
pub fn kind(&self) -> SlunkCryptErrorKind {
self.kind
}
/// Returns a detailed textual description of the SlunkCrypt error that has occurred.
pub fn description(&self) -> &'static str {
&self.description
}
}

View File

@ -0,0 +1,50 @@
/******************************************************************************/
/* SlunkCrypt, by LoRd_MuldeR <MuldeR2@GMX.de> */
/* This work has been released under the CC0 1.0 Universal license! */
/******************************************************************************/
pub type slunkcrypt_t = usize;
const NULL_POINTER: *const ::std::ffi::c_void = ::std::ptr::null();
pub const SLUNKCRYPT_NULL: slunkcrypt_t = unsafe { ::std::mem::transmute(NULL_POINTER) };
pub const SLUNKCRYPT_FALSE: ::std::os::raw::c_int = 0;
pub const SLUNKCRYPT_TRUE: ::std::os::raw::c_int = 1;
pub const SLUNKCRYPT_ENCRYPT: ::std::os::raw::c_int = 0;
pub const SLUNKCRYPT_DECRYPT: ::std::os::raw::c_int = 1;
pub const SLUNKCRYPT_SUCCESS: ::std::os::raw::c_int = 0;
pub const SLUNKCRYPT_FAILURE: ::std::os::raw::c_int = -1;
pub const SLUNKCRYPT_ABORTED: ::std::os::raw::c_int = -2;
pub const SLUNKCRYPT_PWDLEN_MIN: usize = 8;
pub const SLUNKCRYPT_PWDLEN_MAX: usize = 256;
pub const SLUNKCRYPT_PARAM_VERSION: u16 = 2;
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct slunkparam_t {
pub version: u16,
pub thread_count: usize,
pub legacy_compat: ::std::os::raw::c_int,
pub debug_logging: ::std::os::raw::c_int,
}
extern "C" {
pub static SLUNKCRYPT_VERSION_MAJOR: u16;
pub static SLUNKCRYPT_VERSION_MINOR: u16;
pub static SLUNKCRYPT_VERSION_PATCH: u16;
pub static SLUNKCRYPT_BUILD: *const ::std::os::raw::c_char;
pub static SLUNKCRYPT_HAVE_THREADS: ::std::os::raw::c_int;
pub static mut g_slunkcrypt_abort_flag: ::std::os::raw::c_int;
pub fn slunkcrypt_generate_nonce(nonce: *mut u64) -> ::std::os::raw::c_int;
pub fn slunkcrypt_alloc_ext(nonce: u64, passwd: *const u8, passwd_len: usize, mode: ::std::os::raw::c_int, param: *const slunkparam_t) -> slunkcrypt_t;
pub fn slunkcrypt_reset(context: slunkcrypt_t, nonce: u64, passwd: *const u8, passwd_len: usize, mode: ::std::os::raw::c_int) -> ::std::os::raw::c_int;
pub fn slunkcrypt_free(context: slunkcrypt_t);
pub fn slunkcrypt_process(context: slunkcrypt_t, input: *const u8, output: *mut u8, length: usize) -> ::std::os::raw::c_int;
pub fn slunkcrypt_inplace(context: slunkcrypt_t, buffer: *mut u8, length: usize) -> ::std::os::raw::c_int;
pub fn slunkcrypt_random_bytes(buffer: *mut u8, length: usize) -> usize;
pub fn slunkcrypt_bzero(buffer: *mut ::std::os::raw::c_void, length: usize);
}

View File

@ -0,0 +1,13 @@
/******************************************************************************/
/* SlunkCrypt, by LoRd_MuldeR <MuldeR2@GMX.de> */
/* This work has been released under the CC0 1.0 Universal license! */
/******************************************************************************/
#![allow(dead_code)]
#![allow(unused)]
#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
pub mod libslunkcrypt;

View File

@ -0,0 +1,38 @@
/******************************************************************************/
/* SlunkCrypt, by LoRd_MuldeR <MuldeR2@GMX.de> */
/* This work has been released under the CC0 1.0 Universal license! */
/******************************************************************************/
use std::ffi::CStr;
use std::str;
use crate::error::SlunkCryptError;
use crate::ffi::libslunkcrypt::{self, SLUNKCRYPT_SUCCESS};
/// Generate a fresh random nonce, using a Cryptographically secure pseudorandom number generator.
pub fn generate_nonce() -> Result<u64, SlunkCryptError> {
let mut nonce: u64 = u64::default();
let retval = unsafe {
libslunkcrypt::slunkcrypt_generate_nonce(&mut nonce)
};
match retval {
SLUNKCRYPT_SUCCESS => Ok(nonce),
_ => Err(SlunkCryptError::from_retval(retval, "failed to generate nonce!"))
}
}
/// Returns the version of the native SlunkCrypt library.
pub fn get_version() -> (u16,u16,u16) {
unsafe {(
libslunkcrypt::SLUNKCRYPT_VERSION_MAJOR,
libslunkcrypt::SLUNKCRYPT_VERSION_MINOR,
libslunkcrypt::SLUNKCRYPT_VERSION_PATCH
)}
}
// Returns the version of the native SlunkCrypt library.
pub fn get_build() -> &'static str {
unsafe {
CStr::from_ptr(libslunkcrypt::SLUNKCRYPT_BUILD).to_str().unwrap()
}
}

43
binding/rust/src/lib.rs Normal file
View File

@ -0,0 +1,43 @@
/******************************************************************************/
/* SlunkCrypt, by LoRd_MuldeR <MuldeR2@GMX.de> */
/* This work has been released under the CC0 1.0 Universal license! */
/******************************************************************************/
//! # SlunkCrypt Rust Wrapper
//! This crate exposes the functionality of the [**SlunkCrypt**](https://gitlab.com/lord_mulder/slunkcrypt) library to to Rust developers.
//!
//! Please see the [`SlunkCrypt`] struct for details!
//!
//! ## Build Instructions
//!
//! First the "native" SlunkCrypt library needs to be built, if not done yet:
//! ```sh
//! $ cd /home/JohnnyBeSlunk/dev/SlunkCrypt
//! $ make -B SHARED=1
//! ```
//!
//! Now build the SlunkCrypt Rust wrapper crate:
//! ```sh
//! $ cd binding/rust
//! $ cargo build --release
//! ```
//!
//! ## Unit Tests
//!
//! In order to run the unit tests, please type:
//!
//! ```sh
//! $ export LD_LIBRARY_PATH=/home/JohnnyBeSlunk/dev/SlunkCryptlibslunkcrypt/lib
//! $cargo test --release
//! ```
mod context;
mod error;
mod ffi;
mod functions;
mod passwd;
pub use context::SlunkCrypt;
pub use error::{SlunkCryptError, SlunkCryptErrorKind};
pub use functions::{generate_nonce, get_version, get_build};
pub use passwd::SlunkCryptPasswd;

View File

@ -0,0 +1,36 @@
/******************************************************************************/
/* SlunkCrypt, by LoRd_MuldeR <MuldeR2@GMX.de> */
/* This work has been released under the CC0 1.0 Universal license! */
/******************************************************************************/
/// Passphrase to be used with [SlunkCrypt](crate::SlunkCrypt) encryption or decryption.
pub enum SlunkCryptPasswd<'a> {
/// A passphrase constructed from a `&str`
Str(&'a str),
/// A passphrase constructed from a `String`
String(String),
/// A passphrase constructed from `&[u8]`
Bytes(&'a[u8]),
/// A passphrase constructed from `Vec<u8>`
Vec(Vec<u8>)
}
impl<'a> SlunkCryptPasswd<'a> {
pub fn len(&self) -> usize {
match self {
Self::Str(str) => str.len(),
Self::String(str) => str.len(),
Self::Bytes(bin) => bin.len(),
Self::Vec(bin) => bin.len()
}
}
pub fn as_bytes(&'a self) -> &'a[u8] {
match self {
Self::Str(str) => str.as_bytes(),
Self::String(str) => str.as_bytes(),
Self::Bytes(bin) => bin,
Self::Vec(bin) => bin.as_slice()
}
}
}

View File

@ -0,0 +1,188 @@
/******************************************************************************/
/* SlunkCrypt, by LoRd_MuldeR <MuldeR2@GMX.de> */
/* This work has been released under the CC0 1.0 Universal license! */
/******************************************************************************/
use slunkcrypt_rs::{SlunkCryptPasswd, SlunkCrypt};
use hex;
use memx;
use rand::{rngs::OsRng, RngCore};
use std::{env, mem, cmp::Ordering};
const DEFAULT_TEST_LOOPS: usize = 8;
const PASSPHRASE: SlunkCryptPasswd = SlunkCryptPasswd::Str("eUGAwxOm0QwiVnDx");
const PASSPHRASE_BAD: SlunkCryptPasswd = SlunkCryptPasswd::Str("eUGAwxOm1QwiVnDx");
#[test]
fn test_create_instance() {
run_test(|| {
let (context, nonce) = SlunkCrypt::init_encrypt(&PASSPHRASE, None).expect("Failed to create encryption context!");
println!("EncryptContext: {:?}", context);
let context = SlunkCrypt::init_decrypt(&PASSPHRASE, nonce, None).expect("Failed to create decryption context!");
println!("DecryptContext: {:?}", context);
});
}
#[test]
fn test_process() {
run_test(|| {
let (mut orig, mut encr, mut decr) = ([ 0u8; 5003 ], [ 0u8; 5003 ], [ 0u8; 5003 ]);
OsRng.fill_bytes(&mut orig);
println!("Plaintext: {}", hex::encode(&orig));
let (mut context_enc, nonce) = SlunkCrypt::init_encrypt(&PASSPHRASE, None).expect("Failed to create encryption context!");
context_enc.process(&orig, &mut encr).expect("Failed to encrypt data!");
mem::drop(context_enc);
println!("Encrypted: {}", hex::encode(&encr));
assert!(memx::memcmp(&orig, &encr) != Ordering::Equal);
let mut context_dec = SlunkCrypt::init_decrypt(&PASSPHRASE, nonce, None).expect("Failed to create decryption context!");
context_dec.process(&encr, &mut decr).expect("Failed to encrypt data!");
mem::drop(context_dec);
println!("Decrypted: {}", hex::encode(&decr));
});
}
#[test]
fn test_inplace() {
run_test(|| {
let (mut data, mut orig) = ([ 0u8; 5003 ], [ 0u8; 5003 ]);
OsRng.fill_bytes(&mut data);
memx::memcpy(&mut orig, &data).expect("Failed to copy original data!");
println!("Plaintext: {}", hex::encode(&data));
assert!(memx::memcmp(&data, &orig) == Ordering::Equal);
let (mut context_enc, nonce) = SlunkCrypt::init_encrypt(&PASSPHRASE, None).expect("Failed to create encryption context!");
context_enc.inplace(&mut data).expect("Failed to encrypt data!");
mem::drop(context_enc);
println!("Encrypted: {}", hex::encode(&data));
assert!(memx::memcmp(&data, &orig) != Ordering::Equal);
let mut context_dec = SlunkCrypt::init_decrypt(&PASSPHRASE, nonce, None).expect("Failed to create decryption context!");
context_dec.inplace(&mut data).expect("Failed to decrypt data!");
mem::drop(context_dec);
println!("Decrypted: {}", hex::encode(&data));
assert!(memx::memcmp(&data, &orig) == Ordering::Equal);
});
}
#[test]
fn test_reset() {
run_test(|| {
let (mut data, mut orig) = ([ 0u8; 5003 ], [ 0u8; 5003 ]);
OsRng.fill_bytes(&mut data);
memx::memcpy(&mut orig, &data).expect("Failed to copy original data!");
println!("Plaintext: {}", hex::encode(&data));
assert!(memx::memcmp(&data, &orig) == Ordering::Equal);
let (mut context, _nonce) = SlunkCrypt::init_encrypt(&PASSPHRASE, None).expect("Failed to create encryption context!");
context.inplace(&mut data).expect("Failed to encrypt data!");
println!("Encrypted: {}", hex::encode(&data));
assert!(memx::memcmp(&data, &orig) != Ordering::Equal);
memx::memcpy(&mut data, &orig).expect("Failed to copy original data!");
println!("Plaintext: {}", hex::encode(&data));
assert!(memx::memcmp(&data, &orig) == Ordering::Equal);
let nonce = context.reset_encrypt(&PASSPHRASE).expect("Failed to reset encryption context!");
context.inplace(&mut data).expect("Failed to encrypt data!");
println!("Encrypted: {}", hex::encode(&data));
assert!(memx::memcmp(&data, &orig) != Ordering::Equal);
context.reset_decrypt(&PASSPHRASE, nonce).expect("Failed to reset decryption context!");
context.inplace(&mut data).expect("Failed to decrypt data!");
mem::drop(context);
println!("Decrypted: {}", hex::encode(&data));
assert!(memx::memcmp(&data, &orig) == Ordering::Equal);
});
}
#[test]
fn test_fail_bad_nonce() {
run_test(|| {
let (mut data, mut orig) = ([ 0u8; 5003 ], [ 0u8; 5003 ]);
OsRng.fill_bytes(&mut data);
memx::memcpy(&mut orig, &data).expect("Failed to copy original data!");
println!("Plaintext: {}", hex::encode(&data));
assert!(memx::memcmp(&data, &orig) == Ordering::Equal);
let (mut context_enc, nonce) = SlunkCrypt::init_encrypt(&PASSPHRASE, None).expect("Failed to create encryption context!");
context_enc.inplace(&mut data).expect("Failed to encrypt data!");
mem::drop(context_enc);
println!("Encrypted: {}", hex::encode(&data));
assert!(memx::memcmp(&data, &orig) != Ordering::Equal);
let mut context_dec = SlunkCrypt::init_decrypt(&PASSPHRASE, nonce + 1, None).expect("Failed to create decryption context!");
context_dec.inplace(&mut data).expect("Failed to decrypt data!");
mem::drop(context_dec);
println!("Decrypted: {}", hex::encode(&data));
assert!(memx::memcmp(&data, &orig) != Ordering::Equal);
});
}
#[test]
fn test_fail_bad_passwd() {
run_test(|| {
let (mut data, mut orig) = ([ 0u8; 5003 ], [ 0u8; 5003 ]);
OsRng.fill_bytes(&mut data);
memx::memcpy(&mut orig, &data).expect("Failed to copy original data!");
println!("Plaintext: {}", hex::encode(&data));
assert!(memx::memcmp(&data, &orig) == Ordering::Equal);
let (mut context_enc, nonce) = SlunkCrypt::init_encrypt(&PASSPHRASE, None).expect("Failed to create encryption context!");
context_enc.inplace(&mut data).expect("Failed to encrypt data!");
mem::drop(context_enc);
println!("Encrypted: {}", hex::encode(&data));
assert!(memx::memcmp(&data, &orig) != Ordering::Equal);
let mut context_dec = SlunkCrypt::init_decrypt(&PASSPHRASE_BAD, nonce, None).expect("Failed to create decryption context!");
context_dec.inplace(&mut data).expect("Failed to decrypt data!");
mem::drop(context_dec);
println!("Decrypted: {}", hex::encode(&data));
assert!(memx::memcmp(&data, &orig) != Ordering::Equal);
});
}
#[test]
fn test_stress() {
let (mut data, mut orig) = ([ 0u8; u16::MAX as usize ], [ 0u8; u16::MAX as usize ]);
let (mut context_enc, nonce) = SlunkCrypt::init_encrypt(&PASSPHRASE, None).expect("Failed to create encryption context!");
let mut context_dec = SlunkCrypt::init_decrypt(&PASSPHRASE, nonce, None).expect("Failed to create decryption context!");
for i in 0..u16::MAX {
OsRng.fill_bytes(&mut data);
memx::memcpy(&mut orig, &data).expect("Failed to copy original data!");
context_enc.inplace(&mut data).expect("Failed to encrypt data!");
assert!(memx::memcmp(&data, &orig) != Ordering::Equal);
context_dec.inplace(&mut data).expect("Failed to decrypt data!");
assert!(memx::memcmp(&data, &orig) == Ordering::Equal);
if i % 499 == 0 {
println!("{:.1}%", (i as f64 / u16::MAX as f64) * 100.0)
}
}
}
fn run_test<F>(func: F) where F: Fn() {
let loops = env::var("TEST_LOOPS").map_or(DEFAULT_TEST_LOOPS, |value| value.parse::<usize>().unwrap());
for _ in 0..loops {
func();
}
}

View File

@ -0,0 +1,37 @@
/******************************************************************************/
/* SlunkCrypt, by LoRd_MuldeR <MuldeR2@GMX.de> */
/* This work has been released under the CC0 1.0 Universal license! */
/******************************************************************************/
use std::env;
use slunkcrypt_rs::{get_version, get_build, generate_nonce};
const DEFAULT_TEST_LOOPS: usize = 8;
#[test]
fn test_get_version() {
let (major, minor, patch) = get_version();
assert!(major > 0);
println!("Version: {}.{}.{}", major, minor, patch);
}
#[test]
fn test_get_build() {
let build = get_build();
println!("Build: \"{}\"", build);
}
#[test]
fn test_init_generate_nonce() {
run_test(|| {
let nonce = generate_nonce().expect("Failed to generate nonce!");
println!("Nonce: {:16X}", nonce);
});
}
fn run_test<F>(func: F) where F: Fn() {
let loops = env::var("TEST_LOOPS").map_or(DEFAULT_TEST_LOOPS, |value| value.parse::<usize>().unwrap());
for _ in 0..loops {
func();
}
}