use std::process::abort;
use libc::c_char;
use libc::c_int;
use libc::size_t;
use libc::uint8_t;
use smartlist::Stringlist;
pub const DIGEST_LEN: usize = 20;
pub const DIGEST256_LEN: usize = 32;
pub const DIGEST512_LEN: usize = 64;
pub const BASE32_DIGEST_LEN: usize = 32;
pub const BASE64_DIGEST_LEN: usize = 27;
pub const BASE64_DIGEST256_LEN: usize = 43;
pub const BASE64_DIGEST512_LEN: usize = 86;
pub const HEX_DIGEST_LEN: usize = 40;
pub const HEX_DIGEST256_LEN: usize = 64;
pub const HEX_DIGEST512_LEN: usize = 128;
#[allow(non_camel_case_types)]
type digest_algorithm_t = u8;
const DIGEST_SHA1: digest_algorithm_t = 0;
const DIGEST_SHA256: digest_algorithm_t = 1;
const DIGEST_SHA512: digest_algorithm_t = 2;
const DIGEST_SHA3_256: digest_algorithm_t = 3;
const DIGEST_SHA3_512: digest_algorithm_t = 4;
const N_COMMON_DIGEST_ALGORITHMS: usize = DIGEST_SHA256 as usize + 1;
#[repr(C)]
#[derive(Debug, Copy, Clone)]
#[allow(non_camel_case_types)]
struct crypto_digest_t {
_unused: [u8; 0],
}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
#[allow(non_camel_case_types)]
struct crypto_xof_t {
_unused: [u8; 0],
}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
#[allow(non_camel_case_types)]
struct common_digests_t {
pub d: [[c_char; N_COMMON_DIGEST_ALGORITHMS]; DIGEST256_LEN],
}
#[allow(non_camel_case_types)]
#[allow(dead_code)]
type smartlist_t = Stringlist;
#[allow(dead_code)]
extern "C" {
fn crypto_digest(digest: *mut c_char, m: *const c_char, len: size_t) -> c_int;
fn crypto_digest256(
digest: *mut c_char,
m: *const c_char,
len: size_t,
algorithm: digest_algorithm_t,
) -> c_int;
fn crypto_digest512(
digest: *mut c_char,
m: *const c_char,
len: size_t,
algorithm: digest_algorithm_t,
) -> c_int;
fn crypto_common_digests(ds_out: *mut common_digests_t, m: *const c_char, len: size_t)
-> c_int;
fn crypto_digest_smartlist_prefix(
digest_out: *mut c_char,
len_out: size_t,
prepend: *const c_char,
lst: *const smartlist_t,
append: *const c_char,
alg: digest_algorithm_t,
);
fn crypto_digest_smartlist(
digest_out: *mut c_char,
len_out: size_t,
lst: *const smartlist_t,
append: *const c_char,
alg: digest_algorithm_t,
);
fn crypto_digest_algorithm_get_name(alg: digest_algorithm_t) -> *const c_char;
fn crypto_digest_algorithm_get_length(alg: digest_algorithm_t) -> size_t;
fn crypto_digest_algorithm_parse_name(name: *const c_char) -> c_int;
fn crypto_digest_new() -> *mut crypto_digest_t;
fn crypto_digest256_new(algorithm: digest_algorithm_t) -> *mut crypto_digest_t;
fn crypto_digest512_new(algorithm: digest_algorithm_t) -> *mut crypto_digest_t;
fn crypto_digest_free_(digest: *mut crypto_digest_t);
fn crypto_digest_add_bytes(digest: *mut crypto_digest_t, data: *const c_char, len: size_t);
fn crypto_digest_get_digest(digest: *mut crypto_digest_t, out: *mut c_char, out_len: size_t);
fn crypto_digest_dup(digest: *const crypto_digest_t) -> *mut crypto_digest_t;
fn crypto_digest_assign(into: *mut crypto_digest_t, from: *const crypto_digest_t);
fn crypto_hmac_sha256(
hmac_out: *mut c_char,
key: *const c_char,
key_len: size_t,
msg: *const c_char,
msg_len: size_t,
);
fn crypto_mac_sha3_256(
mac_out: *mut uint8_t,
len_out: size_t,
key: *const uint8_t,
key_len: size_t,
msg: *const uint8_t,
msg_len: size_t,
);
fn crypto_xof_new() -> *mut crypto_xof_t;
fn crypto_xof_add_bytes(xof: *mut crypto_xof_t, data: *const uint8_t, len: size_t);
fn crypto_xof_squeeze_bytes(xof: *mut crypto_xof_t, out: *mut uint8_t, len: size_t);
fn crypto_xof_free(xof: *mut crypto_xof_t);
}
pub enum DigestAlgorithm {
SHA2_256,
SHA2_512,
SHA3_256,
SHA3_512,
}
impl From<DigestAlgorithm> for digest_algorithm_t {
fn from(digest: DigestAlgorithm) -> digest_algorithm_t {
match digest {
DigestAlgorithm::SHA2_256 => DIGEST_SHA256,
DigestAlgorithm::SHA2_512 => DIGEST_SHA512,
DigestAlgorithm::SHA3_256 => DIGEST_SHA3_256,
DigestAlgorithm::SHA3_512 => DIGEST_SHA3_512,
}
}
}
pub struct CryptoDigest(*mut crypto_digest_t);
impl Clone for CryptoDigest {
fn clone(&self) -> CryptoDigest {
let digest: *mut crypto_digest_t;
unsafe {
digest = crypto_digest_dup(self.0 as *const crypto_digest_t);
}
if digest.is_null() {
abort();
}
CryptoDigest(digest)
}
}
impl CryptoDigest {
pub fn new(algorithm: Option<DigestAlgorithm>) -> CryptoDigest {
let digest: *mut crypto_digest_t;
if algorithm.is_none() {
unsafe {
digest = crypto_digest_new();
}
} else {
let algo: digest_algorithm_t = algorithm.unwrap().into();
unsafe {
digest = match algo {
DIGEST_SHA1 => crypto_digest_new(),
DIGEST_SHA256 => crypto_digest256_new(DIGEST_SHA256),
DIGEST_SHA3_256 => crypto_digest256_new(DIGEST_SHA3_256),
DIGEST_SHA512 => crypto_digest512_new(DIGEST_SHA512),
DIGEST_SHA3_512 => crypto_digest512_new(DIGEST_SHA3_512),
_ => abort(),
}
}
}
if digest.is_null() {
abort();
}
CryptoDigest(digest)
}
pub fn add_bytes(&self, bytes: &[u8]) {
unsafe {
crypto_digest_add_bytes(
self.0 as *mut crypto_digest_t,
bytes.as_ptr() as *const c_char,
bytes.len() as size_t,
)
}
}
}
impl Drop for CryptoDigest {
fn drop(&mut self) {
unsafe {
crypto_digest_free_(self.0 as *mut crypto_digest_t);
}
}
}
pub fn get_256_bit_digest(digest: CryptoDigest) -> [u8; DIGEST256_LEN] {
let mut buffer: [u8; DIGEST256_LEN] = [0u8; DIGEST256_LEN];
unsafe {
crypto_digest_get_digest(
digest.0,
buffer.as_mut_ptr() as *mut c_char,
DIGEST256_LEN as size_t,
);
if buffer.as_ptr().is_null() {
abort();
}
}
buffer
}
pub fn get_512_bit_digest(digest: CryptoDigest) -> [u8; DIGEST512_LEN] {
let mut buffer: [u8; DIGEST512_LEN] = [0u8; DIGEST512_LEN];
unsafe {
crypto_digest_get_digest(
digest.0,
buffer.as_mut_ptr() as *mut c_char,
DIGEST512_LEN as size_t,
);
if buffer.as_ptr().is_null() {
abort();
}
}
buffer
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_layout_common_digests_t() {
assert_eq!(
::std::mem::size_of::<common_digests_t>(),
64usize,
concat!("Size of: ", stringify!(common_digests_t))
);
assert_eq!(
::std::mem::align_of::<common_digests_t>(),
1usize,
concat!("Alignment of ", stringify!(common_digests_t))
);
}
#[test]
fn test_layout_crypto_digest_t() {
assert_eq!(
::std::mem::size_of::<crypto_digest_t>(),
0usize,
concat!("Size of: ", stringify!(crypto_digest_t))
);
assert_eq!(
::std::mem::align_of::<crypto_digest_t>(),
1usize,
concat!("Alignment of ", stringify!(crypto_digest_t))
);
}
}