use libc::{c_uchar, c_int, c_ulonglong};
use SSError::{self, DECRYPT, ENCRYPT};
use crypto::utils::secmem;
pub const KEYBYTES: usize = 32;
pub const NONCEBYTES: usize = 24;
pub const ZEROBYTES: usize = 32;
pub const BOXZEROBYTES: usize = 16;
pub const MACBYTES: usize = ZEROBYTES - BOXZEROBYTES;
extern "C" {
fn crypto_secretbox_easy(c: *mut c_uchar,
m: *const c_uchar,
mlen: c_ulonglong,
n: *const c_uchar,
k: *const c_uchar) -> c_int;
fn crypto_secretbox_open_easy(m: *mut c_uchar,
c: *const c_uchar,
clen: c_ulonglong,
n: *const c_uchar,
k: *const c_uchar) -> c_int;
fn crypto_secretbox_detached(c: *mut c_uchar,
mac: *mut c_uchar,
m: *const c_uchar,
mlen: c_ulonglong,
n: *const c_uchar,
k: *const c_uchar) -> c_int;
fn crypto_secretbox_open_detached(m: *mut c_uchar,
c: *const c_uchar,
mac: *const c_uchar,
clen: c_ulonglong,
n: *const c_uchar,
k: *const c_uchar) -> c_int;
fn crypto_secretbox(c: *mut c_uchar,
m: *const c_uchar,
mlen: c_ulonglong,
n: *const c_uchar,
k: *const c_uchar) -> c_int;
fn crypto_secretbox_open(m: *mut c_uchar,
c: *const c_uchar,
clen: c_ulonglong,
n: *const c_uchar,
k: *const c_uchar) -> c_int;
}
pub fn encrypt<'a>(message: &[u8],
key: &[u8],
nonce: &[u8]) -> Result<&'a mut [u8], SSError> {
assert!(key.len() == KEYBYTES);
assert!(nonce.len() == NONCEBYTES);
let mut ciphertext = secmem::malloc(MACBYTES + message.len());
let res: i32;
unsafe {
res = crypto_secretbox_easy(ciphertext.as_mut_ptr(),
message.as_ptr(),
message.len() as c_ulonglong,
nonce.as_ptr(),
key.as_ptr());
}
if res == 0 {
secmem::mprotect_readonly(ciphertext);
Ok(ciphertext)
} else {
Err(ENCRYPT("Unable to encrypt message"))
}
}
pub fn open<'a>(ciphertext: &[u8],
key: &[u8],
nonce: &[u8]) -> Result<&'a mut [u8], SSError> {
assert!(key.len() == KEYBYTES);
assert!(nonce.len() == NONCEBYTES);
let mut message = secmem::malloc(ciphertext.len() - MACBYTES);
let res: i32;
unsafe {
res = crypto_secretbox_open_easy(message.as_mut_ptr(),
ciphertext.as_ptr(),
ciphertext.len() as c_ulonglong,
nonce.as_ptr(),
key.as_ptr());
}
if res == 0 {
secmem::mprotect_readonly(message);
Ok(message)
} else {
Err(DECRYPT("Unable to decrypt ciphertext"))
}
}
pub type EncryptDetachedResult<'a> = Result<(&'a mut [u8], &'a mut [u8]), SSError>;
pub fn encrypt_detached<'a>(message: &[u8],
key: &[u8],
nonce: &[u8]) -> EncryptDetachedResult<'a> {
assert!(key.len() == KEYBYTES);
assert!(nonce.len() == NONCEBYTES);
let mut ciphertext = secmem::malloc(message.len());
let mut mac = secmem::malloc(MACBYTES);
let res: i32;
unsafe {
res = crypto_secretbox_detached(ciphertext.as_mut_ptr(),
mac.as_mut_ptr(),
message.as_ptr(),
message.len() as c_ulonglong,
nonce.as_ptr(),
key.as_ptr());
}
if res == 0 {
secmem::mprotect_readonly(ciphertext);
secmem::mprotect_readonly(mac);
Ok((ciphertext, mac))
} else {
Err(ENCRYPT("Unable to encrypt message"))
}
}
pub fn open_detached<'a>(ciphertext: &[u8],
mac: &[u8],
key: &[u8],
nonce: &[u8]) -> Result<&'a mut [u8], SSError> {
assert!(mac.len() == MACBYTES);
assert!(key.len() == KEYBYTES);
assert!(nonce.len() == NONCEBYTES);
let mut message = secmem::malloc(ciphertext.len());
let res: i32;
unsafe {
res = crypto_secretbox_open_detached(message.as_mut_ptr(),
ciphertext.as_ptr(),
mac.as_ptr(),
ciphertext.len() as c_ulonglong,
nonce.as_ptr(),
key.as_ptr());
}
if res == 0 {
secmem::mprotect_readonly(message);
Ok(message)
} else {
Err(DECRYPT("Unable to decrypt ciphertext"))
}
}
pub fn encrypt_nacl<'a>(message: &[u8],
key: &[u8],
nonce: &[u8]) -> Result<&'a [u8], SSError> {
assert!(key.len() == KEYBYTES);
assert!(nonce.len() == NONCEBYTES);
let mut padded = secmem::malloc(ZEROBYTES + message.len());
for i in 0..ZEROBYTES {
padded[i] = 0;
}
for (i,b) in (ZEROBYTES..(ZEROBYTES+message.len())).zip(message.iter()) {
padded[i] = *b;
}
let mut ciphertext = secmem::malloc(padded.len());
let res: i32;
unsafe {
res = crypto_secretbox(ciphertext.as_mut_ptr(),
padded.as_ptr(),
padded.len() as c_ulonglong,
nonce.as_ptr(),
key.as_ptr());
}
secmem::free(padded);
if res == 0 {
secmem::mprotect_readonly(ciphertext);
Ok(ciphertext)
} else {
Err(ENCRYPT("Unable to encrypt message!"))
}
}
pub fn open_nacl<'a>(ciphertext: &[u8],
key: &[u8],
nonce: &[u8]) -> Result<&'a mut [u8], SSError> {
assert!(key.len() == KEYBYTES);
assert!(nonce.len() == NONCEBYTES);
let mut message = secmem::malloc(ciphertext.len());
let res: i32;
unsafe {
res = crypto_secretbox_open(message.as_mut_ptr(),
ciphertext.as_ptr(),
ciphertext.len() as c_ulonglong,
nonce.as_ptr(),
key.as_ptr());
}
if res == 0 {
secmem::mprotect_readonly(message);
Ok(message)
} else {
Err(DECRYPT("Unable to decrypt ciphertext"))
}
}