#[cfg(feature = "encryption")]
pub mod sync {
use crate::encryption::{AesDecryptor, AesStrength};
use crate::error::Result;
use std::io::{self, Read};
pub struct DecryptingReader<R: Read> {
inner: R,
decryptor: AesDecryptor,
auth_code: Vec<u8>,
}
impl<R: Read> DecryptingReader<R> {
pub fn new(
inner: R,
password: &str,
strength: AesStrength,
salt: &[u8],
pw_verify: &[u8; 2],
auth_code: Vec<u8>,
) -> Result<Self> {
let decryptor = AesDecryptor::new(password, strength, salt, pw_verify)?;
Ok(Self {
inner,
decryptor,
auth_code,
})
}
pub fn finish(self) -> Result<()> {
self.decryptor.verify_auth_code(&self.auth_code)
}
}
impl<R: Read> Read for DecryptingReader<R> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
let n = self.inner.read(buf)?;
if n > 0 {
self.decryptor
.decrypt(&mut buf[..n])
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e.to_string()))?;
self.decryptor.update_hmac(&buf[..n]);
}
Ok(n)
}
}
}
#[cfg(all(feature = "encryption", feature = "async"))]
pub mod r#async {
use crate::encryption::{AesDecryptor, AesStrength};
use crate::error::Result;
use std::pin::Pin;
use std::task::{Context, Poll};
use tokio::io::{AsyncRead, ReadBuf};
pub struct AsyncDecryptingReader<R: AsyncRead + Unpin> {
inner: R,
decryptor: AesDecryptor,
auth_code: Vec<u8>,
}
impl<R: AsyncRead + Unpin> AsyncDecryptingReader<R> {
pub fn new(
inner: R,
password: &str,
strength: AesStrength,
salt: &[u8],
pw_verify: &[u8; 2],
auth_code: Vec<u8>,
) -> Result<Self> {
let decryptor = AesDecryptor::new(password, strength, salt, pw_verify)?;
Ok(Self {
inner,
decryptor,
auth_code,
})
}
pub fn finish(self) -> Result<()> {
self.decryptor.verify_auth_code(&self.auth_code)
}
}
impl<R: AsyncRead + Unpin> AsyncRead for AsyncDecryptingReader<R> {
fn poll_read(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &mut ReadBuf<'_>,
) -> Poll<std::io::Result<()>> {
let this = self.get_mut();
let filled_before = buf.filled().len();
let result = Pin::new(&mut this.inner).poll_read(cx, buf);
if let Poll::Ready(Ok(())) = &result {
let new_bytes = &mut buf.filled_mut()[filled_before..];
if !new_bytes.is_empty() {
this.decryptor
.decrypt(new_bytes)
.map_err(|e| {
std::io::Error::new(std::io::ErrorKind::InvalidData, e.to_string())
})
.ok(); this.decryptor.update_hmac(new_bytes);
}
}
result
}
}
}