use std::io;
use std::io::Read;
use std::fs::File;
use std::path::Path;
use ring::digest;
use bcder::{decode, encode};
use bcder::decode::DecodeError;
use bcder::encode::PrimitiveContent;
use bcder::Tag;
use crate::oid;
pub use ring::digest::Digest;
#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
pub struct DigestAlgorithm(());
impl DigestAlgorithm {
pub fn sha256() -> Self {
DigestAlgorithm(())
}
pub fn is_sha256(self) -> bool {
true
}
pub fn digest_len(&self) -> usize {
32
}
}
impl DigestAlgorithm {
pub fn digest(self, data: &[u8]) -> Digest {
digest::digest(&digest::SHA256, data)
}
pub fn digest_file(
self, path: impl AsRef<Path>
) -> Result<Digest, io::Error> {
let mut file = File::open(path)?;
let mut buf = [0u8; 8 * 1024];
let mut ctx = self.start();
loop {
let read = file.read(&mut buf)?;
if read == 0 {
break;
}
ctx.update(&buf[..read]);
}
Ok(ctx.finish())
}
pub fn start(self) -> Context {
Context(digest::Context::new(&digest::SHA256))
}
}
impl DigestAlgorithm {
pub fn take_from<S: decode::Source>(
cons: &mut decode::Constructed<S>
) -> Result<Self, DecodeError<S::Error>> {
cons.take_sequence(Self::from_constructed)
}
pub fn take_opt_from<S: decode::Source>(
cons: &mut decode::Constructed<S>
) -> Result<Option<Self>, DecodeError<S::Error>> {
cons.take_opt_sequence(Self::from_constructed)
}
pub fn take_set_from<S: decode::Source>(
cons: &mut decode::Constructed<S>
) -> Result<Self, DecodeError<S::Error>> {
cons.take_set(Self::take_from)
}
fn from_constructed<S: decode::Source>(
cons: &mut decode::Constructed<S>
) -> Result<Self, DecodeError<S::Error>> {
oid::SHA256.skip_if(cons)?;
cons.take_opt_null()?;
Ok(DigestAlgorithm::default())
}
pub fn skip_set<S: decode::Source>(
cons: &mut decode::Constructed<S>
) -> Result<(), DecodeError<S::Error>> {
cons.take_constructed_if(Tag::SET, |cons| {
while Self::take_opt_from(cons)?.is_some() { }
Ok(())
})
}
pub fn take_oid_from<S: decode::Source>(
cons: &mut decode::Constructed<S>,
) -> Result<Self, DecodeError<S::Error>> {
oid::SHA256.skip_if(cons)?;
Ok(Self::default())
}
pub fn encode(self) -> impl encode::Values {
encode::sequence(oid::SHA256.encode())
}
pub fn encode_set(self) -> impl encode::Values {
encode::set(
self.encode()
)
}
pub fn encode_oid(self) -> impl encode::Values {
oid::SHA256.encode()
}
}
pub fn sha1_digest(data: &[u8]) -> Digest {
digest::digest(&digest::SHA1_FOR_LEGACY_USE_ONLY, data)
}
pub fn start_sha1() -> Context {
Context(digest::Context::new(&digest::SHA1_FOR_LEGACY_USE_ONLY))
}
#[derive(Clone)]
pub struct Context(digest::Context);
impl Context {
pub fn update(&mut self, data: &[u8]) {
self.0.update(data)
}
pub fn finish(self) -> Digest {
self.0.finish()
}
}
impl io::Write for Context {
fn write(&mut self, buf: &[u8]) -> Result<usize, io::Error> {
self.update(buf);
Ok(buf.len())
}
fn flush(&mut self) -> Result<(), io::Error> {
Ok(())
}
}