blob: c9a0f99c6bf063b8ec5997b137758fafe1d96efa [file] [log] [blame]
// Copyright 2021 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// The `cxx` crate's expanded code appears to trigger this elided lifetimes in paths warning
#![allow(elided_lifetimes_in_paths)]
#![allow(dead_code)]
use cxx::UniquePtr;
use fuchsia_zircon_sys as sys;
use std::pin::Pin;
#[cxx::bridge(namespace = "crypto")]
mod ffi {
// No shared structs
unsafe extern "C++" {
// C++ declarations
include!("src/security/fcrypto-rust/ffi.h");
type Cipher;
fn new_cipher() -> UniquePtr<Cipher>;
fn init_for_encipher(
cipher: Pin<&mut Cipher>,
secret: &[u8],
iv: &[u8],
alignment: u64,
) -> i32;
fn init_for_decipher(
cipher: Pin<&mut Cipher>,
secret: &[u8],
iv: &[u8],
alignment: u64,
) -> i32;
fn encipher(
cipher: Pin<&mut Cipher>,
plaintext: &[u8],
offset: u64,
ciphertext: &mut [u8],
) -> i32;
fn decipher(
cipher: Pin<&mut Cipher>,
plaintext: &[u8],
offset: u64,
ciphertext: &mut [u8],
) -> i32;
}
}
pub struct Aes256XtsCipher {
encipherer: Aes256XtsEncipherer,
decipherer: Aes256XtsDecipherer,
}
// TODO: make these failures return a better error type than i32
impl Aes256XtsCipher {
pub fn new(secret: &[u8], iv: &[u8]) -> Result<Aes256XtsCipher, i32> {
// Allocate a pair of C++ Cipher objects.
let encipher_inner = ffi::new_cipher();
let decipher_inner = ffi::new_cipher();
let mut encipherer = Aes256XtsEncipherer { inner: encipher_inner };
let mut decipherer = Aes256XtsDecipherer { inner: decipher_inner };
encipherer.init(secret, iv)?;
decipherer.init(secret, iv)?;
Ok(Aes256XtsCipher { encipherer, decipherer })
}
pub fn encrypt(&mut self, offset: u64, plaintext: &[u8], ciphertext: &mut [u8]) -> Result<(), i32> {
self.encipherer.encipher(offset, plaintext, ciphertext)
}
pub fn decrypt(&mut self, offset: u64, ciphertext: &[u8], plaintext: &mut [u8]) -> Result<(), i32> {
self.decipherer.decipher(offset, ciphertext, plaintext)
}
}
pub struct Aes256XtsEncipherer {
inner: UniquePtr<ffi::Cipher>,
}
pub struct Aes256XtsDecipherer {
inner: UniquePtr<ffi::Cipher>,
}
const ALIGN: u64 = 128;
impl Aes256XtsEncipherer {
fn init(&mut self, secret: &[u8], iv: &[u8]) -> Result<(), i32> {
let mut cref = self.inner.as_mut().ok_or(sys::ZX_ERR_INVALID_ARGS)?;
let res = ffi::init_for_encipher(Pin::as_mut(&mut cref), secret, iv, ALIGN);
if res == 0 {
Ok(())
} else {
Err(res)
}
}
fn encipher(&mut self, offset: u64, plaintext: &[u8], ciphertext: &mut [u8]) -> Result<(), i32> {
assert!(plaintext.len() == ciphertext.len());
let mut cref = self.inner.as_mut().ok_or(sys::ZX_ERR_INVALID_ARGS)?;
let res = ffi::encipher(Pin::as_mut(&mut cref), plaintext, offset, ciphertext);
if res == 0 {
Ok(())
} else {
Err(res)
}
}
}
impl Aes256XtsDecipherer {
fn init(&mut self, secret: &[u8], iv: &[u8]) -> Result<(), i32> {
let mut cref = self.inner.as_mut().ok_or(sys::ZX_ERR_INVALID_ARGS)?;
let res = ffi::init_for_decipher(Pin::as_mut(&mut cref), secret, iv, ALIGN);
if res == 0 {
Ok(())
} else {
Err(res)
}
}
fn decipher(&mut self, offset: u64, ciphertext: &[u8], plaintext: &mut [u8]) -> Result<(), i32> {
assert!(plaintext.len() == ciphertext.len());
let mut cref = self.inner.as_mut().ok_or(sys::ZX_ERR_INVALID_ARGS)?;
let res = ffi::decipher(Pin::as_mut(&mut cref), ciphertext, offset, plaintext);
if res == 0 {
Ok(())
} else {
Err(res)
}
}
}