Unverified Commit ca442708 authored by Steven Fackler's avatar Steven Fackler
Browse files

Switch symm and envelope over to CipherCtx

parent 29047944
Loading
Loading
Loading
Loading
+79 −1
Original line number Diff line number Diff line
use crate::error::ErrorStack;
use crate::pkey::{HasPrivate, HasPublic, PKey, PKeyRef};
use crate::symm::{Cipher, Mode};
use crate::{cvt, cvt_p};
use cfg_if::cfg_if;
@@ -35,7 +36,7 @@ impl CipherCtx {
}

impl CipherCtxRef {
    pub fn init(
    pub fn cipher_init(
        &mut self,
        // FIXME CipherRef
        type_: Option<&Cipher>,
@@ -74,6 +75,83 @@ impl CipherCtxRef {
        Ok(())
    }

    pub fn seal_init<T>(
        &mut self,
        // FIXME CipherRef
        type_: Option<&Cipher>,
        pub_keys: &[PKey<T>],
        encrypted_keys: &mut [Vec<u8>],
        iv: Option<&mut [u8]>,
    ) -> Result<(), ErrorStack>
    where
        T: HasPublic,
    {
        assert_eq!(pub_keys.len(), encrypted_keys.len());
        let iv_len = type_.map_or_else(|| self.iv_length(), |c| c.iv_len());
        if let Some(iv_len) = iv_len {
            assert!(iv.as_ref().map_or(0, |b| b.len()) >= iv_len);
        }

        for (pub_key, buf) in pub_keys.iter().zip(&mut *encrypted_keys) {
            buf.resize(pub_key.size(), 0);
        }

        let mut keys = encrypted_keys
            .iter_mut()
            .map(|b| b.as_mut_ptr())
            .collect::<Vec<_>>();
        let mut key_lengths = vec![0; pub_keys.len()];
        let pub_keys_len = i32::try_from(pub_keys.len()).unwrap();

        unsafe {
            cvt(ffi::EVP_SealInit(
                self.as_ptr(),
                type_.map_or(ptr::null(), Cipher::as_ptr),
                keys.as_mut_ptr(),
                key_lengths.as_mut_ptr(),
                iv.map_or(ptr::null_mut(), |b| b.as_mut_ptr()),
                pub_keys.as_ptr() as *mut _,
                pub_keys_len,
            ))?;
        }

        for (buf, len) in encrypted_keys.iter_mut().zip(key_lengths) {
            buf.truncate(len as usize);
        }

        Ok(())
    }

    pub fn open_init<T>(
        &mut self,
        type_: Option<&Cipher>,
        encrypted_key: &[u8],
        iv: Option<&[u8]>,
        priv_key: Option<&PKeyRef<T>>,
    ) -> Result<(), ErrorStack>
    where
        T: HasPrivate,
    {
        let iv_len = type_.map_or_else(|| self.iv_length(), |c| c.iv_len());
        if let Some(iv_len) = iv_len {
            assert!(iv.map_or(0, |b| b.len()) >= iv_len);
        }

        let len = c_int::try_from(encrypted_key.len()).unwrap();
        unsafe {
            cvt(ffi::EVP_OpenInit(
                self.as_ptr(),
                type_.map_or(ptr::null(), Cipher::as_ptr),
                encrypted_key.as_ptr(),
                len,
                iv.map_or(ptr::null(), |b| b.as_ptr()),
                priv_key.map_or(ptr::null_mut(), ForeignTypeRef::as_ptr),
            ))?;
        }

        Ok(())
    }

    fn assert_cipher(&self) {
        unsafe {
            assert!(!EVP_CIPHER_CTX_get0_cipher(self.as_ptr()).is_null());
+15 −128
Original line number Diff line number Diff line
@@ -21,19 +21,14 @@
//! enc_len += seal.finalize(&mut encrypted[enc_len..]).unwrap();
//! encrypted.truncate(enc_len);
//! ```
use crate::cipher_ctx::CipherCtx;
use crate::error::ErrorStack;
use crate::pkey::{HasPrivate, HasPublic, PKey, PKeyRef};
use crate::symm::Cipher;
use crate::{cvt, cvt_p};
use foreign_types::{ForeignType, ForeignTypeRef};
use libc::c_int;
use std::cmp;
use std::ptr;

/// Represents an EVP_Seal context.
pub struct Seal {
    ctx: *mut ffi::EVP_CIPHER_CTX,
    block_size: usize,
    ctx: CipherCtx,
    iv: Option<Vec<u8>>,
    enc_keys: Vec<Vec<u8>>,
}
@@ -44,45 +39,13 @@ impl Seal {
    where
        T: HasPublic,
    {
        unsafe {
            assert!(pub_keys.len() <= c_int::max_value() as usize);

            let ctx = cvt_p(ffi::EVP_CIPHER_CTX_new())?;
            let mut enc_key_ptrs = vec![];
            let mut pub_key_ptrs = vec![];
            let mut enc_keys = vec![];
            for key in pub_keys {
                let mut enc_key = vec![0; key.size()];
                let enc_key_ptr = enc_key.as_mut_ptr();
                enc_keys.push(enc_key);
                enc_key_ptrs.push(enc_key_ptr);
                pub_key_ptrs.push(key.as_ptr());
            }
        let mut iv = cipher.iv_len().map(|len| vec![0; len]);
            let iv_ptr = iv.as_mut().map_or(ptr::null_mut(), |v| v.as_mut_ptr());
            let mut enc_key_lens = vec![0; enc_keys.len()];

            cvt(ffi::EVP_SealInit(
                ctx,
                cipher.as_ptr(),
                enc_key_ptrs.as_mut_ptr(),
                enc_key_lens.as_mut_ptr(),
                iv_ptr,
                pub_key_ptrs.as_mut_ptr(),
                pub_key_ptrs.len() as c_int,
            ))?;
        let mut enc_keys = vec![vec![]; pub_keys.len()];

            for (buf, len) in enc_keys.iter_mut().zip(&enc_key_lens) {
                buf.truncate(*len as usize);
            }
        let mut ctx = CipherCtx::new()?;
        ctx.seal_init(Some(&cipher), pub_keys, &mut enc_keys, iv.as_deref_mut())?;

            Ok(Seal {
                ctx,
                block_size: cipher.block_size(),
                iv,
                enc_keys,
            })
        }
        Ok(Seal { ctx, iv, enc_keys })
    }

    /// Returns the initialization vector, if the cipher uses one.
@@ -107,20 +70,7 @@ impl Seal {
    /// the block size of the cipher (see `Cipher::block_size`), or if
    /// `output.len() > c_int::max_value()`.
    pub fn update(&mut self, input: &[u8], output: &mut [u8]) -> Result<usize, ErrorStack> {
        unsafe {
            assert!(output.len() >= input.len() + self.block_size);
            assert!(output.len() <= c_int::max_value() as usize);
            let mut outl = output.len() as c_int;
            let inl = input.len() as c_int;
            cvt(ffi::EVP_EncryptUpdate(
                self.ctx,
                output.as_mut_ptr(),
                &mut outl,
                input.as_ptr(),
                inl,
            ))?;
            Ok(outl as usize)
        }
        self.ctx.update(input, Some(output))
    }

    /// Finishes the encryption process, writing any remaining data to `output`.
@@ -133,29 +83,13 @@ impl Seal {
    ///
    /// Panics if `output` is less than the cipher's block size.
    pub fn finalize(&mut self, output: &mut [u8]) -> Result<usize, ErrorStack> {
        unsafe {
            assert!(output.len() >= self.block_size);
            let mut outl = cmp::min(output.len(), c_int::max_value() as usize) as c_int;

            cvt(ffi::EVP_SealFinal(self.ctx, output.as_mut_ptr(), &mut outl))?;

            Ok(outl as usize)
        }
    }
}

impl Drop for Seal {
    fn drop(&mut self) {
        unsafe {
            ffi::EVP_CIPHER_CTX_free(self.ctx);
        }
        self.ctx.finalize(output)
    }
}

/// Represents an EVP_Open context.
pub struct Open {
    ctx: *mut ffi::EVP_CIPHER_CTX,
    block_size: usize,
    ctx: CipherCtx,
}

impl Open {
@@ -169,29 +103,10 @@ impl Open {
    where
        T: HasPrivate,
    {
        unsafe {
            assert!(encrypted_key.len() <= c_int::max_value() as usize);
            match (cipher.iv_len(), iv) {
                (Some(len), Some(iv)) => assert_eq!(len, iv.len(), "IV length mismatch"),
                (None, None) => {}
                (Some(_), None) => panic!("an IV was required but not provided"),
                (None, Some(_)) => panic!("an IV was provided but not required"),
            }
        let mut ctx = CipherCtx::new()?;
        ctx.open_init(Some(&cipher), encrypted_key, iv, Some(priv_key))?;

            let ctx = cvt_p(ffi::EVP_CIPHER_CTX_new())?;
            cvt(ffi::EVP_OpenInit(
                ctx,
                cipher.as_ptr(),
                encrypted_key.as_ptr(),
                encrypted_key.len() as c_int,
                iv.map_or(ptr::null(), |v| v.as_ptr()),
                priv_key.as_ptr(),
            ))?;
            Ok(Open {
                ctx,
                block_size: cipher.block_size(),
            })
        }
        Ok(Open { ctx })
    }

    /// Feeds data from `input` through the cipher, writing decrypted bytes into `output`.
@@ -205,20 +120,7 @@ impl Open {
    /// `block_size` is the block size of the cipher (see `Cipher::block_size`),
    /// or if `output.len() > c_int::max_value()`.
    pub fn update(&mut self, input: &[u8], output: &mut [u8]) -> Result<usize, ErrorStack> {
        unsafe {
            assert!(output.len() >= input.len() + self.block_size);
            assert!(output.len() <= c_int::max_value() as usize);
            let mut outl = output.len() as c_int;
            let inl = input.len() as c_int;
            cvt(ffi::EVP_DecryptUpdate(
                self.ctx,
                output.as_mut_ptr(),
                &mut outl,
                input.as_ptr(),
                inl,
            ))?;
            Ok(outl as usize)
        }
        self.ctx.update(input, Some(output))
    }

    /// Finishes the decryption process, writing any remaining data to `output`.
@@ -231,22 +133,7 @@ impl Open {
    ///
    /// Panics if `output` is less than the cipher's block size.
    pub fn finalize(&mut self, output: &mut [u8]) -> Result<usize, ErrorStack> {
        unsafe {
            assert!(output.len() >= self.block_size);
            let mut outl = cmp::min(output.len(), c_int::max_value() as usize) as c_int;

            cvt(ffi::EVP_OpenFinal(self.ctx, output.as_mut_ptr(), &mut outl))?;

            Ok(outl as usize)
        }
    }
}

impl Drop for Open {
    fn drop(&mut self) {
        unsafe {
            ffi::EVP_CIPHER_CTX_free(self.ctx);
        }
        self.ctx.finalize(output)
    }
}

+2 −2
Original line number Diff line number Diff line
@@ -451,7 +451,7 @@ impl Crypter {
        iv: Option<&[u8]>,
    ) -> Result<Crypter, ErrorStack> {
        let mut ctx = CipherCtx::new()?;
        ctx.init(Some(&t), None, None, mode)?;
        ctx.cipher_init(Some(&t), None, None, mode)?;

        ctx.set_key_length(key.len())?;

@@ -459,7 +459,7 @@ impl Crypter {
            ctx.set_iv_length(iv.len())?;
        }

        ctx.init(None, Some(key), iv, mode)?;
        ctx.cipher_init(None, Some(key), iv, mode)?;

        Ok(Crypter { ctx })
    }