ursa 0.3.7

This is the shared crypto library for Hyperledger components.
Documentation
use super::Encryptor;
use aead::{
    generic_array::{
        typenum::{Unsigned, U0, U12, U16, U32, U36},
        GenericArray,
    },
    Aead, Error, NewAead, Payload,
};
#[cfg(feature = "serde")]
use serde::{de::Visitor, Deserialize, Deserializer, Serialize, Serializer};
use std::{
    os::raw,
    ptr,
    sync::atomic::{AtomicBool, Ordering},
};
use zeroize::Zeroize;

lazy_static! {
    static ref INIT: AtomicBool = AtomicBool::new(false);
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub struct ChaCha20Poly1305 {
    key: GenericArray<u8, U32>,
}

impl Encryptor for ChaCha20Poly1305 {
    type MinSize = U36;
}

impl NewAead for ChaCha20Poly1305 {
    type KeySize = U32;

    fn new(key: &GenericArray<u8, Self::KeySize>) -> Self {
        if !INIT.load(Ordering::Relaxed) {
            INIT.store(true, Ordering::Release);
            unsafe {
                libsodium_ffi::sodium_init();
            }
        }
        Self { key: *key }
    }
}

impl Aead for ChaCha20Poly1305 {
    type NonceSize = U12;
    type TagSize = U16;
    type CiphertextOverhead = U0;

    fn encrypt<'msg, 'aad>(
        &self,
        nonce: &GenericArray<u8, Self::NonceSize>,
        plaintext: impl Into<Payload<'msg, 'aad>>,
    ) -> Result<Vec<u8>, Error> {
        let payload = plaintext.into();
        let mut ciphertext = Vec::with_capacity(payload.msg.len() + Self::TagSize::to_usize());
        let mut clen = ciphertext.len() as raw::c_ulonglong;

        unsafe {
            libsodium_ffi::crypto_aead_chacha20poly1305_ietf_encrypt(
                ciphertext.as_mut_ptr(),
                &mut clen,
                payload.msg.as_ptr(),
                payload.msg.len() as raw::c_ulonglong,
                payload.aad.as_ptr(),
                payload.aad.len() as raw::c_ulonglong,
                ptr::null_mut(),
                nonce.as_slice().as_ptr(),
                self.key.as_slice().as_ptr(),
            );
            ciphertext.set_len(clen as usize);
        }
        Ok(ciphertext)
    }

    fn decrypt<'msg, 'aad>(
        &self,
        nonce: &GenericArray<u8, Self::NonceSize>,
        ciphertext: impl Into<Payload<'msg, 'aad>>,
    ) -> Result<Vec<u8>, Error> {
        let payload = ciphertext.into();
        if payload.msg.len() < Self::TagSize::to_usize() {
            return Err(Error);
        }
        let mut plaintext = Vec::with_capacity(payload.msg.len() - Self::TagSize::to_usize());
        let mut plen = plaintext.len() as raw::c_ulonglong;

        unsafe {
            let res = libsodium_ffi::crypto_aead_chacha20poly1305_ietf_decrypt(
                plaintext.as_mut_ptr(),
                &mut plen,
                ptr::null_mut(),
                payload.msg.as_ptr(),
                payload.msg.len() as raw::c_ulonglong,
                payload.aad.as_ptr(),
                payload.aad.len() as raw::c_ulonglong,
                nonce.as_slice().as_ptr(),
                self.key.as_slice().as_ptr(),
            );
            if res != 0 {
                return Err(Error);
            }
            plaintext.set_len(plen as usize);
        }
        Ok(plaintext)
    }
}

default_impl!(ChaCha20Poly1305);
drop_impl!(ChaCha20Poly1305);
#[cfg(feature = "serde")]
serialize_impl!(ChaCha20Poly1305, ChaCha20Poly1305Visitor);
#[cfg(test)]
mod tests {
    tests_impl!(ChaCha20Poly1305);
}