use libc::{c_int,c_uchar, c_ulonglong};
use SSError::{self, DECRYPT, ENCRYPT};
use std::ptr;
use crypto::utils::secmem;
pub const KEYBYTES: usize = 32;
pub const NPUBBYTES: usize = 8;
#[cfg(feature = "latest")]
pub const IETF_NPUBBYTES: usize = 12;
pub const ABYTES: usize = 16;
extern "C" {
fn crypto_aead_chacha20poly1305_encrypt(c: *mut c_uchar,
clen: *mut c_ulonglong,
m: *const c_uchar,
mlen: c_ulonglong,
ad: *const c_uchar,
adlen: c_ulonglong,
nsec: *const c_uchar,
npub: *const c_uchar,
k: *const c_uchar) -> c_int;
fn crypto_aead_chacha20poly1305_decrypt(m: *mut c_uchar,
mlen: *mut c_ulonglong,
nsec: *mut c_uchar,
c: *const c_uchar,
clen: c_ulonglong,
ad: *const c_uchar,
adlen: c_ulonglong,
npub: *const c_uchar,
k: *const c_uchar) -> c_int;
#[cfg(feature = "latest")]
fn crypto_aead_chacha20poly1305_ietf_encrypt(c: *mut c_uchar,
clen: *mut c_ulonglong,
m: *const c_uchar,
mlen: c_ulonglong,
ad: *const c_uchar,
adlen: c_ulonglong,
nsec: *const c_uchar,
npub: *const c_uchar,
k: *const c_uchar) -> c_int;
#[cfg(feature = "latest")]
fn crypto_aead_chacha20poly1305_ietf_decrypt(m: *mut c_uchar,
mlen: *mut c_ulonglong,
nsec: *mut c_uchar,
c: *const c_uchar,
clen: c_ulonglong,
ad: *const c_uchar,
adlen: c_ulonglong,
npub: *const c_uchar,
k: *const c_uchar) -> c_int;
}
pub fn aead_encrypt<'a>(message: &[u8],
add_data: Option<&[u8]>,
key: &[u8],
nonce: &[u8]) -> Result<&'a mut [u8], SSError> {
assert!(key.len() == KEYBYTES);
assert!(nonce.len() == NPUBBYTES);
if add_data.is_some() {
assert!(add_data.unwrap().len() <= ABYTES);
}
let (ad_ptr, ad_len) = match add_data {
Some(ad) => (ad.as_ptr(), ad.len()),
None => (ptr::null(), 0),
};
let mut ciphertext = secmem::malloc(ABYTES + message.len());
let res: i32;
unsafe {
res = crypto_aead_chacha20poly1305_encrypt(ciphertext.as_mut_ptr(),
ptr::null_mut(),
message.as_ptr(),
message.len() as c_ulonglong,
ad_ptr,
ad_len as c_ulonglong,
ptr::null(),
nonce.as_ptr(),
key.as_ptr());
}
if res == 0 {
Ok(ciphertext)
} else {
Err(ENCRYPT("Unable to encrypt message and associated data"))
}
}
pub fn aead_decrypt<'a>(ciphertext: &[u8],
add_data: Option<&[u8]>,
key: &[u8],
nonce: &[u8]) -> Result<&'a mut [u8], SSError> {
assert!(key.len() == KEYBYTES);
assert!(nonce.len() == NPUBBYTES);
if add_data.is_some() {
assert!(add_data.unwrap().len() <= ABYTES);
}
let (ad_ptr, ad_len) = match add_data {
Some(ad) => (ad.as_ptr(), ad.len()),
None => (ptr::null(), 0),
};
let mut message = secmem::malloc(ciphertext.len() - ABYTES);
let res: i32;
unsafe {
res = crypto_aead_chacha20poly1305_decrypt(message.as_mut_ptr(),
ptr::null_mut(),
ptr::null_mut(),
ciphertext.as_ptr(),
ciphertext.len() as c_ulonglong,
ad_ptr,
ad_len as c_ulonglong,
nonce.as_ptr(),
key.as_ptr());
}
if res == 0 {
Ok(message)
} else {
Err(DECRYPT("Error decrypting ciphertext with associated data"))
}
}
#[cfg(feature = "latest")]
pub fn aead_encrypt_ietf<'a>(message: &[u8],
add_data: Option<&[u8]>,
key: &[u8],
nonce: &[u8]) -> Result<&'a mut [u8], SSError> {
assert!(key.len() == KEYBYTES);
assert!(nonce.len() == IETF_NPUBBYTES);
if add_data.is_some() {
assert!(add_data.unwrap().len() <= ABYTES);
}
let (ad_ptr, ad_len) = match add_data {
Some(ad) => (ad.as_ptr(), ad.len()),
None => (ptr::null(), 0),
};
let mut ciphertext = secmem::malloc(ABYTES + message.len());
let res: i32;
unsafe {
res = crypto_aead_chacha20poly1305_ietf_encrypt(ciphertext.as_mut_ptr(),
ptr::null_mut(),
message.as_ptr(),
message.len() as c_ulonglong,
ad_ptr,
ad_len as c_ulonglong,
ptr::null(),
nonce.as_ptr(),
key.as_ptr());
}
if res == 0 {
Ok(ciphertext)
} else {
Err(ENCRYPT("Unable to encrypt message and associated data"))
}
}
#[cfg(feature = "latest")]
pub fn aead_decrypt_ietf<'a>(ciphertext: &[u8],
add_data: Option<&[u8]>,
key: &[u8],
nonce: &[u8]) -> Result<&'a mut [u8], SSError> {
assert!(key.len() == KEYBYTES);
assert!(nonce.len() == IETF_NPUBBYTES);
if add_data.is_some() {
assert!(add_data.unwrap().len() <= ABYTES);
}
let (ad_ptr, ad_len) = match add_data {
Some(ad) => (ad.as_ptr(), ad.len()),
None => (ptr::null(), 0),
};
let mut message = secmem::malloc(ciphertext.len() - ABYTES);
let res: i32;
unsafe {
res = crypto_aead_chacha20poly1305_ietf_decrypt(message.as_mut_ptr(),
ptr::null_mut(),
ptr::null_mut(),
ciphertext.as_ptr(),
ciphertext.len() as c_ulonglong,
ad_ptr,
ad_len as c_ulonglong,
nonce.as_ptr(),
key.as_ptr());
}
if res == 0 {
Ok(message)
} else {
Err(DECRYPT("Error decrypting ciphertext with associated data"))
}
}