use crypto::utils::secmem;
use libc::{
c_int,
c_uchar,
c_ulonglong,
size_t
};
use self::Family::*;
use SSError::{
self,
MAC
};
pub enum Family {
SHA256,
SHA512,
SHA512256,
}
pub const HMACSHA256_BYTES: usize = 32;
pub const HMACSHA256_KEYBYTES: usize = 32;
pub const HMACSHA512_BYTES: usize = 64;
pub const HMACSHA512_KEYBYTES: usize = 32;
pub const HMACSHA512256_BYTES: usize = 32;
pub const HMACSHA512256_KEYBYTES: usize = 32;
extern "C" {
fn crypto_auth_hmacsha256_statebytes() -> size_t;
fn crypto_auth_hmacsha512_statebytes() -> size_t;
fn crypto_auth_hmacsha512256_statebytes() -> size_t;
fn crypto_auth_hmacsha256_bytes() -> size_t;
fn crypto_auth_hmacsha512_bytes() -> size_t;
fn crypto_auth_hmacsha512256_bytes() -> size_t;
fn crypto_auth_hmacsha256_keybytes() -> size_t;
fn crypto_auth_hmacsha512_keybytes() -> size_t;
fn crypto_auth_hmacsha512256_keybytes() -> size_t;
fn crypto_auth_hmacsha256(
out: *mut c_uchar,
in_: *const c_uchar,
inlen: c_ulonglong,
k: *const c_uchar
)
-> c_int;
fn crypto_auth_hmacsha512(
out: *mut c_uchar,
in_: *const c_uchar,
inlen: c_ulonglong,
k: *const c_uchar
)
-> c_int;
fn crypto_auth_hmacsha512256(
out: *mut c_uchar,
in_: *const c_uchar,
inlen: c_ulonglong,
k: *const c_uchar
)
-> c_int;
fn crypto_auth_hmacsha256_verify(
h: *const c_uchar,
in_: *const c_uchar,
inlen: c_ulonglong,
k: *const c_uchar
)
-> c_int;
fn crypto_auth_hmacsha512_verify(
h: *const c_uchar,
in_: *const c_uchar,
inlen: c_ulonglong,
k: *const c_uchar
)
-> c_int;
fn crypto_auth_hmacsha512256_verify(
h: *const c_uchar,
in_: *const c_uchar,
inlen: c_ulonglong,
k: *const c_uchar
)
-> c_int;
fn crypto_auth_hmacsha256_init(
state: *mut c_uchar,
key: *const c_uchar,
keylen: size_t
)
-> c_int;
fn crypto_auth_hmacsha512_init(
state: *mut c_uchar,
key: *const c_uchar,
keylen: size_t
)
-> c_int;
fn crypto_auth_hmacsha512256_init(
state: *mut c_uchar,
key: *const c_uchar,
keylen: size_t
)
-> c_int;
fn crypto_auth_hmacsha256_update(
state: *mut c_uchar,
in_: *const c_uchar,
inlen: c_ulonglong
)
-> c_int;
fn crypto_auth_hmacsha512_update(
state: *mut c_uchar,
in_: *const c_uchar,
inlen: c_ulonglong
)
-> c_int;
fn crypto_auth_hmacsha512256_update(
state: *mut c_uchar,
in_: *const c_uchar,
inlen: c_ulonglong
)
-> c_int;
fn crypto_auth_hmacsha256_final(
state: *mut c_uchar,
out: *mut c_uchar
)
-> c_int;
fn crypto_auth_hmacsha512_final(
state: *mut c_uchar,
out: *mut c_uchar
)
-> c_int;
fn crypto_auth_hmacsha512256_final(
state: *mut c_uchar,
out: *mut c_uchar
)
-> c_int;
}
pub fn bytes(family: Family) -> usize {
unsafe {
match family {
SHA256 => crypto_auth_hmacsha256_bytes() as usize,
SHA512 => crypto_auth_hmacsha512_bytes() as usize,
SHA512256 => crypto_auth_hmacsha512256_bytes() as usize,
}
}
}
pub fn keybytes(family: Family) -> usize {
unsafe {
match family {
SHA256 => crypto_auth_hmacsha256_keybytes() as usize,
SHA512 => crypto_auth_hmacsha512_keybytes() as usize,
SHA512256 => crypto_auth_hmacsha512256_keybytes() as usize,
}
}
}
pub fn statebytes(family: Family) -> usize {
unsafe {
match family {
SHA256 => crypto_auth_hmacsha256_statebytes() as usize,
SHA512 => crypto_auth_hmacsha512_statebytes() as usize,
SHA512256 => crypto_auth_hmacsha512256_statebytes() as usize,
}
}
}
pub fn auth<'a>(
message: &[u8],
key: &[u8],
family: Family
)
-> Result<&'a mut[u8], SSError>
{
let (res, output) = match family {
SHA256 => {
assert!(key.len() == HMACSHA256_KEYBYTES);
let mut output = secmem::malloc(HMACSHA256_BYTES);
let res: i32;
unsafe {
res = crypto_auth_hmacsha256(
output.as_mut_ptr(),
message.as_ptr(),
message.len() as c_ulonglong,
key.as_ptr()
);
}
(res, output)
},
SHA512 => {
assert!(key.len() == HMACSHA512_KEYBYTES);
let mut output = secmem::malloc(HMACSHA512_BYTES);
let res: i32;
unsafe {
res = crypto_auth_hmacsha512(
output.as_mut_ptr(),
message.as_ptr(),
message.len() as c_ulonglong,
key.as_ptr()
);
}
(res, output)
},
SHA512256 => {
assert!(key.len() == HMACSHA512256_KEYBYTES);
let mut output = secmem::malloc(HMACSHA512256_BYTES);
let res: i32;
unsafe {
res = crypto_auth_hmacsha512256(
output.as_mut_ptr(),
message.as_ptr(),
message.len() as c_ulonglong,
key.as_ptr()
);
}
(res, output)
},
};
if res == 0 {
secmem::mprotect_readonly(output);
Ok(output)
} else {
Err(MAC("Unable to generate MAC"))
}
}
pub fn verify<'a>(
message: &[u8],
mac: &[u8],
key: &[u8],
family: Family
)
-> Result<i32, SSError>
{
let res = match family {
SHA256 => {
assert!(key.len() == HMACSHA256_KEYBYTES);
assert!(mac.len() == HMACSHA256_BYTES);
unsafe {
crypto_auth_hmacsha256_verify(
mac.as_ptr(),
message.as_ptr(),
message.len() as c_ulonglong,
key.as_ptr()
) as i32
}
},
SHA512 => {
assert!(key.len() == HMACSHA512_KEYBYTES);
assert!(mac.len() == HMACSHA512_BYTES);
unsafe {
crypto_auth_hmacsha512_verify(
mac.as_ptr(),
message.as_ptr(),
message.len() as c_ulonglong,
key.as_ptr()
) as i32
}
},
SHA512256 => {
assert!(key.len() == HMACSHA512256_KEYBYTES);
assert!(mac.len() == HMACSHA512256_BYTES);
unsafe {
crypto_auth_hmacsha512256_verify(
mac.as_ptr(),
message.as_ptr(),
message.len() as c_ulonglong,
key.as_ptr()
) as i32
}
},
};
if res == 0 {
Ok(res)
} else {
Err(MAC("Unable to generate MAC"))
}
}
pub fn init<'a>
(
state: &'a mut [u8],
key: &'a [u8],
family: Family
)
-> Result<(), SSError>
{
let res: i32;
unsafe {
res = match family {
SHA256 => crypto_auth_hmacsha256_init(
state.as_mut_ptr(),
key.as_ptr(),
key.len() as size_t
),
SHA512 => crypto_auth_hmacsha512_init(
state.as_mut_ptr(),
key.as_ptr(),
key.len() as size_t
),
SHA512256 => crypto_auth_hmacsha512256_init(
state.as_mut_ptr(),
key.as_ptr(),
key.len() as size_t
),
};
}
if res == 0 {
Ok(())
} else {
Err(MAC("Unable to initialize hash state"))
}
}
pub fn update<'a>(
state: &'a mut [u8],
in_: &[u8],
family: Family
)
-> Result<(), SSError>
{
let res: i32;
unsafe {
res = match family {
SHA256 => crypto_auth_hmacsha256_update(
state.as_mut_ptr(),
in_.as_ptr(),
in_.len() as c_ulonglong
),
SHA512 => crypto_auth_hmacsha512_update(
state.as_mut_ptr(),
in_.as_ptr(),
in_.len() as c_ulonglong
),
SHA512256 => crypto_auth_hmacsha512256_update(
state.as_mut_ptr(),
in_.as_ptr(),
in_.len() as c_ulonglong
),
};
}
if res == 0 {
Ok(())
} else {
Err(MAC("Unable to update hash state"))
}
}
pub fn finalize<'a>(
state: &'a mut [u8],
family: Family
)
-> Result<&'a [u8], SSError>
{
let (res, out) = match family {
SHA256 => {
let out = secmem::malloc(HMACSHA256_BYTES);
let res: i32;
unsafe {
res = crypto_auth_hmacsha256_final(
state.as_mut_ptr(),
out.as_mut_ptr()
);
}
(res, out)
},
SHA512 => {
let out = secmem::malloc(HMACSHA512_BYTES);
let res: i32;
unsafe {
res = crypto_auth_hmacsha512_final(
state.as_mut_ptr(),
out.as_mut_ptr()
);
}
(res, out)
},
SHA512256 => {
let out = secmem::malloc(HMACSHA512256_BYTES);
let res: i32;
unsafe {
res = crypto_auth_hmacsha512256_final(
state.as_mut_ptr(),
out.as_mut_ptr()
);
}
(res, out)
},
};
if res == 0 {
secmem::mprotect_readonly(out);
Ok(out)
} else {
Err(MAC("Unable to update hash state"))
}
}