use cosmian_ffi_utils::{ffi_read_bytes, ffi_read_string, ffi_unwrap, ffi_write_bytes, ErrorCode};
use num_bigint::BigUint;
use num_traits::Num;
use crate::core::{Integer, KEY_LENGTH};
unsafe extern "C" fn fpe(
output: *mut u64,
input: u64,
radix: u32,
digits: u32,
key_ptr: *const i8,
key_len: i32,
tweak_ptr: *const i8,
tweak_len: i32,
encrypt_flag: bool,
) -> i32 {
let key_bytes = ffi_read_bytes!("key", key_ptr, key_len);
let tweak_bytes = ffi_read_bytes!("tweak", tweak_ptr, tweak_len);
let key: [u8; KEY_LENGTH] = ffi_unwrap!(
key_bytes.try_into(),
"key size is 32 bytes",
ErrorCode::Serialization
);
let itg = ffi_unwrap!(
Integer::instantiate(radix, digits as usize),
"cannot instantiate FPE integer",
ErrorCode::Fpe
);
*output = if encrypt_flag {
ffi_unwrap!(
itg.encrypt(&key, tweak_bytes, input),
"fpe encryption process",
ErrorCode::Encryption
)
} else {
ffi_unwrap!(
itg.decrypt(&key, tweak_bytes, input),
"fpe decryption process",
ErrorCode::Decryption
)
};
0
}
#[no_mangle]
pub unsafe extern "C" fn h_fpe_encrypt_integer(
output: *mut u64,
input: u64,
radix: u32,
digits: u32,
key_ptr: *const i8,
key_len: i32,
tweak_ptr: *const i8,
tweak_len: i32,
) -> i32 {
fpe(
output, input, radix, digits, key_ptr, key_len, tweak_ptr, tweak_len, true,
)
}
#[no_mangle]
pub unsafe extern "C" fn h_fpe_decrypt_integer(
output: *mut u64,
input: u64,
radix: u32,
digits: u32,
key_ptr: *const i8,
key_len: i32,
tweak_ptr: *const i8,
tweak_len: i32,
) -> i32 {
fpe(
output, input, radix, digits, key_ptr, key_len, tweak_ptr, tweak_len, false,
)
}
unsafe extern "C" fn fpe_big_integer(
output_ptr: *mut u8,
output_len: *mut i32,
input_ptr: *const i8,
radix: u32,
digits: u32,
key_ptr: *const i8,
key_len: i32,
tweak_ptr: *const i8,
tweak_len: i32,
encrypt_flag: bool,
) -> i32 {
let key_bytes = ffi_read_bytes!("key", key_ptr, key_len);
let tweak_bytes = ffi_read_bytes!("tweak", tweak_ptr, tweak_len);
let input_str = ffi_read_string!("input", input_ptr);
let itg = ffi_unwrap!(
Integer::instantiate(radix, digits as usize),
"cannot instantiate FPE integer",
ErrorCode::Fpe
);
let input_biguint = ffi_unwrap!(
BigUint::from_str_radix(&input_str, radix),
"failed to convert input to BigUint",
ErrorCode::Serialization
);
let key: [u8; KEY_LENGTH] = ffi_unwrap!(
key_bytes.try_into(),
"key size is 32 bytes",
ErrorCode::Serialization
);
let output = if encrypt_flag {
ffi_unwrap!(
itg.encrypt_big(&key, tweak_bytes, &input_biguint),
"fpe encryption process",
ErrorCode::Encryption
)
} else {
ffi_unwrap!(
itg.decrypt_big(&key, tweak_bytes, &input_biguint),
"fpe decryption process",
ErrorCode::Decryption
)
};
let output_str = output.to_str_radix(radix);
ffi_write_bytes!("output_ptr", output_str.as_bytes(), output_ptr, output_len);
}
#[no_mangle]
pub unsafe extern "C" fn h_fpe_encrypt_big_integer(
output_ptr: *mut u8,
output_len: *mut i32,
input_ptr: *const i8,
radix: u32,
digits: u32,
key_ptr: *const i8,
key_len: i32,
tweak_ptr: *const i8,
tweak_len: i32,
) -> i32 {
fpe_big_integer(
output_ptr, output_len, input_ptr, radix, digits, key_ptr, key_len, tweak_ptr, tweak_len,
true,
)
}
#[no_mangle]
pub unsafe extern "C" fn h_fpe_decrypt_big_integer(
output_ptr: *mut u8,
output_len: *mut i32,
input_ptr: *const i8,
radix: u32,
digits: u32,
key_ptr: *const i8,
key_len: i32,
tweak_ptr: *const i8,
tweak_len: i32,
) -> i32 {
fpe_big_integer(
output_ptr, output_len, input_ptr, radix, digits, key_ptr, key_len, tweak_ptr, tweak_len,
false,
)
}