monosodium 0.1.0-pre.1

Plain bindings to libsodium
Documentation
use crate::ffi::sodium::*;
use crate::util::{CryptoBuf, KeyPair};
use crate::util::base64::{Base64Config};

use std::cmp::{Ordering};
use std::os::raw::{c_char};
use std::ptr::{null, null_mut};

pub mod ffi;
pub mod util;

pub fn init_sodium() {
  assert_eq!(0, unsafe { sodium_init() });
}

pub fn random_buf(buf: &mut [u8]) {
  unsafe { randombytes_buf(buf.as_mut_ptr() as *mut _, buf.len()) };
}

pub fn zero_buf(buf: &mut [u8]) {
  unsafe { sodium_memzero(buf.as_mut_ptr() as *mut _, buf.len()) };
}

pub fn eq_bufs(buf: &[u8], other_buf: &[u8]) -> bool {
  if buf.len() != other_buf.len() {
    return false;
  }
  assert_eq!(buf.len(), other_buf.len());
  let ret = unsafe { sodium_memcmp(
      buf.as_ptr() as *const _,
      other_buf.as_ptr() as *const _,
      buf.len(),
  ) };
  match ret {
    0 => true,
    -1 => false,
    _ => panic!(),
  }
}

pub fn partial_cmp_bufs(buf: &[u8], other_buf: &[u8]) -> Option<Ordering> {
  if buf.len() != other_buf.len() {
    return None;
  }
  assert_eq!(buf.len(), other_buf.len());
  let ret = unsafe { sodium_compare(
      buf.as_ptr() as *const _,
      other_buf.as_ptr() as *const _,
      buf.len(),
  ) };
  match ret {
    -1 => Some(Ordering::Less),
    0 => Some(Ordering::Equal),
    1 => Some(Ordering::Greater),
    _ => panic!(),
  }
}

pub fn is_zero_buf(buf: &[u8]) -> bool {
  let ret = unsafe { sodium_is_zero(
      buf.as_ptr(),
      buf.len(),
  ) };
  match ret {
    0 => false,
    1 => true,
    _ => panic!(),
  }
}

pub fn hex_decode_slice<T: ?Sized + AsRef<[u8]>>(input: &T, output: &mut [u8]) -> Result<usize, ()> {
  let hex = input.as_ref();
  let mut bin_len: usize = 0;
  let ret = unsafe { sodium_hex2bin(
      output.as_mut_ptr(), output.len(),
      hex.as_ptr() as *const i8, hex.len(),
      null(),
      &mut bin_len as *mut usize,
      null_mut(),
  ) };
  match ret {
    0 => {}
    -1 => return Err(()),
    _ => panic!(),
  }
  assert!(bin_len <= output.len());
  Ok(bin_len)
}

pub fn hex_encode_slice_c<T: ?Sized + AsRef<[u8]>>(input: &T, output: &mut [u8]) {
  let bin = input.as_ref();
  unsafe { sodium_bin2hex(
      output.as_mut_ptr() as *mut i8, output.len(),
      bin.as_ptr(), bin.len(),
  ) };
}

pub fn base64_decode_config_slice<T: ?Sized + AsRef<[u8]>>(input: &T, config: Base64Config, output: &mut [u8]) -> Result<usize, ()> {
  let b64 = input.as_ref();
  let mut bin_len: usize = 0;
  let ret = unsafe { sodium_base642bin(
      output.as_mut_ptr(), output.len(),
      b64.as_ptr() as *const i8, b64.len(),
      null(),
      &mut bin_len as *mut usize,
      null_mut(),
      config.to_raw_variant(),
  ) };
  match ret {
    0 => {}
    -1 => return Err(()),
    _ => panic!(),
  }
  assert!(bin_len <= output.len());
  Ok(bin_len)
}

pub fn base64_encode_config_slice_c<T: ?Sized + AsRef<[u8]>>(input: &T, config: Base64Config, output: &mut [u8]) {
  let bin = input.as_ref();
  unsafe { sodium_bin2base64(
      output.as_mut_ptr() as *mut i8, output.len(),
      bin.as_ptr(), bin.len(),
      config.to_raw_variant(),
  ) };
}

pub fn aead_key_buflen() -> usize {
  crypto_aead_xchacha20poly1305_ietf_KEYBYTES as usize
}

pub fn aead_nonce_buflen() -> usize {
  crypto_aead_xchacha20poly1305_ietf_NPUBBYTES as usize
}

pub fn aead_cipher_buflen(msg_len: usize) -> usize {
  let cipher_len = msg_len + crypto_aead_xchacha20poly1305_ietf_ABYTES as usize;
  assert!(cipher_len > msg_len);
  cipher_len
}

pub fn aead_decrypt_buflen(cipher_len: usize) -> usize {
  let decrypt_len = cipher_len - crypto_aead_xchacha20poly1305_ietf_ABYTES as usize;
  assert!(decrypt_len < cipher_len);
  decrypt_len
}

pub fn gen_aead_key(key_buf: &mut [u8]) {
  assert_eq!(key_buf.len(), crypto_aead_xchacha20poly1305_ietf_KEYBYTES as usize);
  unsafe { crypto_aead_xchacha20poly1305_ietf_keygen(key_buf.as_mut_ptr()) };
}

pub fn aead_encrypt(cipher_buf: &mut [u8], msg_buf: &[u8], moremsg_buf: &[u8], nonce_buf: &[u8], key_buf: &[u8]) -> Result<(), ()> {
  assert_eq!(cipher_buf.len(), aead_cipher_buflen(msg_buf.len()));
  assert_eq!(nonce_buf.len(), aead_nonce_buflen());
  assert_eq!(key_buf.len(), aead_key_buflen());
  let mut cipher_buflen_ret: u64 = 0;
  let ret = unsafe { crypto_aead_xchacha20poly1305_ietf_encrypt(
      cipher_buf.as_mut_ptr(), &mut cipher_buflen_ret as *mut _,
      msg_buf.as_ptr(), msg_buf.len() as u64,
      moremsg_buf.as_ptr(), moremsg_buf.len() as u64,
      null(),
      nonce_buf.as_ptr(), key_buf.as_ptr(),
  ) };
  assert_eq!(cipher_buflen_ret, cipher_buf.len() as u64);
  match ret {
    0 => {}
    -1 => return Err(()),
    _ => panic!(),
  }
  Ok(())
}

pub fn aead_decrypt(decrypt_buf: &mut [u8], cipher_buf: &[u8], moremsg_buf: &[u8], nonce_buf: &[u8], key_buf: &[u8]) -> Result<(), ()> {
  assert_eq!(decrypt_buf.len(), aead_decrypt_buflen(cipher_buf.len()));
  assert_eq!(nonce_buf.len(), aead_nonce_buflen());
  assert_eq!(key_buf.len(), aead_key_buflen());
  let mut decrypt_buflen_ret: u64 = 0;
  let ret = unsafe { crypto_aead_xchacha20poly1305_ietf_decrypt(
      decrypt_buf.as_mut_ptr(), &mut decrypt_buflen_ret as *mut _,
      null_mut(),
      cipher_buf.as_ptr(), cipher_buf.len() as u64,
      moremsg_buf.as_ptr(), moremsg_buf.len() as u64,
      nonce_buf.as_ptr(), key_buf.as_ptr(),
  ) };
  assert_eq!(decrypt_buflen_ret, decrypt_buf.len() as u64);
  match ret {
    0 => {}
    -1 => return Err(()),
    _ => panic!(),
  }
  Ok(())
}

pub fn auth_sig_buflen() -> usize {
  crypto_auth_hmacsha512256_BYTES as usize
}

pub fn auth_key_buflen() -> usize {
  crypto_auth_hmacsha512256_KEYBYTES as usize
}

pub fn auth_sign(sig_buf: &mut [u8], msg_buf: &[u8], key_buf: &[u8]) -> Result<(), ()> {
  assert_eq!(sig_buf.len(), auth_sig_buflen());
  assert_eq!(key_buf.len(), auth_key_buflen());
  let ret = unsafe { crypto_auth_hmacsha512256(
      sig_buf.as_mut_ptr(),
      msg_buf.as_ptr(), msg_buf.len() as u64,
      key_buf.as_ptr(),
  ) };
  match ret {
    0 => {}
    -1 => return Err(()),
    _ => panic!(),
  }
  Ok(())
}

pub fn auth_verify(sig_buf: &[u8], msg_buf: &[u8], key_buf: &[u8]) -> Result<(), ()> {
  assert_eq!(sig_buf.len(), auth_sig_buflen());
  assert_eq!(key_buf.len(), auth_key_buflen());
  let ret = unsafe { crypto_auth_hmacsha512256_verify(
      sig_buf.as_ptr(),
      msg_buf.as_ptr(), msg_buf.len() as u64,
      key_buf.as_ptr(),
  ) };
  match ret {
    0 => {}
    -1 => return Err(()),
    _ => panic!(),
  }
  Ok(())
}

pub fn sign_buflen() -> usize {
  crypto_sign_BYTES as usize
}

pub fn sign_public_key_buflen() -> usize {
  crypto_sign_PUBLICKEYBYTES as usize
}

pub fn sign_secret_key_buflen() -> usize {
  crypto_sign_SECRETKEYBYTES as usize
}

pub fn gen_sign_keypair() -> Result<KeyPair, ()> {
  let mut public_key_buf = CryptoBuf::zero_bytes(sign_public_key_buflen());
  let mut secret_key_buf = CryptoBuf::zero_bytes(sign_secret_key_buflen());
  let ret = {
    let p = public_key_buf.as_mut();
    let s = secret_key_buf.as_mut();
    unsafe { crypto_sign_keypair(
      p.as_mut_ptr(),
      s.as_mut_ptr(),
    ) }
  };
  match ret {
    0 => {}
    -1 => return Err(()),
    _ => panic!(),
  }
  Ok(KeyPair{
    public: public_key_buf,
    secret: secret_key_buf,
  })
}

pub fn sign(sig_buf: &mut [u8], msg_buf: &[u8], secret_key_buf: &[u8]) -> Result<(), ()> {
  assert_eq!(sig_buf.len(), sign_buflen());
  assert_eq!(secret_key_buf.len(), sign_secret_key_buflen());
  let mut sig_buflen_ret: u64 = 0;
  let ret = unsafe { crypto_sign_detached(
      sig_buf.as_mut_ptr(), &mut sig_buflen_ret as *mut u64,
      msg_buf.as_ptr(), msg_buf.len() as u64,
      secret_key_buf.as_ptr(),
  ) };
  assert_eq!(sig_buflen_ret, sig_buf.len() as u64);
  match ret {
    0 => {}
    -1 => return Err(()),
    _ => panic!(),
  }
  Ok(())
}

pub fn sign_verify(sig_buf: &[u8], msg_buf: &[u8], public_key_buf: &[u8]) -> Result<(), ()> {
  assert_eq!(sig_buf.len(), sign_buflen());
  assert_eq!(public_key_buf.len(), sign_public_key_buflen());
  let ret = unsafe { crypto_sign_verify_detached(
      sig_buf.as_ptr(),
      msg_buf.as_ptr(), msg_buf.len() as u64,
      public_key_buf.as_ptr(),
  ) };
  match ret {
    0 => {}
    -1 => return Err(()),
    _ => panic!(),
  }
  Ok(())
}

pub fn generic_hash_buflen() -> usize {
  crypto_generichash_BYTES as usize
}

pub fn generic_hash_key_buflen() -> usize {
  crypto_generichash_KEYBYTES as usize
}

pub fn generic_hash(hash_buf: &mut [u8], msg_buf: &[u8], key_buf: &[u8]) -> Result<(), ()> {
  assert_eq!(hash_buf.len(), generic_hash_buflen());
  assert_eq!(key_buf.len(), generic_hash_key_buflen());
  let ret = unsafe { crypto_generichash(
      hash_buf.as_mut_ptr(), hash_buf.len(),
      msg_buf.as_ptr(), msg_buf.len() as u64,
      key_buf.as_ptr(), key_buf.len(),
  ) };
  match ret {
    0 => {}
    -1 => return Err(()),
    _ => panic!(),
  }
  Ok(())
}

pub fn pwhash_buflen() -> usize {
  crypto_pwhash_BYTES_MIN as usize
}

pub fn pwhash_salt_buflen() -> usize {
  crypto_pwhash_SALTBYTES as usize
}

pub fn pwhash_str_buflen() -> usize {
  crypto_pwhash_STRBYTES as usize
}

pub fn pwhash_str_prefix() -> &'static [u8] {
  crypto_pwhash_STRPREFIX
}

pub fn pwhash_str(str_buf: &mut [u8], passwd_buf: &[u8], ops_limit: u64, mem_limit: usize) -> Result<(), ()> {
  assert_eq!(str_buf.len(), pwhash_str_buflen());
  let ret = unsafe { crypto_pwhash_str(
      str_buf.as_mut_ptr() as *mut c_char,
      passwd_buf.as_ptr() as *const c_char, passwd_buf.len() as u64,
      ops_limit,
      mem_limit,
  ) };
  match ret {
    0 => {}
    -1 => return Err(()),
    _ => panic!(),
  }
  Ok(())
}

pub fn pwhash_str_verify(str_buf: &[u8], passwd_buf: &[u8]) -> Result<(), ()> {
  assert_eq!(str_buf.len(), pwhash_str_buflen());
  let ret = unsafe { crypto_pwhash_str_verify(
      str_buf.as_ptr() as *const c_char,
      passwd_buf.as_ptr() as *const c_char, passwd_buf.len() as u64,
  ) };
  match ret {
    0 => {}
    -1 => return Err(()),
    _ => panic!(),
  }
  Ok(())
}