mod sodium_padding;
use sodiumoxide::base64;
use super::error::{Error, Result};
#[doc(hidden)]
#[macro_export]
macro_rules! try_into {
($x:expr) => {
($x).try_into()
.or(Err(Error::ProgrammingError("Try into failed")))
};
}
pub type StrBase64 = str;
pub type StringBase64 = String;
pub const SYMMETRIC_KEY_SIZE: usize = 32; pub const SYMMETRIC_TAG_SIZE: usize = 16; pub const SYMMETRIC_NONCE_SIZE: usize = 24;
pub fn randombytes(size: usize) -> Vec<u8> {
sodiumoxide::randombytes::randombytes(size)
}
pub fn randombytes_deterministic(size: usize, seed: &[u8; 32]) -> Vec<u8> {
let nonce =
sodiumoxide::crypto::stream::xchacha20::Nonce(*b"LibsodiumDRG\0\0\0\0\0\0\0\0\0\0\0\0");
let key = sodiumoxide::crypto::stream::xchacha20::Key(*seed);
sodiumoxide::crypto::stream::xchacha20::stream(size, &nonce, &key)
}
pub fn memcmp(x: &[u8], y: &[u8]) -> bool {
sodiumoxide::utils::memcmp(x, y)
}
pub fn from_base64(string: &StrBase64) -> Result<Vec<u8>> {
match base64::decode(string, base64::Variant::UrlSafeNoPadding) {
Ok(bytes) => Ok(bytes),
Err(_) => Err(Error::Base64("Failed decoding base64 string")),
}
}
pub fn to_base64(bytes: &[u8]) -> Result<StringBase64> {
Ok(base64::encode(bytes, base64::Variant::UrlSafeNoPadding))
}
pub(crate) fn shuffle<T>(a: &mut Vec<T>) -> Vec<usize> {
let len = a.len();
let mut shuffled_indices: Vec<usize> = (0..len).collect();
for i in 0..len {
let j = i + sodiumoxide::randombytes::randombytes_uniform((len - i) as u32) as usize;
a.swap(i, j);
shuffled_indices.swap(i, j);
}
let mut ret = vec![0; len];
for i in 0..len {
ret[shuffled_indices[i]] = i;
}
ret
}
pub fn get_padding(length: u32) -> u32 {
if length < (1 << 14) {
let size = (1 << 10) - 1;
return (length | size) + 1;
}
let e = (length as f64).log2().floor();
let s = (e.log2().floor() as u32) + 1;
let last_bits = (e as u32) - s;
let bit_mask = (1 << last_bits) - 1;
(length + bit_mask) & !bit_mask
}
pub(crate) fn buffer_pad_small(buf: &[u8]) -> Result<Vec<u8>> {
let len = buf.len();
let padding = len + 1;
buffer_pad_fixed(buf, padding)
}
pub(crate) fn buffer_pad(buf: &[u8]) -> Result<Vec<u8>> {
let len = buf.len();
let padding = get_padding(len as u32) as usize;
buffer_pad_fixed(buf, padding)
}
pub(crate) fn buffer_unpad(buf: &[u8]) -> Result<Vec<u8>> {
let len = buf.len();
buffer_unpad_fixed(buf, len)
}
pub(crate) fn buffer_pad_fixed(buf: &[u8], blocksize: usize) -> Result<Vec<u8>> {
let len = buf.len();
let missing = blocksize - (len % blocksize);
let padding = len + missing;
let mut ret = vec![0; padding];
ret[..len].copy_from_slice(buf);
sodium_padding::pad(&mut ret[..], len, blocksize)
.map_err(|_| Error::Padding("Failed padding"))?;
Ok(ret)
}
pub(crate) fn buffer_unpad_fixed(buf: &[u8], blocksize: usize) -> Result<Vec<u8>> {
let len = buf.len();
if len == 0 {
return Ok(vec![0; 0]);
}
let mut buf = buf.to_vec();
let new_len = sodium_padding::unpad(&buf[..], len, blocksize)
.map_err(|_| Error::Padding("Failed unpadding"))?;
buf.truncate(new_len);
Ok(buf)
}
pub trait MsgPackSerilization {
type Output;
fn to_msgpack(&self) -> Result<Vec<u8>>;
fn from_msgpack(data: &[u8]) -> Result<Self::Output>;
}