use crate::error::Result;
use crate::mechanism::{Digest, MechOperation};
use crate::ossl::common::{mech_type_to_digest_alg, osslctx};
use crate::pkcs11::*;
use ossl::digest::OsslDigest;
#[derive(Debug)]
pub struct HashOperation {
mech: CK_MECHANISM_TYPE,
hasher: OsslDigest,
finalized: bool,
in_use: bool,
}
impl HashOperation {
pub fn new(mech: CK_MECHANISM_TYPE) -> Result<HashOperation> {
Ok(HashOperation {
mech: mech,
hasher: OsslDigest::new(
osslctx(),
mech_type_to_digest_alg(mech)?,
None,
)?,
finalized: false,
in_use: false,
})
}
pub fn restore(
mech: CK_MECHANISM_TYPE,
state: &[u8],
) -> Result<HashOperation> {
let mut op = Self::new(mech)?;
op.hasher.set_state(state)?;
op.in_use = true;
Ok(op)
}
}
impl MechOperation for HashOperation {
fn mechanism(&self) -> Result<CK_MECHANISM_TYPE> {
Ok(self.mech)
}
fn finalized(&self) -> bool {
self.finalized
}
fn reset(&mut self) -> Result<()> {
self.hasher.reset(None)?;
self.finalized = false;
self.in_use = false;
Ok(())
}
fn state_size(&self) -> Result<usize> {
Ok(self
.hasher
.get_state_size()
.map_err(|_| CKR_STATE_UNSAVEABLE)?)
}
fn state_save(&self, state: &mut [u8]) -> Result<usize> {
Ok(self
.hasher
.get_state(state)
.map_err(|_| CKR_STATE_UNSAVEABLE)?)
}
}
impl Digest for HashOperation {
fn digest(&mut self, data: &[u8], digest: &mut [u8]) -> Result<()> {
if self.in_use || self.finalized {
return Err(CKR_OPERATION_NOT_INITIALIZED)?;
}
if digest.len() != self.hasher.size() {
return Err(CKR_GENERAL_ERROR)?;
}
self.finalized = true;
self.hasher.update(data)?;
let len = self.hasher.finalize(digest)?;
if len != digest.len() {
return Err(CKR_GENERAL_ERROR)?;
}
Ok(())
}
fn digest_update(&mut self, data: &[u8]) -> Result<()> {
if self.finalized {
return Err(CKR_OPERATION_NOT_INITIALIZED)?;
}
self.in_use = true;
match self.hasher.update(data) {
Ok(()) => Ok(()),
Err(_) => {
self.finalized = true;
Err(CKR_DEVICE_ERROR)?
}
}
}
fn digest_final(&mut self, digest: &mut [u8]) -> Result<()> {
if self.finalized {
return Err(CKR_OPERATION_NOT_INITIALIZED)?;
}
if digest.len() != self.hasher.size() {
return Err(CKR_GENERAL_ERROR)?;
}
self.finalized = true;
let len = self.hasher.finalize(digest)?;
if len != digest.len() {
return Err(CKR_GENERAL_ERROR)?;
}
Ok(())
}
fn digest_len(&self) -> Result<usize> {
Ok(self.hasher.size())
}
}