pub mod tpm;
pub mod merkle_stream;
pub mod x509;
pub use merkle_stream::MerkleStream;
pub mod secret_stream;
pub use secret_stream::SecretStream;
mod envelope;
pub mod file_cred_store;
pub use envelope::Envelope;
use crate::{
btensure, bterr, fmt, io, BigArray, BlockError, BlockMeta, BlockPath, Deserialize, Epoch,
Formatter, Hashable, Principal, Principaled, Result, Serialize, Writecap, WritecapBody,
};
use btserde::{self, from_vec, to_vec, write_to};
use foreign_types::ForeignType;
use log::error;
use openssl::{
encrypt::{Decrypter as OsslDecrypter, Encrypter as OsslEncrypter},
error::ErrorStack,
hash::{hash, DigestBytes, Hasher, MessageDigest},
nid::Nid,
pkcs5::pbkdf2_hmac,
pkey::{HasPrivate, HasPublic, PKey, PKeyRef},
rand::rand_bytes,
rsa::{Padding as OpensslPadding, Rsa as OsslRsa},
sign::{Signer as OsslSigner, Verifier as OsslVerifier},
symm::{decrypt as openssl_decrypt, encrypt as openssl_encrypt, Cipher, Crypter, Mode},
};
use serde::{
de::{self, DeserializeOwned, Deserializer, SeqAccess, Visitor},
ser::{Error as SerError, SerializeStruct, Serializer},
};
use std::{
cell::RefCell,
fmt::Display,
io::{Read, Write},
marker::PhantomData,
ops::{Deref, DerefMut},
sync::Arc,
};
use strum_macros::{Display, EnumDiscriminants, FromRepr};
use zeroize::{ZeroizeOnDrop, Zeroizing};
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Clone)]
pub struct Ciphertext<T> {
data: Vec<u8>,
phantom: PhantomData<T>,
}
impl<T> Ciphertext<T> {
fn new(data: Vec<u8>) -> Ciphertext<T> {
Ciphertext {
data,
phantom: PhantomData,
}
}
}
pub struct Signed<T> {
_data: Vec<u8>,
sig: Signature,
phantom: PhantomData<T>,
}
impl<T> Signed<T> {
fn new(data: Vec<u8>, sig: Signature) -> Signed<T> {
Signed {
_data: data,
sig,
phantom: PhantomData,
}
}
}
#[derive(Debug)]
pub enum Error {
NoReadCap,
NoKeyAvailable,
MissingPrivateKey,
KeyVariantUnsupported,
BlockNotEncrypted,
InvalidHashFormat,
InvalidSignature,
IncorrectSize {
expected: usize,
actual: usize,
},
TooSmall {
required: usize,
actual: usize,
},
IndexOutOfBounds {
index: usize,
limit: usize,
},
IndivisibleSize {
divisor: usize,
actual: usize,
},
InvalidOffset {
actual: usize,
limit: usize,
},
HashCmpFailure,
RootHashNotVerified,
SignatureMismatch(Box<SignatureMismatch>),
Library(Box<dyn ::std::error::Error + Send + Sync + 'static>),
OpAlreadyFinished,
NotIssuedTo,
NoRootCreds,
WrongRootPassword,
}
impl Error {
fn signature_mismatch(expected: Principal, actual: Principal) -> Error {
Error::SignatureMismatch(Box::new(SignatureMismatch { expected, actual }))
}
fn library<E: std::error::Error + Send + Sync + 'static>(err: E) -> Error {
Error::Library(Box::new(err))
}
}
impl Display for Error {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
Error::NoReadCap => write!(f, "no readcap"),
Error::NoKeyAvailable => write!(f, "no key available"),
Error::MissingPrivateKey => write!(f, "private key was missing"),
Error::KeyVariantUnsupported => write!(f, "unsupported key variant"),
Error::BlockNotEncrypted => write!(f, "block was not encrypted"),
Error::InvalidHashFormat => write!(f, "invalid format"),
Error::InvalidSignature => write!(f, "invalid signature"),
Error::IncorrectSize { expected, actual } => {
write!(f, "expected size {expected} but got {actual}")
}
Error::TooSmall { required, actual } => {
write!(f, "expected at least {required} but got {actual}")
}
Error::IndexOutOfBounds { index, limit } => write!(
f,
"index {index} is out of bounds, it must be strictly less than {limit}",
),
Error::IndivisibleSize { divisor, actual } => write!(
f,
"expected a size which is divisible by {divisor} but got {actual}",
),
Error::InvalidOffset { actual, limit } => write!(
f,
"offset {actual} is out of bounds, it must be strictly less than {limit}",
),
Error::HashCmpFailure => write!(f, "hash data are not equal"),
Error::RootHashNotVerified => write!(f, "root hash is not verified"),
Error::SignatureMismatch(mismatch) => {
let actual = &mismatch.actual;
let expected = &mismatch.expected;
write!(
f,
"expected a signature from {expected} but found one from {actual}"
)
}
Error::Library(err) => err.fmt(f),
Error::OpAlreadyFinished => write!(f, "operation is already finished"),
Error::NotIssuedTo => write!(f, "writecap was not issued to the given principal"),
Error::NoRootCreds => write!(f, "root creds are not present"),
Error::WrongRootPassword => write!(f, "incorrect root password"),
}
}
}
impl std::error::Error for Error {}
impl From<ErrorStack> for Error {
fn from(error: ErrorStack) -> Error {
Error::library(error)
}
}
#[derive(Debug)]
pub struct SignatureMismatch {
pub actual: Principal,
pub expected: Principal,
}
pub fn rand_array<const LEN: usize>() -> Result<[u8; LEN]> {
let mut array = [0; LEN];
rand_bytes(&mut array)?;
Ok(array)
}
pub fn rand_vec(len: usize) -> Result<Vec<u8>> {
let mut vec = vec![0; len];
rand_bytes(&mut vec)?;
Ok(vec)
}
pub trait Op {
fn update(&mut self, data: &[u8]) -> Result<()>;
fn finish_into(&mut self, buf: &mut [u8]) -> Result<usize>;
}
impl<T: ?Sized + Op, P: DerefMut<Target = T>> Op for P {
fn update(&mut self, data: &[u8]) -> Result<()> {
self.deref_mut().update(data)
}
fn finish_into(&mut self, buf: &mut [u8]) -> Result<usize> {
self.deref_mut().finish_into(buf)
}
}
pub trait HashOp: Op {
type Hash: Hash;
fn kind(&self) -> HashKind;
fn finish(&mut self) -> Result<Self::Hash>;
}
pub struct OsslHashOp<H> {
hasher: Hasher,
phantom: PhantomData<H>,
kind: HashKind,
}
impl<H> OsslHashOp<H> {
fn new(arg: HashKind) -> Result<Self> {
let hasher = Hasher::new(arg.into())?;
let phantom = PhantomData;
Ok(OsslHashOp {
hasher,
phantom,
kind: arg,
})
}
}
impl<H> Op for OsslHashOp<H> {
fn update(&mut self, data: &[u8]) -> Result<()> {
Ok(self.hasher.update(data)?)
}
fn finish_into(&mut self, buf: &mut [u8]) -> Result<usize> {
if buf.len() < self.kind.len() {
return Err(bterr!(Error::IncorrectSize {
expected: self.kind.len(),
actual: buf.len(),
}));
}
let digest = self.hasher.finish()?;
let slice = digest.as_ref();
buf.copy_from_slice(slice);
Ok(slice.len())
}
}
impl<H: Hash + From<DigestBytes>> HashOp for OsslHashOp<H> {
type Hash = H;
fn kind(&self) -> HashKind {
self.kind
}
fn finish(&mut self) -> Result<Self::Hash> {
let digest = self.hasher.finish()?;
Ok(H::from(digest))
}
}
pub struct HashStream<T, Op: HashOp> {
inner: T,
op: Op,
update_failed: bool,
}
impl<T, Op: HashOp> HashStream<T, Op> {
pub fn new(inner: T, op: Op) -> HashStream<T, Op> {
HashStream {
inner,
op,
update_failed: false,
}
}
pub fn finish_into(&mut self, buf: &mut [u8]) -> Result<usize> {
if self.update_failed {
return Err(bterr!(
"HashStream::finish_into can't produce result due to HashOp update failure",
));
}
self.op.finish_into(buf)
}
pub fn finish(&mut self) -> Result<Op::Hash> {
if self.update_failed {
return Err(bterr!(
"HashStream::finish can't produce result due to HashOp update failure",
));
}
self.op.finish()
}
}
impl<T: Read, Op: HashOp> Read for HashStream<T, Op> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
if self.update_failed {
return Err(bterr!(
"HashStream::read can't continue due to previous HashOp update failure",
)
.into());
}
let read = self.inner.read(buf)?;
if read > 0 {
if let Err(err) = self.op.update(&buf[..read]) {
self.update_failed = true;
error!("HashWrap::read failed to update HashOp: {}", err);
}
}
Ok(read)
}
}
impl<T: Write, Op: HashOp> Write for HashStream<T, Op> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.op.update(buf)?;
self.inner.write(buf)
}
fn flush(&mut self) -> io::Result<()> {
self.inner.flush()
}
}
pub trait Hash: AsRef<[u8]> + AsMut<[u8]> + Sized {
type Op: HashOp;
type Arg;
fn new(arg: Self::Arg) -> Self;
fn kind(&self) -> HashKind;
fn start_op(&self) -> Result<Self::Op>;
}
pub trait DefaultHash: Hash {
fn default() -> Self;
}
impl<A: Default, T: Hash<Arg = A>> DefaultHash for T {
fn default() -> Self {
Self::new(A::default())
}
}
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, Hashable, Clone)]
pub struct Sha2_256([u8; Self::LEN]);
impl Sha2_256 {
pub const KIND: HashKind = HashKind::Sha2_256;
pub const LEN: usize = Self::KIND.len();
}
impl AsRef<[u8]> for Sha2_256 {
fn as_ref(&self) -> &[u8] {
self.0.as_slice()
}
}
impl AsMut<[u8]> for Sha2_256 {
fn as_mut(&mut self) -> &mut [u8] {
self.0.as_mut_slice()
}
}
impl From<DigestBytes> for Sha2_256 {
fn from(value: DigestBytes) -> Self {
let mut hash = Sha2_256::new(());
hash.as_mut().copy_from_slice(value.as_ref());
hash
}
}
impl From<[u8; Self::LEN]> for Sha2_256 {
fn from(value: [u8; Self::LEN]) -> Self {
Sha2_256(value)
}
}
impl From<Sha2_256> for [u8; Sha2_256::LEN] {
fn from(value: Sha2_256) -> Self {
value.0
}
}
impl Hash for Sha2_256 {
type Op = OsslHashOp<Sha2_256>;
type Arg = ();
fn new(_: Self::Arg) -> Self {
Sha2_256([0u8; Self::KIND.len()])
}
fn kind(&self) -> HashKind {
Self::KIND
}
fn start_op(&self) -> Result<Self::Op> {
OsslHashOp::new(Self::KIND)
}
}
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, Hashable, Clone)]
pub struct Sha2_512(#[serde(with = "BigArray")] [u8; Self::LEN]);
impl Sha2_512 {
pub const KIND: HashKind = HashKind::Sha2_512;
pub const LEN: usize = Self::KIND.len();
}
impl AsRef<[u8]> for Sha2_512 {
fn as_ref(&self) -> &[u8] {
self.0.as_slice()
}
}
impl AsMut<[u8]> for Sha2_512 {
fn as_mut(&mut self) -> &mut [u8] {
self.0.as_mut_slice()
}
}
impl From<DigestBytes> for Sha2_512 {
fn from(value: DigestBytes) -> Self {
let mut hash = Sha2_512::new(());
hash.as_mut().copy_from_slice(value.as_ref());
hash
}
}
impl From<[u8; Self::LEN]> for Sha2_512 {
fn from(value: [u8; Self::LEN]) -> Self {
Self(value)
}
}
impl From<Sha2_512> for [u8; Sha2_512::LEN] {
fn from(value: Sha2_512) -> Self {
value.0
}
}
impl Hash for Sha2_512 {
type Op = OsslHashOp<Sha2_512>;
type Arg = ();
fn new(_: Self::Arg) -> Self {
Sha2_512([0u8; Self::LEN])
}
fn kind(&self) -> HashKind {
Self::KIND
}
fn start_op(&self) -> Result<Self::Op> {
OsslHashOp::new(Self::KIND)
}
}
#[derive(
Debug,
PartialEq,
Eq,
Serialize,
Deserialize,
Hashable,
Clone,
EnumDiscriminants,
PartialOrd,
Ord,
)]
#[strum_discriminants(derive(FromRepr, Display, Serialize, Deserialize))]
#[strum_discriminants(name(HashKind))]
pub enum VarHash {
Sha2_256(Sha2_256),
Sha2_512(Sha2_512),
}
impl VarHash {
const HASH_SEP: char = '!';
pub fn kind(&self) -> HashKind {
self.into()
}
pub fn as_slice(&self) -> &[u8] {
self.as_ref()
}
pub fn as_mut_slice(&mut self) -> &mut [u8] {
self.as_mut()
}
}
impl From<HashKind> for VarHash {
fn from(kind: HashKind) -> VarHash {
match kind {
HashKind::Sha2_256 => VarHash::Sha2_256(Sha2_256::default()),
HashKind::Sha2_512 => VarHash::Sha2_512(Sha2_512::default()),
}
}
}
impl AsRef<[u8]> for VarHash {
fn as_ref(&self) -> &[u8] {
match self {
VarHash::Sha2_256(arr) => arr.as_ref(),
VarHash::Sha2_512(arr) => arr.as_ref(),
}
}
}
impl AsMut<[u8]> for VarHash {
fn as_mut(&mut self) -> &mut [u8] {
match self {
VarHash::Sha2_256(arr) => arr.as_mut(),
VarHash::Sha2_512(arr) => arr.as_mut(),
}
}
}
impl TryFrom<MessageDigest> for VarHash {
type Error = crate::Error;
fn try_from(value: MessageDigest) -> Result<Self> {
let kind: HashKind = value.try_into()?;
Ok(kind.into())
}
}
impl Hash for VarHash {
type Op = VarHashOp;
type Arg = HashKind;
fn new(arg: Self::Arg) -> Self {
arg.into()
}
fn kind(&self) -> HashKind {
self.kind()
}
fn start_op(&self) -> Result<Self::Op> {
VarHashOp::new(self.kind())
}
}
impl TryFrom<&str> for VarHash {
type Error = crate::Error;
fn try_from(string: &str) -> Result<VarHash> {
let mut split: Vec<&str> = string.split(Self::HASH_SEP).collect();
if split.len() != 2 {
return Err(bterr!(Error::InvalidHashFormat));
};
let second = split.pop().ok_or(Error::InvalidHashFormat)?;
let first = split
.pop()
.ok_or(Error::InvalidHashFormat)?
.parse::<usize>()
.map_err(|_| Error::InvalidHashFormat)?;
let mut hash = VarHash::from(HashKind::from_repr(first).ok_or(Error::InvalidHashFormat)?);
base64_url::decode_to_slice(second, hash.as_mut()).map_err(|_| Error::InvalidHashFormat)?;
Ok(hash)
}
}
impl Display for VarHash {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let hash_kind: HashKind = self.into();
let hash_data = base64_url::encode(self.as_ref());
write!(f, "{}{}{hash_data}", hash_kind as u32, VarHash::HASH_SEP)
}
}
#[allow(clippy::derivable_impls)]
impl Default for HashKind {
fn default() -> HashKind {
HashKind::Sha2_256
}
}
impl Default for VarHash {
fn default() -> Self {
HashKind::default().into()
}
}
impl HashKind {
#[allow(clippy::len_without_is_empty)]
pub const fn len(self) -> usize {
match self {
HashKind::Sha2_256 => 32,
HashKind::Sha2_512 => 64,
}
}
pub fn digest<'a, I: Iterator<Item = &'a [u8]>>(self, dest: &mut [u8], parts: I) -> Result<()> {
btensure!(
dest.len() >= self.len(),
Error::TooSmall {
required: self.len(),
actual: dest.len(),
}
);
let mut hasher = Hasher::new(self.into())?;
for part in parts {
hasher.update(part)?;
}
let hash = hasher.finish()?;
dest[..self.len()].copy_from_slice(&hash);
Ok(())
}
}
pub struct BtHasher {
hasher: RefCell<Hasher>,
}
impl BtHasher {
pub fn new(kind: HashKind) -> Result<Self> {
btensure!(
kind.len() >= 8,
bterr!("only digests which produce at least 8 bytes are supported")
);
let hasher = RefCell::new(Hasher::new(kind.into())?);
Ok(Self { hasher })
}
}
impl std::hash::Hasher for BtHasher {
fn write(&mut self, bytes: &[u8]) {
let hasher = self.hasher.get_mut();
hasher.update(bytes).unwrap();
}
fn finish(&self) -> u64 {
let mut hasher = self.hasher.borrow_mut();
let hash = hasher.finish().unwrap();
let mut buf = [0u8; 8];
buf.copy_from_slice(&hash[..8]);
u64::from_le_bytes(buf)
}
fn write_u8(&mut self, i: u8) {
self.write(&[i])
}
fn write_u16(&mut self, i: u16) {
self.write(&i.to_le_bytes())
}
fn write_u32(&mut self, i: u32) {
self.write(&i.to_le_bytes())
}
fn write_u64(&mut self, i: u64) {
self.write(&i.to_le_bytes())
}
fn write_u128(&mut self, i: u128) {
self.write(&i.to_le_bytes())
}
fn write_usize(&mut self, i: usize) {
self.write(&i.to_le_bytes())
}
fn write_i8(&mut self, i: i8) {
self.write_u8(i as u8)
}
fn write_i16(&mut self, i: i16) {
self.write_u16(i as u16)
}
fn write_i32(&mut self, i: i32) {
self.write_u32(i as u32)
}
fn write_i64(&mut self, i: i64) {
self.write_u64(i as u64)
}
fn write_i128(&mut self, i: i128) {
self.write_u128(i as u128)
}
fn write_isize(&mut self, i: isize) {
self.write_usize(i as usize)
}
}
impl TryFrom<MessageDigest> for HashKind {
type Error = crate::Error;
fn try_from(value: MessageDigest) -> Result<Self> {
let nid = value.type_();
if Nid::SHA256 == nid {
Ok(HashKind::Sha2_256)
} else if Nid::SHA512 == nid {
Ok(HashKind::Sha2_512)
} else {
Err(bterr!("Unsupported MessageDigest with NID: {:?}", nid))
}
}
}
impl From<HashKind> for MessageDigest {
fn from(kind: HashKind) -> Self {
match kind {
HashKind::Sha2_256 => MessageDigest::sha256(),
HashKind::Sha2_512 => MessageDigest::sha512(),
}
}
}
pub struct VarHashOp {
kind: HashKind,
hasher: Hasher,
}
impl VarHashOp {
pub fn new(arg: HashKind) -> Result<Self> {
let hasher = Hasher::new(arg.into())?;
Ok(VarHashOp { kind: arg, hasher })
}
}
impl Op for VarHashOp {
fn update(&mut self, data: &[u8]) -> Result<()> {
Ok(self.hasher.update(data)?)
}
fn finish_into(&mut self, buf: &mut [u8]) -> Result<usize> {
btensure!(
buf.len() >= self.kind.len(),
bterr!(Error::IncorrectSize {
expected: self.kind.len(),
actual: buf.len(),
})
);
let digest = self.hasher.finish()?;
let slice = digest.as_ref();
buf.copy_from_slice(slice);
Ok(slice.len())
}
}
impl HashOp for VarHashOp {
type Hash = VarHash;
fn kind(&self) -> HashKind {
self.kind
}
fn finish(&mut self) -> Result<Self::Hash> {
let digest = self.hasher.finish()?;
let mut hash: VarHash = self.kind.into();
hash.as_mut().copy_from_slice(digest.as_ref());
Ok(hash)
}
}
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Clone, Default)]
pub struct Signature {
kind: Sign,
data: Vec<u8>,
}
impl Signature {
pub fn new(kind: Sign, data: Vec<u8>) -> Self {
Self { kind, data }
}
pub fn empty(kind: Sign) -> Signature {
let data = vec![0; kind.key_len() as usize];
Signature { kind, data }
}
pub fn copy_from(kind: Sign, from: &[u8]) -> Signature {
let mut data = vec![0; kind.key_len() as usize];
data.as_mut_slice().copy_from_slice(from);
Signature { kind, data }
}
pub fn as_slice(&self) -> &[u8] {
self.data.as_slice()
}
pub fn as_mut_slice(&mut self) -> &mut [u8] {
self.data.as_mut_slice()
}
pub fn scheme(&self) -> Sign {
self.kind
}
pub fn take_data(self) -> Vec<u8> {
self.data
}
}
impl AsRef<[u8]> for Signature {
fn as_ref(&self) -> &[u8] {
self.as_slice()
}
}
impl AsMut<[u8]> for Signature {
fn as_mut(&mut self) -> &mut [u8] {
self.as_mut_slice()
}
}
#[derive(Serialize, Deserialize)]
pub struct TaggedCiphertext<T, U> {
aad: U,
ciphertext: Ciphertext<T>,
tag: Vec<u8>,
}
#[derive(EnumDiscriminants, ZeroizeOnDrop, Serialize, Deserialize, PartialEq, Eq)]
#[strum_discriminants(name(AeadKeyKind))]
#[strum_discriminants(derive(Serialize, Deserialize))]
pub enum AeadKey {
AesGcm256 {
key: [u8; AeadKeyKind::AesGcm256.key_len()],
iv: [u8; AeadKeyKind::AesGcm256.iv_len()],
},
}
impl AeadKeyKind {
const fn key_len(self) -> usize {
match self {
AeadKeyKind::AesGcm256 => 32,
}
}
const fn iv_len(self) -> usize {
match self {
AeadKeyKind::AesGcm256 => 16,
}
}
}
#[derive(Serialize, Deserialize)]
pub struct DerivationParams {
iter: usize,
hash: HashKind,
kind: AeadKeyKind,
salt: Vec<u8>,
iv: Vec<u8>,
}
impl DerivationParams {
const PBKDF2_ITER: usize = 1000000;
const PBKDF2_HASH: HashKind = HashKind::Sha2_256;
pub const EXPORT_KEY_KIND: AeadKeyKind = AeadKeyKind::AesGcm256;
pub fn new() -> Result<DerivationParams> {
const_assert!(
DerivationParams::PBKDF2_HASH.len() == DerivationParams::EXPORT_KEY_KIND.key_len()
);
Ok(DerivationParams {
iter: Self::PBKDF2_ITER,
hash: Self::PBKDF2_HASH,
kind: Self::EXPORT_KEY_KIND,
salt: rand_vec(Self::PBKDF2_HASH.len())?,
iv: rand_vec(Self::EXPORT_KEY_KIND.iv_len())?,
})
}
pub fn hmac(&self, password: &str) -> Result<Zeroizing<[u8; Self::EXPORT_KEY_KIND.key_len()]>> {
let mut key = Zeroizing::new([0u8; Self::EXPORT_KEY_KIND.key_len()]);
pbkdf2_hmac(
password.as_bytes(),
self.salt.as_slice(),
self.iter,
self.hash.into(),
key.as_mut_slice(),
)?;
Ok(key)
}
fn derive_key(&self, password: &str) -> Result<AeadKey> {
let key = self.hmac(password)?;
AeadKey::copy_components(self.kind, key.as_slice(), &self.iv)
}
}
fn array_from<const N: usize>(slice: &[u8]) -> Result<[u8; N]> {
let slice_len = slice.len();
btensure!(
N == slice_len,
Error::IncorrectSize {
actual: slice_len,
expected: N,
}
);
let mut array = [0u8; N];
array.copy_from_slice(slice);
Ok(array)
}
impl AeadKey {
pub fn new(kind: AeadKeyKind) -> Result<AeadKey> {
match kind {
AeadKeyKind::AesGcm256 => Ok(AeadKey::AesGcm256 {
key: rand_array()?,
iv: rand_array()?,
}),
}
}
fn copy_components(kind: AeadKeyKind, key_buf: &[u8], iv_buf: &[u8]) -> Result<AeadKey> {
match kind {
AeadKeyKind::AesGcm256 => Ok(AeadKey::AesGcm256 {
key: array_from(key_buf)?,
iv: array_from(iv_buf)?,
}),
}
}
fn encrypt<T: Serialize + DeserializeOwned, U: Serialize + DeserializeOwned>(
&self,
aad: U,
plaintext: &T,
) -> Result<TaggedCiphertext<T, U>> {
let (cipher, key, iv, mut tag) = match self {
AeadKey::AesGcm256 { key, iv } => (
Cipher::aes_256_gcm(),
key.as_slice(),
iv.as_slice(),
vec![0u8; 16],
),
};
let aad_data = to_vec(&aad)?;
let plaintext_buf = to_vec(&plaintext)?;
let mut ciphertext = vec![0u8; plaintext_buf.len() + cipher.block_size()];
let mut crypter = Crypter::new(cipher, Mode::Encrypt, key, Some(iv))?;
crypter.aad_update(&aad_data)?;
let mut count = crypter.update(&plaintext_buf, &mut ciphertext)?;
count += crypter.finalize(&mut ciphertext[count..])?;
ciphertext.truncate(count);
crypter.get_tag(&mut tag)?;
Ok(TaggedCiphertext {
aad,
ciphertext: Ciphertext::new(ciphertext),
tag,
})
}
fn decrypt<T: Serialize + DeserializeOwned, U: Serialize + DeserializeOwned>(
&self,
tagged: &TaggedCiphertext<T, U>,
) -> Result<T> {
let ciphertext = &tagged.ciphertext.data;
let (cipher, key, iv) = match self {
AeadKey::AesGcm256 { key, iv } => {
(Cipher::aes_256_gcm(), key.as_slice(), iv.as_slice())
}
};
let mut plaintext = vec![0u8; ciphertext.len() + cipher.block_size()];
let mut crypter = Crypter::new(cipher, Mode::Decrypt, key, Some(iv))?;
crypter.set_tag(&tagged.tag)?;
let aad_buf = to_vec(&tagged.aad)?;
crypter.aad_update(&aad_buf)?;
let mut count = crypter.update(ciphertext, &mut plaintext)?;
count += crypter.finalize(&mut plaintext[count..])?;
plaintext.truncate(count);
Ok(from_vec(&plaintext)?)
}
}
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Clone, EnumDiscriminants, ZeroizeOnDrop)]
#[strum_discriminants(name(SymKeyKind))]
pub enum SymKey {
Aes256Cbc { key: [u8; 32], iv: [u8; 16] },
Aes256Ctr { key: [u8; 32], iv: [u8; 16] },
}
struct SymParams<'a> {
cipher: Cipher,
key: &'a [u8],
iv: Option<&'a [u8]>,
}
impl SymKey {
pub(crate) fn generate(kind: SymKeyKind) -> Result<SymKey> {
match kind {
SymKeyKind::Aes256Cbc => Ok(SymKey::Aes256Cbc {
key: rand_array()?,
iv: rand_array()?,
}),
SymKeyKind::Aes256Ctr => Ok(SymKey::Aes256Ctr {
key: rand_array()?,
iv: rand_array()?,
}),
}
}
fn params(&self) -> SymParams {
let (cipher, key, iv) = match self {
SymKey::Aes256Cbc { key, iv } => (Cipher::aes_256_cbc(), key, Some(iv.as_slice())),
SymKey::Aes256Ctr { key, iv } => (Cipher::aes_256_ctr(), key, Some(iv.as_slice())),
};
SymParams { cipher, key, iv }
}
fn block_size(&self) -> usize {
let SymParams { cipher, .. } = self.params();
cipher.block_size()
}
fn expansion_sz(&self) -> usize {
match self {
SymKey::Aes256Cbc { .. } => 16,
SymKey::Aes256Ctr { .. } => 0,
}
}
pub fn key_slice(&self) -> &[u8] {
let SymParams { key, .. } = self.params();
key
}
pub fn iv_slice(&self) -> Option<&[u8]> {
let SymParams { iv, .. } = self.params();
iv
}
}
impl Encrypter for SymKey {
fn encrypt(&self, slice: &[u8]) -> Result<Vec<u8>> {
let SymParams { cipher, key, iv } = self.params();
Ok(openssl_encrypt(cipher, key, iv, slice)?)
}
}
impl Decrypter for SymKey {
fn decrypt(&self, slice: &[u8]) -> Result<Vec<u8>> {
let SymParams { cipher, key, iv } = self.params();
Ok(openssl_decrypt(cipher, key, iv, slice)?)
}
}
#[allow(clippy::derivable_impls)]
impl Default for SymKeyKind {
fn default() -> Self {
SymKeyKind::Aes256Ctr
}
}
#[repr(u32)]
#[derive(Debug, Display, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
pub enum BitLen {
Bits128 = 16,
Bits256 = 32,
Bits512 = 64,
Bits2048 = 256,
Bits3072 = 384,
Bits4096 = 512,
}
impl BitLen {
const fn bits(self) -> u32 {
8 * self as u32
}
fn try_from_u32(value: u32) -> Result<Self> {
match value {
16 => Ok(Self::Bits128),
32 => Ok(Self::Bits256),
64 => Ok(Self::Bits512),
256 => Ok(Self::Bits2048),
384 => Ok(Self::Bits3072),
512 => Ok(Self::Bits4096),
_ => Err(bterr!("invalid KeyLen value: {value}")),
}
}
}
impl TryFrom<u32> for BitLen {
type Error = crate::Error;
fn try_from(value: u32) -> std::result::Result<Self, Self::Error> {
Self::try_from_u32(value)
}
}
pub trait Scheme:
DeserializeOwned + Serialize + Copy + std::fmt::Debug + PartialEq + Into<Self::Kind>
{
type Kind: Scheme;
fn as_enum(self) -> SchemeKind;
fn hash_kind(&self) -> HashKind;
fn padding(&self) -> Option<OpensslPadding>;
fn public_from_der(self, der: &[u8]) -> Result<PKey<Public>>;
fn private_from_der(self, der: &[u8]) -> Result<PKey<Private>>;
fn generate(self) -> Result<AsymKeyPair<Self::Kind>>;
fn key_len(self) -> BitLen;
fn message_digest(&self) -> MessageDigest {
self.hash_kind().into()
}
}
pub enum SchemeKind {
Sign(Sign),
Encrypt(Encrypt),
}
#[derive(Deserialize, Serialize, Clone, Debug, PartialEq, Eq, Copy)]
pub enum Encrypt {
RsaEsOaep(RsaEsOaep),
}
impl Scheme for Encrypt {
type Kind = Encrypt;
fn as_enum(self) -> SchemeKind {
SchemeKind::Encrypt(self)
}
fn hash_kind(&self) -> HashKind {
match self {
Encrypt::RsaEsOaep(inner) => inner.hash_kind(),
}
}
fn padding(&self) -> Option<OpensslPadding> {
match self {
Encrypt::RsaEsOaep(inner) => inner.padding(),
}
}
fn public_from_der(self, der: &[u8]) -> Result<PKey<Public>> {
match self {
Encrypt::RsaEsOaep(inner) => inner.public_from_der(der),
}
}
fn private_from_der(self, der: &[u8]) -> Result<PKey<Private>> {
match self {
Encrypt::RsaEsOaep(inner) => inner.private_from_der(der),
}
}
fn generate(self) -> Result<AsymKeyPair<Self::Kind>> {
match self {
Encrypt::RsaEsOaep(inner) => inner.generate(),
}
}
fn key_len(self) -> BitLen {
match self {
Encrypt::RsaEsOaep(inner) => inner.key_len(),
}
}
}
impl Encrypt {
pub const RSA_OAEP_2048_SHA_256: Encrypt = Encrypt::RsaEsOaep(RsaEsOaep {
key_len: BitLen::Bits2048,
hash_kind: HashKind::Sha2_256,
});
pub const RSA_OAEP_3072_SHA_256: Encrypt = Encrypt::RsaEsOaep(RsaEsOaep {
key_len: BitLen::Bits3072,
hash_kind: HashKind::Sha2_256,
});
}
#[derive(Deserialize, Serialize, Clone, Debug, PartialEq, Eq, Copy)]
pub enum Sign {
RsaSsaPss(RsaSsaPss),
}
impl Default for Sign {
fn default() -> Self {
Self::RSA_PSS_2048_SHA_256
}
}
impl Scheme for Sign {
type Kind = Sign;
fn as_enum(self) -> SchemeKind {
SchemeKind::Sign(self)
}
fn hash_kind(&self) -> HashKind {
match self {
Sign::RsaSsaPss(inner) => inner.hash_kind(),
}
}
fn padding(&self) -> Option<OpensslPadding> {
match self {
Sign::RsaSsaPss(inner) => inner.padding(),
}
}
fn public_from_der(self, der: &[u8]) -> Result<PKey<Public>> {
match self {
Sign::RsaSsaPss(inner) => inner.public_from_der(der),
}
}
fn private_from_der(self, der: &[u8]) -> Result<PKey<Private>> {
match self {
Sign::RsaSsaPss(inner) => inner.private_from_der(der),
}
}
fn generate(self) -> Result<AsymKeyPair<Self::Kind>> {
match self {
Sign::RsaSsaPss(inner) => inner.generate(),
}
}
fn key_len(self) -> BitLen {
self.key_len_const()
}
}
impl Sign {
pub const RSA_PSS_2048_SHA_256: Sign = Sign::RsaSsaPss(RsaSsaPss {
key_bits: BitLen::Bits2048,
hash_kind: HashKind::Sha2_256,
});
pub const RSA_PSS_3072_SHA_256: Sign = Sign::RsaSsaPss(RsaSsaPss {
key_bits: BitLen::Bits3072,
hash_kind: HashKind::Sha2_256,
});
const fn key_len_const(self) -> BitLen {
match self {
Sign::RsaSsaPss(inner) => inner.key_bits,
}
}
}
enum Rsa {}
impl Rsa {
const EXP: u32 = 65537; fn generate<S: Scheme>(scheme: S) -> Result<AsymKeyPair<S>> {
let key = OsslRsa::generate(scheme.key_len().bits())?;
let public_der = key.public_key_to_der()?;
let private_der = key.private_key_to_der()?;
let public = AsymKey::<Public, S>::new(scheme, &public_der)?;
let private = AsymKey::<Private, S>::new(scheme, &private_der)?;
Ok(AsymKeyPair { public, private })
}
}
#[derive(Deserialize, Serialize, Clone, Debug, PartialEq, Eq, Copy)]
pub struct RsaEsOaep {
key_len: BitLen,
hash_kind: HashKind,
}
impl Scheme for RsaEsOaep {
type Kind = Encrypt;
fn as_enum(self) -> SchemeKind {
SchemeKind::Encrypt(self.into())
}
fn hash_kind(&self) -> HashKind {
self.hash_kind
}
fn padding(&self) -> Option<OpensslPadding> {
Some(OpensslPadding::PKCS1_OAEP)
}
fn public_from_der(self, der: &[u8]) -> Result<PKey<Public>> {
Ok(PKey::public_key_from_der(der)?.conv_pub())
}
fn private_from_der(self, der: &[u8]) -> Result<PKey<Private>> {
Ok(PKey::private_key_from_der(der)?.conv_priv())
}
fn generate(self) -> Result<AsymKeyPair<Self::Kind>> {
Rsa::generate(self.into())
}
fn key_len(self) -> BitLen {
self.key_len
}
}
impl From<RsaEsOaep> for Encrypt {
fn from(scheme: RsaEsOaep) -> Self {
Encrypt::RsaEsOaep(scheme)
}
}
#[derive(Deserialize, Serialize, Clone, Debug, PartialEq, Eq, Copy)]
pub struct RsaSsaPss {
key_bits: BitLen,
hash_kind: HashKind,
}
impl Scheme for RsaSsaPss {
type Kind = Sign;
fn as_enum(self) -> SchemeKind {
SchemeKind::Sign(self.into())
}
fn hash_kind(&self) -> HashKind {
self.hash_kind
}
fn padding(&self) -> Option<OpensslPadding> {
Some(OpensslPadding::PKCS1_PSS)
}
fn public_from_der(self, der: &[u8]) -> Result<PKey<Public>> {
Ok(PKey::public_key_from_der(der)?.conv_pub())
}
fn private_from_der(self, der: &[u8]) -> Result<PKey<Private>> {
Ok(PKey::private_key_from_der(der)?.conv_priv())
}
fn generate(self) -> Result<AsymKeyPair<Self::Kind>> {
Rsa::generate(self.into())
}
fn key_len(self) -> BitLen {
self.key_bits
}
}
impl From<RsaSsaPss> for Sign {
fn from(scheme: RsaSsaPss) -> Self {
Sign::RsaSsaPss(scheme)
}
}
pub trait KeyPrivacy {}
#[derive(Clone, Debug)]
pub enum Public {}
impl KeyPrivacy for Public {}
unsafe impl HasPublic for Public {}
#[derive(Debug, Clone)]
pub enum Private {}
impl KeyPrivacy for Private {}
unsafe impl HasPrivate for Private {}
trait PKeyExt<T> {
fn conv_pkey<U>(self) -> PKey<U>;
fn conv_pub(self) -> PKey<Public>;
fn conv_priv(self) -> PKey<Private>;
}
impl<T> PKeyExt<T> for PKey<T> {
fn conv_pkey<U>(self) -> PKey<U> {
let ptr = self.as_ptr();
let new_pkey = unsafe { PKey::from_ptr(ptr) };
std::mem::forget(self);
new_pkey
}
fn conv_pub(self) -> PKey<Public> {
self.conv_pkey()
}
fn conv_priv(self) -> PKey<Private> {
self.conv_pkey()
}
}
#[derive(Debug, Clone)]
pub struct AsymKey<P, S> {
scheme: S,
pkey: PKey<P>,
}
impl<P, S: Copy> AsymKey<P, S> {
pub fn scheme(&self) -> S {
self.scheme
}
}
pub type AsymKeyPub<S> = AsymKey<Public, S>;
impl<S: Scheme> AsymKey<Public, S> {
pub(crate) fn new(scheme: S, der: &[u8]) -> Result<AsymKey<Public, S>> {
let pkey = scheme.public_from_der(der)?;
Ok(AsymKey { scheme, pkey })
}
}
impl<S: Scheme> AsymKey<Private, S> {
pub(crate) fn new(scheme: S, der: &[u8]) -> Result<AsymKey<Private, S>> {
let pkey = scheme.private_from_der(der)?;
Ok(AsymKey { scheme, pkey })
}
pub fn to_der(&self) -> Result<Vec<u8>> {
self.pkey.private_key_to_der().map_err(|err| err.into())
}
}
macro_rules! impl_asym_key_serialize {
($privacy:ty, $ser_lambda:expr) => {
impl<S: Scheme> Serialize for AsymKey<$privacy, S> {
fn serialize<T: Serializer>(&self, s: T) -> std::result::Result<T::Ok, T::Error> {
let mut struct_s = s.serialize_struct(stringify!(AsymKey), 2)?;
struct_s.serialize_field("scheme", &self.scheme)?;
let der = $ser_lambda(&self.pkey).map_err(T::Error::custom)?;
struct_s.serialize_field("pkey", der.as_slice())?;
struct_s.end()
}
}
};
}
impl_asym_key_serialize!(Public, |pkey: &PKey<Public>| pkey.public_key_to_der());
impl_asym_key_serialize!(Private, |pkey: &PKey<Private>| pkey.private_key_to_der());
macro_rules! impl_asym_key_deserialize {
($privacy:ty) => {
impl<'de, S: Scheme> Deserialize<'de> for AsymKey<$privacy, S> {
fn deserialize<D: Deserializer<'de>>(d: D) -> std::result::Result<Self, D::Error> {
const FIELDS: &[&str] = &["scheme", "pkey"];
struct StructVisitor<S: Scheme>(PhantomData<S>);
impl<'de, S: Scheme> Visitor<'de> for StructVisitor<S> {
type Value = AsymKey<$privacy, S>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_fmt(format_args!("struct {}", stringify!(AsymKey)))
}
fn visit_seq<V: SeqAccess<'de>>(
self,
mut seq: V,
) -> std::result::Result<Self::Value, V::Error> {
let scheme: S = seq
.next_element()?
.ok_or_else(|| de::Error::missing_field(FIELDS[0]))?;
let der: Vec<u8> = seq
.next_element()?
.ok_or_else(|| de::Error::missing_field(FIELDS[1]))?;
AsymKey::<$privacy, _>::new(scheme, der.as_slice())
.map_err(de::Error::custom)
}
}
d.deserialize_struct(stringify!(AsymKey), FIELDS, StructVisitor(PhantomData))
}
}
};
}
impl_asym_key_deserialize!(Public);
impl_asym_key_deserialize!(Private);
impl<S: Scheme> PartialEq for AsymKey<Public, S> {
fn eq(&self, other: &Self) -> bool {
self.scheme == other.scheme && self.pkey.public_eq(&other.pkey)
}
}
impl Principaled for AsymKey<Public, Sign> {
fn principal_of_kind(&self, kind: HashKind) -> Principal {
let der = self.pkey.public_key_to_der().unwrap();
let bytes = hash(kind.into(), der.as_slice()).unwrap();
let mut hash_buf = VarHash::from(kind);
hash_buf.as_mut().copy_from_slice(&bytes);
Principal(hash_buf)
}
}
impl Encrypter for AsymKey<Public, Encrypt> {
fn encrypt(&self, slice: &[u8]) -> Result<Vec<u8>> {
let mut encrypter = OsslEncrypter::new(&self.pkey)?;
if let Some(padding) = self.scheme.padding() {
encrypter.set_rsa_padding(padding)?;
}
{
let Encrypt::RsaEsOaep(inner) = self.scheme;
encrypter.set_rsa_oaep_md(inner.message_digest())?;
}
let buffer_len = encrypter.encrypt_len(slice)?;
let mut ciphertext = vec![0; buffer_len];
let ciphertext_len = encrypter.encrypt(slice, &mut ciphertext)?;
ciphertext.truncate(ciphertext_len);
Ok(ciphertext)
}
}
impl Decrypter for AsymKey<Private, Encrypt> {
fn decrypt(&self, slice: &[u8]) -> Result<Vec<u8>> {
let mut decrypter = OsslDecrypter::new(&self.pkey)?;
if let Some(padding) = self.scheme.padding() {
decrypter.set_rsa_padding(padding)?;
}
{
let Encrypt::RsaEsOaep(inner) = self.scheme;
decrypter.set_rsa_oaep_md(inner.message_digest())?;
}
let buffer_len = decrypter.decrypt_len(slice)?;
let mut plaintext = vec![0; buffer_len];
let plaintext_len = decrypter.decrypt(slice, &mut plaintext)?;
plaintext.truncate(plaintext_len);
Ok(plaintext)
}
}
impl Signer for AsymKey<Private, Sign> {
fn init_sign(&self) -> Result<Box<dyn '_ + SignOp>> {
let op = OsslSignOp::new((self.scheme, self.pkey.as_ref()))?;
Ok(Box::new(op))
}
fn sign(&self, parts: &mut dyn Iterator<Item = &[u8]>) -> Result<Signature> {
let mut signer = OsslSigner::new(self.scheme.message_digest(), &self.pkey)?;
if let Some(padding) = self.scheme.padding() {
signer.set_rsa_padding(padding)?;
}
for part in parts {
signer.update(part)?;
}
let mut signature = Signature::empty(self.scheme);
signer.sign(signature.as_mut_slice())?;
Ok(signature)
}
fn kind(&self) -> Sign {
self.scheme
}
}
impl Verifier for AsymKey<Public, Sign> {
fn init_verify(&self) -> Result<Box<dyn '_ + VerifyOp>> {
let op = OsslVerifyOp::init(self.scheme, self.pkey.as_ref())?;
Ok(Box::new(op))
}
fn verify(&self, parts: &mut dyn Iterator<Item = &[u8]>, signature: &[u8]) -> Result<()> {
let mut verifier = OsslVerifier::new(self.scheme.message_digest(), &self.pkey)?;
if let Some(padding) = self.scheme.padding() {
verifier.set_rsa_padding(padding)?;
}
for part in parts {
verifier.update(part)?;
}
if verifier.verify(signature)? {
Ok(())
} else {
Err(bterr!(Error::InvalidSignature))
}
}
fn kind(&self) -> Sign {
self.scheme
}
}
#[derive(Clone, Serialize)]
pub struct AsymKeyPair<S: Scheme> {
public: AsymKey<Public, S>,
private: AsymKey<Private, S>,
}
impl<'de, S: Scheme> Deserialize<'de> for AsymKeyPair<S> {
fn deserialize<D: Deserializer<'de>>(d: D) -> std::result::Result<Self, D::Error> {
const FIELDS: &[&str] = &["public", "private"];
struct StructVisitor<S: Scheme>(PhantomData<S>);
impl<'de, S: Scheme> Visitor<'de> for StructVisitor<S> {
type Value = AsymKeyPair<S>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_fmt(format_args!("struct {}", stringify!(AsymKeyPair)))
}
fn visit_seq<V: SeqAccess<'de>>(
self,
mut seq: V,
) -> std::result::Result<Self::Value, V::Error> {
let public: AsymKey<Public, S> = seq
.next_element()?
.ok_or_else(|| de::Error::missing_field(FIELDS[0]))?;
let private: AsymKey<Private, S> = seq
.next_element()?
.ok_or_else(|| de::Error::missing_field(FIELDS[1]))?;
Ok(AsymKeyPair { public, private })
}
}
d.deserialize_struct(stringify!(AsymKey), FIELDS, StructVisitor(PhantomData))
}
}
impl<S: Scheme> AsymKeyPair<S> {
pub fn new(scheme: S, public_der: &[u8], private_der: &[u8]) -> Result<AsymKeyPair<S>> {
let public = AsymKey::<Public, _>::new(scheme, public_der)?;
let private = AsymKey::<Private, _>::new(scheme, private_der)?;
Ok(AsymKeyPair { public, private })
}
pub fn public(&self) -> &AsymKey<Public, S> {
&self.public
}
pub fn private(&self) -> &AsymKey<Private, S> {
&self.private
}
}
impl Principaled for AsymKeyPair<Sign> {
fn principal_of_kind(&self, kind: HashKind) -> Principal {
self.public.principal_of_kind(kind)
}
}
impl Encrypter for AsymKeyPair<Encrypt> {
fn encrypt(&self, slice: &[u8]) -> Result<Vec<u8>> {
self.public.encrypt(slice)
}
}
impl Decrypter for AsymKeyPair<Encrypt> {
fn decrypt(&self, slice: &[u8]) -> Result<Vec<u8>> {
self.private.decrypt(slice)
}
}
impl Signer for AsymKeyPair<Sign> {
fn init_sign(&self) -> Result<Box<dyn '_ + SignOp>> {
self.private.init_sign()
}
fn sign(&self, parts: &mut dyn Iterator<Item = &[u8]>) -> Result<Signature> {
self.private.sign(parts)
}
fn kind(&self) -> Sign {
self.private.kind()
}
}
impl Verifier for AsymKeyPair<Sign> {
fn init_verify(&self) -> Result<Box<dyn '_ + VerifyOp>> {
self.public.init_verify()
}
fn verify(&self, parts: &mut dyn Iterator<Item = &[u8]>, signature: &[u8]) -> Result<()> {
self.public.verify(parts, signature)
}
fn kind(&self) -> Sign {
self.public.kind()
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ConcretePub {
pub sign: AsymKeyPub<Sign>,
pub enc: AsymKeyPub<Encrypt>,
}
impl Principaled for ConcretePub {
fn principal_of_kind(&self, kind: HashKind) -> Principal {
self.sign.principal_of_kind(kind)
}
}
impl Encrypter for ConcretePub {
fn encrypt(&self, slice: &[u8]) -> Result<Vec<u8>> {
self.enc.encrypt(slice)
}
}
impl Verifier for ConcretePub {
fn init_verify(&self) -> Result<Box<dyn '_ + VerifyOp>> {
self.sign.init_verify()
}
fn verify(&self, parts: &mut dyn Iterator<Item = &[u8]>, signature: &[u8]) -> Result<()> {
self.sign.verify(parts, signature)
}
fn kind(&self) -> Sign {
self.sign.kind()
}
}
impl CredsPub for ConcretePub {
fn public_sign(&self) -> &AsymKey<Public, Sign> {
&self.sign
}
fn concrete_pub(&self) -> ConcretePub {
self.clone()
}
}
impl PartialEq for ConcretePub {
fn eq(&self, other: &Self) -> bool {
self.principal() == other.principal()
}
}
#[derive(Clone, Serialize, Deserialize)]
pub struct ConcreteCreds {
sign: AsymKeyPair<Sign>,
encrypt: AsymKeyPair<Encrypt>,
writecap: Option<Writecap>,
}
impl ConcreteCreds {
pub fn new(sign: AsymKeyPair<Sign>, encrypt: AsymKeyPair<Encrypt>) -> ConcreteCreds {
ConcreteCreds {
sign,
encrypt,
writecap: None,
}
}
pub fn generate() -> Result<ConcreteCreds> {
let encrypt = Encrypt::RSA_OAEP_3072_SHA_256.generate()?;
let sign = Sign::RSA_PSS_3072_SHA_256.generate()?;
Ok(ConcreteCreds {
sign,
encrypt,
writecap: None,
})
}
pub fn set_writecap(&mut self, writecap: Writecap) -> Result<()> {
writecap.assert_issued_to(&self.principal())?;
self.writecap = Some(writecap);
Ok(())
}
pub fn sign_pair(&self) -> &AsymKeyPair<Sign> {
&self.sign
}
pub fn encrypt_pair(&self) -> &AsymKeyPair<Encrypt> {
&self.encrypt
}
}
impl Verifier for ConcreteCreds {
fn init_verify(&self) -> Result<Box<dyn '_ + VerifyOp>> {
self.sign.init_verify()
}
fn verify(&self, parts: &mut dyn Iterator<Item = &[u8]>, signature: &[u8]) -> Result<()> {
self.sign.verify(parts, signature)
}
fn kind(&self) -> Sign {
Verifier::kind(&self.sign)
}
}
impl Encrypter for ConcreteCreds {
fn encrypt(&self, slice: &[u8]) -> Result<Vec<u8>> {
self.encrypt.encrypt(slice)
}
}
impl Principaled for ConcreteCreds {
fn principal_of_kind(&self, kind: HashKind) -> Principal {
self.sign.principal_of_kind(kind)
}
}
impl CredsPub for ConcreteCreds {
fn public_sign(&self) -> &AsymKey<Public, Sign> {
&self.sign.public
}
fn concrete_pub(&self) -> ConcretePub {
ConcretePub {
sign: self.sign.public.clone(),
enc: self.encrypt.public.clone(),
}
}
}
impl Signer for ConcreteCreds {
fn init_sign(&self) -> Result<Box<dyn '_ + SignOp>> {
self.sign.init_sign()
}
fn sign(&self, parts: &mut dyn Iterator<Item = &[u8]>) -> Result<Signature> {
self.sign.sign(parts)
}
fn kind(&self) -> Sign {
Signer::kind(&self.sign)
}
}
impl Decrypter for ConcreteCreds {
fn decrypt(&self, slice: &[u8]) -> Result<Vec<u8>> {
self.encrypt.decrypt(slice)
}
}
impl CredsPriv for ConcreteCreds {
fn writecap(&self) -> Option<&Writecap> {
self.writecap.as_ref()
}
}
pub trait Encrypter {
fn encrypt(&self, slice: &[u8]) -> Result<Vec<u8>>;
}
impl<T: ?Sized + Encrypter, P: Deref<Target = T>> Encrypter for P {
fn encrypt(&self, slice: &[u8]) -> Result<Vec<u8>> {
self.deref().encrypt(slice)
}
}
pub trait EncrypterExt: Encrypter {
fn ser_encrypt<T: Serialize>(&self, value: &T) -> Result<Ciphertext<T>> {
let data = to_vec(value)?;
let data = self.encrypt(&data)?;
Ok(Ciphertext::new(data))
}
}
impl<T: Encrypter + ?Sized> EncrypterExt for T {}
pub trait Decrypter {
fn decrypt(&self, slice: &[u8]) -> Result<Vec<u8>>;
}
impl<T: ?Sized + Decrypter, P: Deref<Target = T>> Decrypter for P {
fn decrypt(&self, slice: &[u8]) -> Result<Vec<u8>> {
self.deref().decrypt(slice)
}
}
pub trait DecrypterExt: Decrypter {
fn ser_decrypt<T: DeserializeOwned>(&self, ct: &Ciphertext<T>) -> Result<T> {
let pt = self.decrypt(ct.data.as_slice())?;
Ok(from_vec(&pt)?)
}
}
impl<T: Decrypter + ?Sized> DecrypterExt for T {}
pub trait SignOp: Op {
fn scheme(&self) -> Sign;
fn finish(&mut self) -> Result<Signature> {
let scheme = self.scheme();
let mut sig = Signature::empty(scheme);
self.finish_into(sig.as_mut())?;
Ok(sig)
}
}
impl<T: ?Sized + SignOp, P: DerefMut<Target = T>> SignOp for P {
fn scheme(&self) -> Sign {
self.deref().scheme()
}
}
pub struct OsslSignOp<'a> {
signer: OsslSigner<'a>,
scheme: Sign,
}
impl<'a> OsslSignOp<'a> {
pub fn new(arg: (Sign, &'a PKeyRef<Private>)) -> Result<Self> {
let scheme = arg.0;
let mut signer = OsslSigner::new(arg.0.message_digest(), arg.1)?;
if let Some(padding) = scheme.padding() {
signer.set_rsa_padding(padding)?;
}
Ok(OsslSignOp { signer, scheme })
}
}
impl<'a> Op for OsslSignOp<'a> {
fn update(&mut self, data: &[u8]) -> Result<()> {
Ok(self.signer.update(data)?)
}
fn finish_into(&mut self, buf: &mut [u8]) -> Result<usize> {
Ok(self.signer.sign(buf)?)
}
}
impl<'a> SignOp for OsslSignOp<'a> {
fn scheme(&self) -> Sign {
self.scheme
}
}
pub struct SignWrite<T, Op> {
inner: T,
op: Op,
}
impl<T, Op: SignOp> SignWrite<T, Op> {
pub fn new(inner: T, op: Op) -> Self {
SignWrite { inner, op }
}
pub fn finish_into(mut self, buf: &mut [u8]) -> Result<(usize, T)> {
Ok((self.op.finish_into(buf)?, self.inner))
}
pub fn finish(mut self) -> Result<(Signature, T)> {
Ok((self.op.finish()?, self.inner))
}
}
impl<T: Write, Op: SignOp> Write for SignWrite<T, Op> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.op.update(buf)?;
self.inner.write(buf)
}
fn flush(&mut self) -> io::Result<()> {
self.inner.flush()
}
}
pub trait Signer {
fn init_sign(&self) -> Result<Box<dyn '_ + SignOp>>;
fn sign(&self, parts: &mut dyn Iterator<Item = &[u8]>) -> Result<Signature>;
fn sign_writecap(&self, writecap: &mut Writecap) -> Result<()> {
let signed = self.ser_sign(&writecap.body)?;
writecap.signature = signed.sig;
Ok(())
}
fn kind(&self) -> Sign;
}
impl<T: ?Sized + Signer> Signer for &T {
fn init_sign(&self) -> Result<Box<dyn '_ + SignOp>> {
(*self).init_sign()
}
fn sign(&self, parts: &mut dyn Iterator<Item = &[u8]>) -> Result<Signature> {
(*self).sign(parts)
}
fn kind(&self) -> Sign {
(*self).kind()
}
}
impl<T: ?Sized + Signer> Signer for Arc<T> {
fn init_sign(&self) -> Result<Box<dyn '_ + SignOp>> {
self.deref().init_sign()
}
fn sign(&self, parts: &mut dyn Iterator<Item = &[u8]>) -> Result<Signature> {
self.deref().sign(parts)
}
fn kind(&self) -> Sign {
self.deref().kind()
}
}
pub trait SignerExt: Signer {
fn ser_sign<T: Serialize>(&self, value: &T) -> Result<Signed<T>> {
let data = to_vec(value)?;
let sig = self.sign(&mut std::iter::once(data.as_slice()))?;
Ok(Signed::new(data, sig))
}
fn ser_sign_into<T: Serialize>(&self, value: &T, buf: &mut Vec<u8>) -> Result<Signature> {
write_to(value, &mut *buf)?;
self.sign(&mut std::iter::once(buf.as_slice()))
}
}
impl<T: ?Sized + Signer> SignerExt for T {}
pub trait VerifyOp {
fn update(&mut self, data: &[u8]) -> Result<()>;
fn finish(&mut self, sig: &[u8]) -> Result<()>;
fn scheme(&self) -> Sign;
}
impl<T: ?Sized + VerifyOp, P: DerefMut<Target = T>> VerifyOp for P {
fn update(&mut self, data: &[u8]) -> Result<()> {
self.deref_mut().update(data)
}
fn finish(&mut self, sig: &[u8]) -> Result<()> {
self.deref_mut().finish(sig)
}
fn scheme(&self) -> Sign {
self.deref().scheme()
}
}
pub struct OsslVerifyOp<'a> {
verifier: OsslVerifier<'a>,
scheme: Sign,
}
impl<'a> OsslVerifyOp<'a> {
pub fn init(scheme: Sign, pkey: &'a PKeyRef<Public>) -> Result<Self> {
let mut verifier = OsslVerifier::new(scheme.message_digest(), pkey)?;
if let Some(padding) = scheme.padding() {
verifier.set_rsa_padding(padding)?;
}
Ok(OsslVerifyOp { verifier, scheme })
}
}
impl<'a> VerifyOp for OsslVerifyOp<'a> {
fn update(&mut self, data: &[u8]) -> Result<()> {
Ok(self.verifier.update(data)?)
}
fn finish(&mut self, sig: &[u8]) -> Result<()> {
match self.verifier.verify(sig) {
Ok(true) => Ok(()),
Ok(false) => Err(bterr!(Error::InvalidSignature)),
Err(err) => Err(err.into()),
}
}
fn scheme(&self) -> Sign {
self.scheme
}
}
pub struct VerifyRead<T, Op> {
inner: T,
op: Op,
update_failed: bool,
}
impl<T: Read, Op: VerifyOp> VerifyRead<T, Op> {
pub fn new(inner: T, op: Op) -> Self {
VerifyRead {
inner,
op,
update_failed: false,
}
}
pub fn finish(mut self, sig: &[u8]) -> std::result::Result<T, (T, crate::Error)> {
if self.update_failed {
return Err((
self.inner,
bterr!("VerifyRead::finish: update_failed was true"),
));
}
match self.op.finish(sig) {
Ok(_) => Ok(self.inner),
Err(err) => Err((self.inner, err)),
}
}
}
impl<T: Read, Op: VerifyOp> Read for VerifyRead<T, Op> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
if self.update_failed {
return Err(bterr!("VerifyRead::read update previously failed").into());
}
let read = self.inner.read(buf)?;
if read > 0 {
if let Err(err) = self.op.update(&buf[..read]) {
self.update_failed = true;
error!("VerifyRead::read failed to update VerifyOp: {err}");
}
}
Ok(read)
}
}
pub trait Verifier {
fn init_verify(&self) -> Result<Box<dyn '_ + VerifyOp>>;
fn verify(&self, parts: &mut dyn Iterator<Item = &[u8]>, signature: &[u8]) -> Result<()>;
fn kind(&self) -> Sign;
}
impl<V: ?Sized + Verifier> Verifier for &V {
fn init_verify<'a>(&'a self) -> Result<Box<dyn 'a + VerifyOp>> {
(*self).init_verify()
}
fn verify(&self, parts: &mut dyn Iterator<Item = &[u8]>, signature: &[u8]) -> Result<()> {
(*self).verify(parts, signature)
}
fn kind(&self) -> Sign {
(*self).kind()
}
}
impl<V: ?Sized + Verifier> Verifier for Arc<V> {
fn init_verify<'a>(&'a self) -> Result<Box<dyn 'a + VerifyOp>> {
self.deref().init_verify()
}
fn verify(&self, parts: &mut dyn Iterator<Item = &[u8]>, signature: &[u8]) -> Result<()> {
self.deref().verify(parts, signature)
}
fn kind(&self) -> Sign {
self.deref().kind()
}
}
pub trait VerifierExt: Verifier {
fn ser_verify<T: Serialize>(&self, value: &T, signature: &[u8]) -> Result<()>;
}
impl<V: ?Sized + Verifier> VerifierExt for V {
fn ser_verify<T: Serialize>(&self, value: &T, signature: &[u8]) -> Result<()> {
let data = to_vec(value)?;
self.verify(&mut std::iter::once(data.as_slice()), signature)
}
}
pub trait CredsPub: Verifier + Encrypter + Principaled {
fn public_sign(&self) -> &AsymKey<Public, Sign>;
fn concrete_pub(&self) -> ConcretePub;
fn sign_kind(&self) -> Sign {
Verifier::kind(self)
}
}
impl<T: ?Sized + CredsPub> CredsPub for &T {
fn public_sign(&self) -> &AsymKey<Public, Sign> {
(*self).public_sign()
}
fn concrete_pub(&self) -> ConcretePub {
(*self).concrete_pub()
}
}
impl<T: ?Sized + CredsPub> CredsPub for Arc<T> {
fn public_sign(&self) -> &AsymKey<Public, Sign> {
self.deref().public_sign()
}
fn concrete_pub(&self) -> ConcretePub {
self.deref().concrete_pub()
}
}
pub trait CredsPriv: Decrypter + Signer {
fn writecap(&self) -> Option<&Writecap>;
fn sign_kind(&self) -> Sign {
Signer::kind(self)
}
fn bind_path(&self) -> Result<BlockPath> {
Ok(self
.writecap()
.ok_or(BlockError::MissingWritecap)?
.bind_path())
}
}
impl<T: ?Sized + CredsPriv> CredsPriv for &T {
fn writecap(&self) -> Option<&Writecap> {
(*self).writecap()
}
}
impl<T: ?Sized + CredsPriv> CredsPriv for Arc<T> {
fn writecap(&self) -> Option<&Writecap> {
self.deref().writecap()
}
}
pub trait Creds: CredsPriv + CredsPub + Send + Sync {
fn issue_writecap(
&self,
issued_to: Principal,
path_components: &mut dyn Iterator<Item = &str>,
expires: Epoch,
) -> Result<Writecap> {
let root_principal = self
.writecap()
.map(|e| e.root_principal())
.unwrap_or_else(|| self.principal());
let path = BlockPath::from_components(root_principal, path_components);
let body = WritecapBody {
issued_to,
path,
expires,
signing_key: self.public_sign().to_owned(),
};
let signed = self.ser_sign(&body)?;
Ok(Writecap {
body,
signature: signed.sig,
next: self.writecap().map(|e| Box::new(e.to_owned())),
})
}
fn pub_sign_kind(&self) -> Sign {
CredsPub::sign_kind(self)
}
fn priv_sign_kind(&self) -> Sign {
CredsPriv::sign_kind(self)
}
}
impl<C: ?Sized + CredsPriv + CredsPub + Send + Sync> Creds for C {}
pub trait CredStore {
type CredHandle: 'static + Creds;
type ExportedCreds: 'static + Serialize + DeserializeOwned;
fn node_creds(&self) -> Result<Self::CredHandle>;
fn root_creds(&self, password: &str) -> Result<Self::CredHandle>;
fn storage_key(&self) -> Result<AsymKeyPub<Encrypt>>;
fn export_root_creds(
&self,
root_creds: &Self::CredHandle,
password: &str,
new_parent: &AsymKeyPub<Encrypt>,
) -> Result<Self::ExportedCreds>;
}
impl<T: ?Sized + CredStore, P: Deref<Target = T>> CredStore for P {
type CredHandle = T::CredHandle;
type ExportedCreds = T::ExportedCreds;
fn node_creds(&self) -> Result<Self::CredHandle> {
self.deref().node_creds()
}
fn root_creds(&self, password: &str) -> Result<Self::CredHandle> {
self.deref().root_creds(password)
}
fn storage_key(&self) -> Result<AsymKeyPub<Encrypt>> {
self.deref().storage_key()
}
fn export_root_creds(
&self,
root_creds: &Self::CredHandle,
password: &str,
new_parent: &AsymKeyPub<Encrypt>,
) -> Result<Self::ExportedCreds> {
self.deref()
.export_root_creds(root_creds, password, new_parent)
}
}
pub trait CredStoreMut: CredStore {
fn gen_root_creds(&self, password: &str) -> Result<Self::CredHandle>;
fn import_root_creds(
&self,
password: &str,
exported: Self::ExportedCreds,
) -> Result<Self::CredHandle>;
fn assign_node_writecap(&self, handle: &mut Self::CredHandle, writecap: Writecap)
-> Result<()>;
fn assign_root_writecap(&self, handle: &mut Self::CredHandle, writecap: Writecap)
-> Result<()>;
fn provision_root(&self, password: &str, expires: Epoch) -> Result<Self::CredHandle> {
let mut root_creds = self.gen_root_creds(password)?;
let writecap =
root_creds.issue_writecap(root_creds.principal(), &mut std::iter::empty(), expires)?;
self.assign_root_writecap(&mut root_creds, writecap)?;
Ok(root_creds)
}
fn provision_node_start(&self) -> Result<Principal> {
let node_creds = self.node_creds()?;
Ok(node_creds.principal())
}
fn provision_node_finish(&self, writecap: Writecap) -> Result<Self::CredHandle> {
let mut node_creds = self.node_creds()?;
self.assign_node_writecap(&mut node_creds, writecap)?;
Ok(node_creds)
}
}
impl<T: ?Sized + CredStoreMut, P: Deref<Target = T>> CredStoreMut for P {
fn gen_root_creds(&self, password: &str) -> Result<T::CredHandle> {
self.deref().gen_root_creds(password)
}
fn import_root_creds(
&self,
password: &str,
exported: Self::ExportedCreds,
) -> Result<Self::CredHandle> {
self.deref().import_root_creds(password, exported)
}
fn assign_node_writecap(
&self,
handle: &mut Self::CredHandle,
writecap: Writecap,
) -> Result<()> {
self.deref().assign_node_writecap(handle, writecap)
}
fn assign_root_writecap(
&self,
handle: &mut Self::CredHandle,
writecap: Writecap,
) -> Result<()> {
self.deref().assign_root_writecap(handle, writecap)
}
}
impl BlockMeta {
pub fn assert_valid(&self, path: &BlockPath) -> Result<()> {
let body = &self.body;
let writecap = body
.writecap
.as_ref()
.ok_or(crate::BlockError::MissingWritecap)?;
writecap.assert_valid_for(path)?;
let signed_by = body.signing_key.principal();
if writecap.body.issued_to != signed_by {
return Err(bterr!(Error::signature_mismatch(
writecap.body.issued_to.clone(),
signed_by,
)));
}
body.signing_key.ser_verify(&body, self.sig.as_slice())
}
}
#[derive(Debug, PartialEq, Eq, Display)]
pub enum WritecapAuthzErr {
UnauthorizedPath,
Expired,
NotChained,
RootDoesNotOwnPath,
Serde(String),
ChainTooLong(usize),
}
impl Writecap {
pub fn assert_valid_for(&self, path: &BlockPath) -> Result<()> {
let mut writecap = self;
const CHAIN_LEN_LIMIT: usize = 256;
let mut prev: Option<&Writecap> = None;
let mut sig_input_buf = Vec::new();
let now = Epoch::now();
for _ in 0..CHAIN_LEN_LIMIT {
if !writecap.body.path.contains(path) {
return Err(bterr!(WritecapAuthzErr::UnauthorizedPath));
}
if writecap.body.expires <= now {
return Err(bterr!(WritecapAuthzErr::Expired));
}
if let Some(prev) = &prev {
if prev
.body
.signing_key
.principal_of_kind(writecap.body.issued_to.kind())
!= writecap.body.issued_to
{
return Err(bterr!(WritecapAuthzErr::NotChained));
}
}
sig_input_buf.clear();
write_to(&writecap.body, &mut sig_input_buf)
.map_err(|e| bterr!(WritecapAuthzErr::Serde(e.to_string())))?;
writecap.body.signing_key.verify(
&mut std::iter::once(sig_input_buf.as_slice()),
writecap.signature.as_slice(),
)?;
match &writecap.next {
Some(next) => {
prev = Some(writecap);
writecap = next;
}
None => {
if writecap
.body
.signing_key
.principal_of_kind(path.root().kind())
== *path.root()
{
return Ok(());
} else {
return Err(bterr!(WritecapAuthzErr::RootDoesNotOwnPath));
}
}
}
}
Err(bterr!(WritecapAuthzErr::ChainTooLong(CHAIN_LEN_LIMIT)))
}
}
#[cfg(test)]
mod tests {
use std::{
io::{Seek, SeekFrom},
time::Duration,
};
use super::*;
use crate::{
crypto::secret_stream::SecretStream,
test_helpers::{self, *},
Sectored, TryCompose,
};
#[test]
fn encrypt_decrypt_block() {
const SECT_SZ: usize = 16;
const SECT_CT: usize = 8;
let mut block = make_block_with();
write_fill(&mut block, SECT_SZ, SECT_CT);
block.rewind().expect("rewind failed");
read_check(block, SECT_SZ, SECT_CT);
}
#[test]
fn rsa_sign_and_verify() -> Result<()> {
let key = make_key_pair();
let header = b"About: lyrics".as_slice();
let message = b"Everything that feels so good is bad bad bad.".as_slice();
let signature = key.sign(&mut [header, message].into_iter())?;
key.verify(&mut [header, message].into_iter(), signature.as_slice())
}
#[test]
fn hash_to_string() {
let hash = make_principal().0;
let string = hash.to_string();
assert_eq!("0!dSip4J0kurN5VhVo_aTipM-ywOOWrqJuRRVQ7aa-bew", string)
}
#[test]
fn hash_to_string_round_trip() -> Result<()> {
let expected = make_principal().0;
let string = expected.to_string();
let actual = VarHash::try_from(string.as_str())?;
assert_eq!(expected, actual);
Ok(())
}
#[test]
fn verify_writecap_valid() {
let writecap = make_writecap(["apps", "verse"].into_iter());
writecap
.assert_valid_for(&writecap.body.path)
.expect("failed to verify writecap");
}
#[test]
fn verify_writecap_invalid_signature() -> Result<()> {
let mut writecap = make_writecap(["apps", "verse"].into_iter());
writecap.signature = Signature::empty(Sign::RSA_PSS_3072_SHA_256);
let result = writecap.assert_valid_for(&writecap.body.path);
if let Err(ref err) = result {
if let Some(err) = err.downcast_ref::<Error>() {
if let Error::InvalidSignature = err {
return Ok(());
}
}
}
Err(bterr!("unexpected result {:?}", result))
}
fn assert_authz_err<T: std::fmt::Debug>(
expected: WritecapAuthzErr,
result: Result<T>,
) -> Result<()> {
if let Some(err) = result.as_ref().err() {
if let Some(actual) = err.downcast_ref::<WritecapAuthzErr>() {
if *actual == expected {
return Ok(());
}
}
}
Err(bterr!("unexpected result: {:?}", result))
}
#[test]
fn verify_writecap_invalid_path_not_contained() -> Result<()> {
let writecap = make_writecap(["apps", "verse"].into_iter());
let mut path = writecap.body.path.clone();
path.pop_component();
let result = writecap.assert_valid_for(&path);
assert_authz_err(WritecapAuthzErr::UnauthorizedPath, result)
}
#[test]
fn verify_writecap_invalid_expired() -> Result<()> {
let mut writecap = make_writecap(["apps", "verse"].into_iter());
writecap.body.expires = Epoch::now() - Duration::from_secs(1);
let result = writecap.assert_valid_for(&writecap.body.path);
assert_authz_err(WritecapAuthzErr::Expired, result)
}
#[test]
fn verify_writecap_invalid_not_chained() -> Result<()> {
let (mut root_writecap, root_key) = make_self_signed_writecap();
root_writecap.body.issued_to = Principal(VarHash::from(HashKind::Sha2_256));
root_key.sign_writecap(&mut root_writecap)?;
let node_principal = NODE_CREDS.principal();
let writecap = make_writecap_trusted_by(
root_writecap,
&root_key,
node_principal,
["apps", "contacts"].into_iter(),
);
let result = writecap.assert_valid_for(&writecap.body.path);
assert_authz_err(WritecapAuthzErr::NotChained, result)
}
#[test]
fn verify_writecap_invalid_root_doesnt_own_path() -> Result<()> {
let (mut root_writecap, root_key) = make_self_signed_writecap();
let owner = Principal(VarHash::from(HashKind::Sha2_256));
root_writecap.body.path = make_path_with_root(owner, std::iter::empty());
root_key.sign_writecap(&mut root_writecap)?;
let node_principal = NODE_CREDS.principal();
let writecap = make_writecap_trusted_by(
root_writecap,
&root_key,
node_principal,
["apps", "contacts"].into_iter(),
);
let result = writecap.assert_valid_for(&writecap.body.path);
assert_authz_err(WritecapAuthzErr::RootDoesNotOwnPath, result)
}
#[test]
fn aeadkey_encrypt_decrypt_aes256gcm() {
let key = AeadKey::new(AeadKeyKind::AesGcm256).expect("failed to create key");
let aad = [1u8; 16];
let expected = [2u8; 32];
let tagged = key.encrypt(aad, &expected).expect("encrypt failed");
let actual = key.decrypt(&tagged).expect("decrypt failed");
assert_eq!(expected, actual.as_slice());
}
#[test]
fn aeadkey_decrypt_fails_when_ct_modified() {
let key = AeadKey::new(AeadKeyKind::AesGcm256).expect("failed to create key");
let aad = [1u8; 16];
let expected = [2u8; 32];
let mut tagged = key.encrypt(aad, &expected).expect("encrypt failed");
tagged.ciphertext.data[0] = tagged.ciphertext.data[0].wrapping_add(1);
let result = key.decrypt(&tagged);
assert!(result.is_err())
}
#[test]
fn aeadkey_decrypt_fails_when_aad_modified() {
let key = AeadKey::new(AeadKeyKind::AesGcm256).expect("failed to create key");
let aad = [1u8; 16];
let expected = [2u8; 32];
let mut tagged = key.encrypt(aad, &expected).expect("encrypt failed");
tagged.aad[0] = tagged.aad[0].wrapping_add(1);
let result = key.decrypt(&tagged);
assert!(result.is_err())
}
#[test]
fn compose_merkle_and_secret_streams() {
use merkle_stream::tests::make_merkle_stream_filled_with_zeros;
const SECT_SZ: usize = 4096;
const SECT_CT: usize = 16;
let merkle = make_merkle_stream_filled_with_zeros(SECT_SZ, SECT_CT);
let key = SymKey::generate(SymKeyKind::Aes256Cbc).expect("key generation failed");
let mut secret = SecretStream::new(key)
.try_compose(merkle)
.expect("compose for secret failed");
let secret_sect_sz = secret.sector_sz();
write_fill(&mut secret, secret_sect_sz, SECT_CT);
secret.rewind().expect("rewind failed");
read_check(secret, secret_sect_sz, SECT_CT);
}
fn ossl_hash_op_same_as_digest_test_case<H: Hash + From<DigestBytes>>(kind: HashKind) {
let parts = (0u8..32).map(|k| vec![k; kind.len()]).collect::<Vec<_>>();
let expected = {
let mut expected = vec![0u8; kind.len()];
kind.digest(expected.as_mut(), parts.iter().map(|a| a.as_slice()))
.unwrap();
expected
};
let mut op = OsslHashOp::<H>::new(kind).unwrap();
for part in parts.iter() {
op.update(part.as_slice()).unwrap();
}
let actual = op.finish().unwrap();
assert_eq!(expected.as_slice(), actual.as_ref());
}
#[test]
fn ossl_hash_op_same_as_digest() {
ossl_hash_op_same_as_digest_test_case::<Sha2_256>(Sha2_256::KIND);
ossl_hash_op_same_as_digest_test_case::<Sha2_512>(Sha2_512::KIND);
}
#[test]
fn hash_stream_agrees_with_digest_method() {
let cursor = BtCursor::new([0u8; 3 * 32]);
let parts = (1u8..4).map(|k| [k; Sha2_512::LEN]).collect::<Vec<_>>();
let expected = {
let mut expected = Sha2_512::default();
HashKind::Sha2_512
.digest(expected.as_mut(), parts.iter().map(|a| a.as_slice()))
.unwrap();
expected
};
let op = OsslHashOp::<Sha2_512>::new(Sha2_512::KIND).unwrap();
let mut wrap = HashStream::new(cursor, op);
for part in parts.iter() {
wrap.write(part.as_slice()).unwrap();
}
let actual = wrap.finish().unwrap();
assert_eq!(expected, actual);
}
#[test]
fn var_hash_op_agress_with_digest_method() {
let parts = (32..64u8).map(|k| [k; Sha2_512::LEN]).collect::<Vec<_>>();
let expected = {
let mut expected = VarHash::from(HashKind::Sha2_512);
HashKind::Sha2_512
.digest(expected.as_mut(), parts.iter().map(|a| a.as_slice()))
.unwrap();
expected
};
let mut op = VarHashOp::new(HashKind::Sha2_512).unwrap();
for part in parts.iter() {
op.update(part.as_slice()).unwrap();
}
let actual = op.finish().unwrap();
assert_eq!(expected, actual);
}
#[test]
fn ossl_sign_op_sig_can_be_verified() {
let keys = &test_helpers::NODE_CREDS;
let part_values = (1..9u8).map(|k| [k; 32]).collect::<Vec<_>>();
let get_parts = || part_values.iter().map(|a| a.as_slice());
let mut sign_op = keys.init_sign().expect("init_sign failed");
for part in get_parts() {
sign_op.update(part).expect("update failed");
}
let sig = sign_op.finish().expect("finish failed");
keys.verify(&mut get_parts(), sig.as_ref())
.expect("verify failed");
}
#[test]
fn sign_write_sig_can_be_verified() {
use crate::Decompose;
const LEN: usize = 512;
let cursor = BtCursor::new([0u8; LEN]);
let keys = &test_helpers::NODE_CREDS;
let sign_op = keys.sign.private.init_sign().expect("init_sign failed");
let mut sign_write = SignWrite::new(cursor, sign_op);
for part in (1..9u8).map(|k| [k; LEN / 8]) {
sign_write.write(part.as_slice()).expect("write failed");
}
let (sig, cursor) = sign_write.finish().expect("finish failed");
let array = cursor.into_inner();
keys.verify(&mut std::iter::once(array.as_slice()), sig.as_ref())
.expect("verify failed");
}
#[test]
fn sign_write_then_verify_read() {
const LEN: usize = 512;
let cursor = BtCursor::new([0u8; LEN]);
let keys = &test_helpers::NODE_CREDS;
let sign_op = keys.sign.private.init_sign().expect("init_sign failed");
let mut sign_write = SignWrite::new(cursor, sign_op);
for part in (1..9u8).map(|k| [k; LEN / 8]) {
sign_write.write(part.as_slice()).expect("write failed");
}
let (sig, mut cursor) = sign_write.finish().expect("finish failed");
cursor.seek(SeekFrom::Start(0)).expect("seek failed");
let verify_op = keys.sign.public.init_verify().expect("init_verify failed");
let mut verify_read = VerifyRead::new(cursor, verify_op);
let mut buf = Vec::with_capacity(LEN);
verify_read
.read_to_end(&mut buf)
.expect("read_to_end failed");
verify_read
.finish(sig.as_ref())
.expect("failed to verify signature");
}
mod dependency_tests {
use super::*;
use openssl::{
ec::{EcGroup, EcKey},
nid::Nid,
};
#[test]
fn aes_256_cbc_roundtrip() {
use super::*;
let expected = b"We attack at the crack of noon!";
let cipher = Cipher::aes_256_cbc();
let key = BLOCK_KEY.key_slice();
let iv = BLOCK_KEY.iv_slice();
let ciphertext = openssl_encrypt(cipher, key, iv, expected).unwrap();
let actual = openssl_decrypt(cipher, key, iv, ciphertext.as_slice()).unwrap();
assert_eq!(expected, actual.as_slice());
}
#[test]
fn secp256k1_key_lengths() {
let group = EcGroup::from_curve_name(Nid::SECP256K1).unwrap();
let key = EcKey::generate(&group).unwrap();
let public = key.public_key_to_der().unwrap();
let private = key.private_key_to_der().unwrap();
let public_len = public.len();
let private_len = private.len();
assert_eq!(88, public_len);
assert_eq!(118, private_len);
}
#[test]
fn ed25519_key_lengths() {
let key = PKey::generate_x25519().unwrap();
let public = key.public_key_to_der().unwrap();
let private = key.private_key_to_der().unwrap();
let public_len = public.len();
let private_len = private.len();
assert_eq!(44, public_len);
assert_eq!(48, private_len);
}
}
mod obj_safety {
use super::*;
#[test]
fn op_obj_safe() {
assert_obj_safe!(Op);
}
#[test]
fn sign_op_obj_safe() {
assert_obj_safe!(SignOp);
}
#[test]
fn verify_op_obj_safe() {
assert_obj_safe!(VerifyOp);
}
#[test]
fn encrypter_obj_safe() {
assert_obj_safe!(Encrypter);
}
#[test]
fn decrypter_obj_safe() {
assert_obj_safe!(Decrypter);
}
#[test]
fn verifier_obj_safe() {
assert_obj_safe!(Verifier);
}
#[test]
fn signer_obj_safe() {
assert_obj_safe!(Signer);
}
#[test]
fn creds_pub_obj_safe() {
assert_obj_safe!(CredsPub);
}
#[test]
fn creds_priv_obj_safe() {
assert_obj_safe!(CredsPriv);
}
#[test]
fn creds_obj_safe() {
assert_obj_safe!(Creds);
}
}
}