|
@@ -11,11 +11,13 @@ use crate::{
|
|
|
|
|
|
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, Hasher, MessageDigest},
|
|
|
- pkey::{HasPrivate, HasPublic, PKey},
|
|
|
+ hash::{hash, DigestBytes, Hasher, MessageDigest},
|
|
|
+ nid::Nid,
|
|
|
+ pkey::{HasPrivate, HasPublic, PKey, PKeyRef},
|
|
|
rand::rand_bytes,
|
|
|
rsa::{Padding as OpensslPadding, Rsa as OsslRsa},
|
|
|
sign::{Signer as OsslSigner, Verifier as OsslVerifier},
|
|
@@ -25,7 +27,11 @@ use serde::{
|
|
|
de::{self, DeserializeOwned, Deserializer, SeqAccess, Visitor},
|
|
|
ser::{SerializeStruct, Serializer},
|
|
|
};
|
|
|
-use std::{marker::PhantomData, num::TryFromIntError};
|
|
|
+use std::{
|
|
|
+ io::{Read, Write},
|
|
|
+ marker::PhantomData,
|
|
|
+ num::TryFromIntError,
|
|
|
+};
|
|
|
use strum_macros::{Display, EnumDiscriminants, FromRepr};
|
|
|
use zeroize::ZeroizeOnDrop;
|
|
|
|
|
@@ -206,7 +212,296 @@ pub fn rand_vec(len: usize) -> Result<Vec<u8>> {
|
|
|
Ok(vec)
|
|
|
}
|
|
|
|
|
|
+/// An ongoing Init-Update-Finish operation.
|
|
|
+pub trait Op: Sized {
|
|
|
+ /// The type of the argument given to `init`.
|
|
|
+ type Arg;
|
|
|
+
|
|
|
+ /// Initialize a new operation.
|
|
|
+ fn init(arg: Self::Arg) -> Result<Self>;
|
|
|
+
|
|
|
+ /// Update this operation using the given data.
|
|
|
+ fn update(&mut self, data: &[u8]) -> Result<()>;
|
|
|
+
|
|
|
+ /// Finish this operation and write the result into the given buffer. If the given buffer is not
|
|
|
+ /// large enough the implementation must return Error::IncorrectSize.
|
|
|
+ fn finish_into(self, buf: &mut [u8]) -> Result<usize>;
|
|
|
+}
|
|
|
+
|
|
|
+/// An ongoing hash hash operation.
|
|
|
+pub trait HashOp: Op {
|
|
|
+ /// The specific hash type which is returned by the finish method.
|
|
|
+ type Hash: Hash;
|
|
|
+
|
|
|
+ /// Returns the kind of hash this operation is computing.
|
|
|
+ fn kind(&self) -> HashKind;
|
|
|
+
|
|
|
+ /// Finish this operation and return a hash type containing the result.
|
|
|
+ fn finish(self) -> Result<Self::Hash>;
|
|
|
+}
|
|
|
+
|
|
|
+// A hash operation which uses OpenSSL.
|
|
|
+pub struct OsslHashOp<H> {
|
|
|
+ hasher: Hasher,
|
|
|
+ phantom: PhantomData<H>,
|
|
|
+ kind: HashKind,
|
|
|
+}
|
|
|
+
|
|
|
+impl<H> Op for OsslHashOp<H> {
|
|
|
+ type Arg = HashKind;
|
|
|
+
|
|
|
+ fn init(arg: Self::Arg) -> Result<Self> {
|
|
|
+ let hasher = Hasher::new(arg.into())?;
|
|
|
+ let phantom = PhantomData;
|
|
|
+ Ok(OsslHashOp {
|
|
|
+ hasher,
|
|
|
+ phantom,
|
|
|
+ kind: arg,
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ 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(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))
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/// A wrapper which updates a `HashOp` when data is read or written.
|
|
|
+pub struct HashStream<T, Op: HashOp> {
|
|
|
+ inner: T,
|
|
|
+ op: Op,
|
|
|
+ update_failed: bool,
|
|
|
+}
|
|
|
+
|
|
|
+impl<T, Op: HashOp> HashStream<T, Op> {
|
|
|
+ /// Create a new `HashWrap`.
|
|
|
+ pub fn new(inner: T, op: Op) -> HashStream<T, Op> {
|
|
|
+ HashStream {
|
|
|
+ inner,
|
|
|
+ op,
|
|
|
+ update_failed: false,
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /// Finish this hash operation and write the result into the given buffer. The number of bytes
|
|
|
+ /// written is returned.
|
|
|
+ pub fn finish_into(self, buf: &mut [u8]) -> Result<usize> {
|
|
|
+ if self.update_failed {
|
|
|
+ return Err(Error::custom(
|
|
|
+ "HashStream::finish_into can't produce result due to HashOp update failure",
|
|
|
+ ));
|
|
|
+ }
|
|
|
+ self.op.finish_into(buf)
|
|
|
+ }
|
|
|
+
|
|
|
+ /// Finish this hash operation and return the resulting hash.
|
|
|
+ pub fn finish(self) -> Result<Op::Hash> {
|
|
|
+ if self.update_failed {
|
|
|
+ return Err(Error::custom(
|
|
|
+ "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(Error::custom(
|
|
|
+ "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()
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
/// A cryptographic hash.
|
|
|
+pub trait Hash: AsRef<[u8]> + AsMut<[u8]> + Sized {
|
|
|
+ /// The hash operation associated with this `Hash`.
|
|
|
+ type Op: HashOp;
|
|
|
+ /// The type of the argument required by `new`.
|
|
|
+ type Arg;
|
|
|
+
|
|
|
+ /// Returns a new `Hash` instance.
|
|
|
+ fn new(arg: Self::Arg) -> Self;
|
|
|
+ /// Returns the `HashKind` of self.
|
|
|
+ fn kind(&self) -> HashKind;
|
|
|
+ /// Starts a new hash operation.
|
|
|
+ fn start_op(&self) -> Result<Self::Op>;
|
|
|
+}
|
|
|
+
|
|
|
+/// Trait for hash types which can be created with no arguments.
|
|
|
+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(());
|
|
|
+ // TODO: It would be great if there was a way to avoid this copy.
|
|
|
+ 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::init(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::init(Self::KIND)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/// One of several concrete hash types.
|
|
|
#[derive(
|
|
|
Debug,
|
|
|
PartialEq,
|
|
@@ -221,10 +516,9 @@ pub fn rand_vec(len: usize) -> Result<Vec<u8>> {
|
|
|
)]
|
|
|
#[strum_discriminants(derive(FromRepr, Display, Serialize, Deserialize))]
|
|
|
#[strum_discriminants(name(HashKind))]
|
|
|
-pub enum Hash {
|
|
|
- Sha2_256([u8; HashKind::Sha2_256.len()]),
|
|
|
- #[serde(with = "BigArray")]
|
|
|
- Sha2_512([u8; HashKind::Sha2_512.len()]),
|
|
|
+pub enum VarHash {
|
|
|
+ Sha2_256(Sha2_256),
|
|
|
+ Sha2_512(Sha2_512),
|
|
|
}
|
|
|
|
|
|
impl Default for HashKind {
|
|
@@ -233,7 +527,7 @@ impl Default for HashKind {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-impl Default for Hash {
|
|
|
+impl Default for VarHash {
|
|
|
fn default() -> Self {
|
|
|
HashKind::default().into()
|
|
|
}
|
|
@@ -265,6 +559,23 @@ impl HashKind {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+impl TryFrom<MessageDigest> for HashKind {
|
|
|
+ type Error = 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(Error::custom(format!(
|
|
|
+ "Unsupported MessageDigest with NID: {:?}",
|
|
|
+ nid
|
|
|
+ )))
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
impl From<HashKind> for MessageDigest {
|
|
|
fn from(kind: HashKind) -> Self {
|
|
|
match kind {
|
|
@@ -274,46 +585,71 @@ impl From<HashKind> for MessageDigest {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-impl Hash {
|
|
|
+impl VarHash {
|
|
|
/// The character that's used to separate a hash type from its value in its string
|
|
|
/// representation.
|
|
|
const HASH_SEP: char = '!';
|
|
|
|
|
|
pub fn kind(&self) -> HashKind {
|
|
|
- HashKind::from(self)
|
|
|
+ self.into()
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-impl From<HashKind> for Hash {
|
|
|
- fn from(discriminant: HashKind) -> Hash {
|
|
|
- match discriminant {
|
|
|
- HashKind::Sha2_256 => Hash::Sha2_256([0u8; HashKind::Sha2_256.len()]),
|
|
|
- HashKind::Sha2_512 => Hash::Sha2_512([0u8; HashKind::Sha2_512.len()]),
|
|
|
+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 Hash {
|
|
|
+impl AsRef<[u8]> for VarHash {
|
|
|
fn as_ref(&self) -> &[u8] {
|
|
|
match self {
|
|
|
- Hash::Sha2_256(arr) => arr,
|
|
|
- Hash::Sha2_512(arr) => arr,
|
|
|
+ VarHash::Sha2_256(arr) => arr.as_ref(),
|
|
|
+ VarHash::Sha2_512(arr) => arr.as_ref(),
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-impl AsMut<[u8]> for Hash {
|
|
|
+impl AsMut<[u8]> for VarHash {
|
|
|
fn as_mut(&mut self) -> &mut [u8] {
|
|
|
match self {
|
|
|
- Hash::Sha2_256(arr) => arr,
|
|
|
- Hash::Sha2_512(arr) => arr,
|
|
|
+ VarHash::Sha2_256(arr) => arr.as_mut(),
|
|
|
+ VarHash::Sha2_512(arr) => arr.as_mut(),
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-impl TryFrom<&str> for Hash {
|
|
|
+impl TryFrom<MessageDigest> for VarHash {
|
|
|
+ type Error = 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::init(self.kind())
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+impl TryFrom<&str> for VarHash {
|
|
|
type Error = Error;
|
|
|
- fn try_from(string: &str) -> Result<Hash> {
|
|
|
+ fn try_from(string: &str) -> Result<VarHash> {
|
|
|
let mut split: Vec<&str> = string.split(Self::HASH_SEP).collect();
|
|
|
if split.len() != 2 {
|
|
|
return Err(Error::InvalidHashFormat);
|
|
@@ -324,17 +660,63 @@ impl TryFrom<&str> for Hash {
|
|
|
.ok_or(Error::InvalidHashFormat)?
|
|
|
.parse::<usize>()
|
|
|
.map_err(|_| Error::InvalidHashFormat)?;
|
|
|
- let mut hash = Hash::from(HashKind::from_repr(first).ok_or(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 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_kind as u32, Hash::HASH_SEP, hash_data)
|
|
|
+ write!(f, "{}{}{}", hash_kind as u32, VarHash::HASH_SEP, hash_data)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+pub struct VarHashOp {
|
|
|
+ kind: HashKind,
|
|
|
+ hasher: Hasher,
|
|
|
+}
|
|
|
+
|
|
|
+impl Op for VarHashOp {
|
|
|
+ type Arg = HashKind;
|
|
|
+
|
|
|
+ fn init(arg: Self::Arg) -> Result<Self> {
|
|
|
+ let hasher = Hasher::new(arg.into())?;
|
|
|
+ Ok(VarHashOp { kind: arg, hasher })
|
|
|
+ }
|
|
|
+
|
|
|
+ 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(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)
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -606,17 +988,23 @@ impl KeyLen {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+/// A Cryptographic Scheme. This is a common type for operations such as encrypting, decrypting,
|
|
|
+/// signing and verifying.
|
|
|
pub trait Scheme:
|
|
|
for<'de> Deserialize<'de> + Serialize + Copy + std::fmt::Debug + PartialEq + Into<Self::Kind>
|
|
|
{
|
|
|
type Kind: Scheme;
|
|
|
fn as_enum(self) -> SchemeKind;
|
|
|
- fn message_digest(&self) -> MessageDigest;
|
|
|
+ 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) -> KeyLen;
|
|
|
+
|
|
|
+ fn message_digest(&self) -> MessageDigest {
|
|
|
+ self.hash_kind().into()
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
pub enum SchemeKind {
|
|
@@ -636,9 +1024,9 @@ impl Scheme for Encrypt {
|
|
|
SchemeKind::Encrypt(self)
|
|
|
}
|
|
|
|
|
|
- fn message_digest(&self) -> MessageDigest {
|
|
|
+ fn hash_kind(&self) -> HashKind {
|
|
|
match self {
|
|
|
- Encrypt::RsaEsOaep(inner) => inner.message_digest(),
|
|
|
+ Encrypt::RsaEsOaep(inner) => inner.hash_kind(),
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -703,9 +1091,9 @@ impl Scheme for Sign {
|
|
|
SchemeKind::Sign(self)
|
|
|
}
|
|
|
|
|
|
- fn message_digest(&self) -> MessageDigest {
|
|
|
+ fn hash_kind(&self) -> HashKind {
|
|
|
match self {
|
|
|
- Sign::RsaSsaPss(inner) => inner.message_digest(),
|
|
|
+ Sign::RsaSsaPss(inner) => inner.hash_kind(),
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -786,7 +1174,7 @@ impl Scheme for RsaEsOaep {
|
|
|
SchemeKind::Encrypt(self.into())
|
|
|
}
|
|
|
|
|
|
- fn message_digest(&self) -> MessageDigest {
|
|
|
+ fn hash_kind(&self) -> HashKind {
|
|
|
self.hash_kind.into()
|
|
|
}
|
|
|
|
|
@@ -830,7 +1218,7 @@ impl Scheme for RsaSsaPss {
|
|
|
SchemeKind::Sign(self.into())
|
|
|
}
|
|
|
|
|
|
- fn message_digest(&self) -> MessageDigest {
|
|
|
+ fn hash_kind(&self) -> HashKind {
|
|
|
self.hash_kind.into()
|
|
|
}
|
|
|
|
|
@@ -989,7 +1377,7 @@ 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 = Hash::from(kind);
|
|
|
+ let mut hash_buf = VarHash::from(kind);
|
|
|
hash_buf.as_mut().copy_from_slice(&bytes);
|
|
|
Principal(hash_buf)
|
|
|
}
|
|
@@ -1032,6 +1420,12 @@ impl Decrypter for AsymKey<Private, Encrypt> {
|
|
|
}
|
|
|
|
|
|
impl Signer for AsymKey<Private, Sign> {
|
|
|
+ type Op<'s> = OsslSignOp<'s>;
|
|
|
+
|
|
|
+ fn init_sign<'s>(&'s self) -> Result<Self::Op<'s>> {
|
|
|
+ OsslSignOp::init((self.scheme, self.pkey.as_ref()))
|
|
|
+ }
|
|
|
+
|
|
|
fn sign<'a, I: Iterator<Item = &'a [u8]>>(&self, parts: I) -> Result<Signature> {
|
|
|
let mut signer = OsslSigner::new(self.scheme.message_digest(), &self.pkey)?;
|
|
|
if let Some(padding) = self.scheme.padding() {
|
|
@@ -1047,6 +1441,12 @@ impl Signer for AsymKey<Private, Sign> {
|
|
|
}
|
|
|
|
|
|
impl Verifier for AsymKey<Public, Sign> {
|
|
|
+ type Op<'v> = OsslVerifyOp<'v>;
|
|
|
+
|
|
|
+ fn init_verify<'v>(&'v self) -> Result<Self::Op<'v>> {
|
|
|
+ OsslVerifyOp::init((self.scheme, self.pkey.as_ref()))
|
|
|
+ }
|
|
|
+
|
|
|
fn verify<'a, I: Iterator<Item = &'a [u8]>>(&self, parts: I, signature: &[u8]) -> Result<()> {
|
|
|
let mut verifier = OsslVerifier::new(self.scheme.message_digest(), &self.pkey)?;
|
|
|
if let Some(padding) = self.scheme.padding() {
|
|
@@ -1097,12 +1497,22 @@ impl Decrypter for AsymKeyPair<Encrypt> {
|
|
|
}
|
|
|
|
|
|
impl Signer for AsymKeyPair<Sign> {
|
|
|
+ type Op<'s> = <AsymKey<Private, Sign> as Signer>::Op<'s>;
|
|
|
+ fn init_sign<'s>(&'s self) -> Result<Self::Op<'s>> {
|
|
|
+ self.private.init_sign()
|
|
|
+ }
|
|
|
fn sign<'a, I: Iterator<Item = &'a [u8]>>(&self, parts: I) -> Result<Signature> {
|
|
|
self.private.sign(parts)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
impl Verifier for AsymKeyPair<Sign> {
|
|
|
+ type Op<'v> = OsslVerifyOp<'v>;
|
|
|
+
|
|
|
+ fn init_verify<'v>(&'v self) -> Result<Self::Op<'v>> {
|
|
|
+ self.public.init_verify()
|
|
|
+ }
|
|
|
+
|
|
|
fn verify<'a, I: Iterator<Item = &'a [u8]>>(&self, parts: I, signature: &[u8]) -> Result<()> {
|
|
|
self.public.verify(parts, signature)
|
|
|
}
|
|
@@ -1127,6 +1537,12 @@ impl Encrypter for PublicCreds {
|
|
|
}
|
|
|
|
|
|
impl Verifier for PublicCreds {
|
|
|
+ type Op<'v> = OsslVerifyOp<'v>;
|
|
|
+
|
|
|
+ fn init_verify<'v>(&'v self) -> Result<Self::Op<'v>> {
|
|
|
+ self.sign.init_verify()
|
|
|
+ }
|
|
|
+
|
|
|
fn verify<'a, I: Iterator<Item = &'a [u8]>>(&self, parts: I, signature: &[u8]) -> Result<()> {
|
|
|
self.sign.verify(parts, signature)
|
|
|
}
|
|
@@ -1173,6 +1589,12 @@ impl ConcreteCreds {
|
|
|
}
|
|
|
|
|
|
impl Verifier for ConcreteCreds {
|
|
|
+ type Op<'v> = OsslVerifyOp<'v>;
|
|
|
+
|
|
|
+ fn init_verify<'v>(&'v self) -> Result<Self::Op<'v>> {
|
|
|
+ self.sign.init_verify()
|
|
|
+ }
|
|
|
+
|
|
|
fn verify<'a, I: Iterator<Item = &'a [u8]>>(&self, parts: I, signature: &[u8]) -> Result<()> {
|
|
|
self.sign.verify(parts, signature)
|
|
|
}
|
|
@@ -1197,6 +1619,12 @@ impl CredsPub for ConcreteCreds {
|
|
|
}
|
|
|
|
|
|
impl Signer for ConcreteCreds {
|
|
|
+ type Op<'s> = <AsymKeyPair<Sign> as Signer>::Op<'s>;
|
|
|
+
|
|
|
+ fn init_sign<'s>(&'s self) -> Result<Self::Op<'s>> {
|
|
|
+ self.sign.init_sign()
|
|
|
+ }
|
|
|
+
|
|
|
fn sign<'a, I: Iterator<Item = &'a [u8]>>(&self, parts: I) -> Result<Signature> {
|
|
|
self.sign.sign(parts)
|
|
|
}
|
|
@@ -1249,11 +1677,92 @@ pub trait DecrypterExt: Decrypter {
|
|
|
|
|
|
impl<T: Decrypter + ?Sized> DecrypterExt for T {}
|
|
|
|
|
|
+/// Represents an ongoing signing operation.
|
|
|
+pub trait SignOp: Op {
|
|
|
+ /// Returns the signature scheme that this operation is using.
|
|
|
+ fn scheme(&self) -> Sign;
|
|
|
+
|
|
|
+ /// Finishes this signature operation and returns a new signature containing the result.
|
|
|
+ fn finish(self) -> Result<Signature> {
|
|
|
+ let scheme = self.scheme();
|
|
|
+ let mut sig = Signature::empty(scheme);
|
|
|
+ self.finish_into(sig.as_mut())?;
|
|
|
+ Ok(sig)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+pub struct OsslSignOp<'a> {
|
|
|
+ signer: OsslSigner<'a>,
|
|
|
+ scheme: Sign,
|
|
|
+}
|
|
|
+
|
|
|
+impl<'a> Op for OsslSignOp<'a> {
|
|
|
+ type Arg = (Sign, &'a PKeyRef<Private>);
|
|
|
+
|
|
|
+ fn init(arg: Self::Arg) -> 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 })
|
|
|
+ }
|
|
|
+
|
|
|
+ fn update(&mut self, data: &[u8]) -> Result<()> {
|
|
|
+ Ok(self.signer.update(data)?)
|
|
|
+ }
|
|
|
+
|
|
|
+ fn finish_into(self, buf: &mut [u8]) -> Result<usize> {
|
|
|
+ Ok(self.signer.sign(buf)?)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+impl<'a> SignOp for OsslSignOp<'a> {
|
|
|
+ fn scheme(&self) -> Sign {
|
|
|
+ self.scheme
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/// A struct which computes a signature over data as it is written to it.
|
|
|
+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(self, buf: &mut [u8]) -> Result<(usize, T)> {
|
|
|
+ Ok((self.op.finish_into(buf)?, self.inner))
|
|
|
+ }
|
|
|
+
|
|
|
+ pub fn finish(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 {
|
|
|
+ type Op<'s>: SignOp
|
|
|
+ where
|
|
|
+ Self: 's;
|
|
|
+
|
|
|
+ /// Starts a new signing operation and returns the struct representing it.
|
|
|
+ fn init_sign<'s>(&'s self) -> Result<Self::Op<'s>>;
|
|
|
fn sign<'a, I: Iterator<Item = &'a [u8]>>(&self, parts: I) -> Result<Signature>;
|
|
|
-}
|
|
|
|
|
|
-pub trait SignerExt: Signer {
|
|
|
fn ser_sign<T: Serialize>(&self, value: &T) -> Result<Signed<T>> {
|
|
|
let data = to_vec(value)?;
|
|
|
let sig = self.sign(std::iter::once(data.as_slice()))?;
|
|
@@ -1265,23 +1774,120 @@ pub trait SignerExt: Signer {
|
|
|
writecap.signature = signed.sig;
|
|
|
Ok(())
|
|
|
}
|
|
|
+
|
|
|
+ fn ser_sign_into<T: Serialize>(&self, value: &T, buf: &mut Vec<u8>) -> Result<Signature> {
|
|
|
+ write_to(value, buf)?;
|
|
|
+ let sig = self.sign(std::iter::once(buf.as_slice()))?;
|
|
|
+ Ok(sig)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+pub trait VerifyOp: Sized {
|
|
|
+ type Arg;
|
|
|
+
|
|
|
+ fn init(arg: Self::Arg) -> Result<Self>;
|
|
|
+
|
|
|
+ fn update(&mut self, data: &[u8]) -> Result<()>;
|
|
|
+
|
|
|
+ fn finish(self, sig: &[u8]) -> Result<()>;
|
|
|
+
|
|
|
+ fn scheme(&self) -> Sign;
|
|
|
+}
|
|
|
+
|
|
|
+pub struct OsslVerifyOp<'a> {
|
|
|
+ verifier: OsslVerifier<'a>,
|
|
|
+ scheme: Sign,
|
|
|
+}
|
|
|
+
|
|
|
+impl<'a> VerifyOp for OsslVerifyOp<'a> {
|
|
|
+ type Arg = (Sign, &'a PKeyRef<Public>);
|
|
|
+
|
|
|
+ fn init(arg: Self::Arg) -> Result<Self> {
|
|
|
+ let scheme = arg.0;
|
|
|
+ let mut verifier = OsslVerifier::new(scheme.message_digest(), arg.1)?;
|
|
|
+ if let Some(padding) = scheme.padding() {
|
|
|
+ verifier.set_rsa_padding(padding)?;
|
|
|
+ }
|
|
|
+ Ok(OsslVerifyOp { verifier, scheme })
|
|
|
+ }
|
|
|
+
|
|
|
+ fn update(&mut self, data: &[u8]) -> Result<()> {
|
|
|
+ Ok(self.verifier.update(data)?)
|
|
|
+ }
|
|
|
+
|
|
|
+ fn finish(self, sig: &[u8]) -> Result<()> {
|
|
|
+ match self.verifier.verify(sig) {
|
|
|
+ Ok(true) => Ok(()),
|
|
|
+ Ok(false) => Err(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(self, sig: &[u8]) -> std::result::Result<T, (T, Error)> {
|
|
|
+ if self.update_failed {
|
|
|
+ return Err((
|
|
|
+ self.inner,
|
|
|
+ Error::custom("VerifyRead::finish: update_failed was true"),
|
|
|
+ ));
|
|
|
+ }
|
|
|
+ match self.op.finish(sig) {
|
|
|
+ Ok(_) => Ok(self.inner),
|
|
|
+ Err(err) => Err((self.inner, err)),
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
-impl<T: Signer + ?Sized> SignerExt for T {}
|
|
|
+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(Error::custom("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 {
|
|
|
+ type Op<'v>: VerifyOp
|
|
|
+ where
|
|
|
+ Self: 'v;
|
|
|
+
|
|
|
+ fn init_verify<'v>(&'v self) -> Result<Self::Op<'v>>;
|
|
|
+
|
|
|
fn verify<'a, I: Iterator<Item = &'a [u8]>>(&self, parts: I, signature: &[u8]) -> Result<()>;
|
|
|
-}
|
|
|
|
|
|
-pub trait VerifierExt: Verifier {
|
|
|
fn ser_verify<T: Serialize>(&self, value: &T, signature: &[u8]) -> Result<()> {
|
|
|
let data = to_vec(value)?;
|
|
|
self.verify(std::iter::once(data.as_slice()), signature)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-impl<T: Verifier + ?Sized> VerifierExt for T {}
|
|
|
-
|
|
|
/// Trait for types which can be used as public credentials.
|
|
|
pub trait CredsPub: Verifier + Encrypter + Principaled {
|
|
|
/// Returns a reference to the public signing key which can be used to verify signatures.
|
|
@@ -1452,8 +2058,9 @@ impl Writecap {
|
|
|
mod tests {
|
|
|
use super::*;
|
|
|
use crate::{
|
|
|
- crypto::secret_stream::SecretStream, test_helpers::*, BrotliParams, Sectored, SectoredBuf,
|
|
|
- TryCompose,
|
|
|
+ crypto::secret_stream::SecretStream,
|
|
|
+ test_helpers::{self, *},
|
|
|
+ BrotliParams, Sectored, SectoredBuf, TryCompose,
|
|
|
};
|
|
|
use std::{
|
|
|
io::{Seek, SeekFrom},
|
|
@@ -1492,7 +2099,7 @@ mod tests {
|
|
|
fn hash_to_string_round_trip() -> Result<()> {
|
|
|
let expected = make_principal().0;
|
|
|
let string = expected.to_string();
|
|
|
- let actual = Hash::try_from(string.as_str())?;
|
|
|
+ let actual = VarHash::try_from(string.as_str())?;
|
|
|
assert_eq!(expected, actual);
|
|
|
Ok(())
|
|
|
}
|
|
@@ -1551,7 +2158,7 @@ mod tests {
|
|
|
#[test]
|
|
|
fn verify_writecap_invalid_not_chained() -> Result<()> {
|
|
|
let (mut root_writecap, root_key) = make_self_signed_writecap();
|
|
|
- root_writecap.body.issued_to = Principal(Hash::Sha2_256([0; 32]));
|
|
|
+ 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(
|
|
@@ -1567,7 +2174,7 @@ mod tests {
|
|
|
#[test]
|
|
|
fn verify_writecap_invalid_root_doesnt_own_path() -> Result<()> {
|
|
|
let (mut root_writecap, root_key) = make_self_signed_writecap();
|
|
|
- let owner = Principal(Hash::Sha2_256([0; 32]));
|
|
|
+ let owner = Principal(VarHash::from(HashKind::Sha2_256));
|
|
|
root_writecap.body.path = make_path_with_root(owner, vec![]);
|
|
|
root_key.sign_writecap(&mut root_writecap)?;
|
|
|
let node_principal = NODE_CREDS.principal();
|
|
@@ -1659,6 +2266,142 @@ mod tests {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ 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>::init(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());
|
|
|
+ }
|
|
|
+
|
|
|
+ /// Tests that the hash computed using an `OsslHashOp` is the same as the one returned by the
|
|
|
+ /// `HashKind::digest` method.
|
|
|
+ #[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);
|
|
|
+ }
|
|
|
+
|
|
|
+ /// Tests that a `HashWrap` instance calculates the same hash as a call to the `digest` method.
|
|
|
+ #[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>::init(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);
|
|
|
+ }
|
|
|
+
|
|
|
+ /// Tests that the `VarHash` computed by `VarHashOp` is the same as the one returned by the
|
|
|
+ /// `digest` method.
|
|
|
+ #[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::init(HashKind::Sha2_512).unwrap();
|
|
|
+
|
|
|
+ for part in parts.iter() {
|
|
|
+ op.update(part.as_slice()).unwrap();
|
|
|
+ }
|
|
|
+ let actual = op.finish().unwrap();
|
|
|
+
|
|
|
+ assert_eq!(expected, actual);
|
|
|
+ }
|
|
|
+
|
|
|
+ /// Tests that the signature produced by `OsslSignOp` can be verified.
|
|
|
+ #[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(get_parts(), sig.as_ref())
|
|
|
+ .expect("verify failed");
|
|
|
+ }
|
|
|
+
|
|
|
+ /// Tests that the signature produced by a `SignWrite` can be verified.
|
|
|
+ #[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(std::iter::once(array.as_slice()), sig.as_ref())
|
|
|
+ .expect("verify failed");
|
|
|
+ }
|
|
|
+
|
|
|
+ /// Tests that data signed using a `SignWrite` can later be verified using a `VerifyRead`.
|
|
|
+ #[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");
|
|
|
+ }
|
|
|
+
|
|
|
/// Tests that validate the dependencies of this module.
|
|
|
mod dependency_tests {
|
|
|
use super::*;
|