use std::io;
use std::io::Write;
use rust_crypto::aessafe::AesSafe128Encryptor;
use rust_crypto::buffer::BufferResult;
use rust_crypto::buffer::RefReadBuffer;
use rust_crypto::buffer::RefWriteBuffer;
use rust_crypto::buffer::WriteBuffer;
use rust_crypto::blockmodes::CbcEncryptor;
use rust_crypto::blockmodes::EncPadding;
use rust_crypto::blockmodes::PkcsPadding;
use rust_crypto::symmetriccipher::Encryptor;
use ::misc::*;
use ::zbackup::data::*;
type EncryptorType =
CbcEncryptor <
AesSafe128Encryptor,
EncPadding <PkcsPadding>,
>;
pub struct CryptoWriter <Target: Write> {
target: Target,
encryptor: EncryptorType,
plaintext_eof: bool,
ciphertext_buffer: [u8; BUFFER_SIZE],
ciphertext_eof: bool,
}
impl <Target: Write> CryptoWriter <Target> {
pub fn wrap (
target: Target,
encryption_key: [u8; KEY_SIZE],
) -> io::Result <CryptoWriter <Target>> {
let encryptor =
CbcEncryptor::new (
AesSafe128Encryptor::new (
& encryption_key),
PkcsPadding,
[0u8; KEY_SIZE].to_vec ());
Ok (CryptoWriter {
target: target,
encryptor: encryptor,
plaintext_eof: false,
ciphertext_buffer: [0u8; BUFFER_SIZE],
ciphertext_eof: false,
})
}
fn encrypt_and_write (
& mut self,
plaintext_buffer: & [u8],
) -> io::Result <()> {
assert! (
! self.ciphertext_eof);
let mut read_buffer =
RefReadBuffer::new (
plaintext_buffer);
loop {
let bytes_out;
let encrypt_result;
{
let mut write_buffer =
RefWriteBuffer::new (
& mut self.ciphertext_buffer);
encrypt_result =
self.encryptor.encrypt (
& mut read_buffer,
& mut write_buffer,
self.plaintext_eof,
).map_err (
|_|
io::Error::new (
io::ErrorKind::InvalidData,
"Encryption failed")
) ?;
bytes_out =
write_buffer.position ();
}
self.target.write (
& self.ciphertext_buffer [
0 .. bytes_out],
) ?;
match encrypt_result {
BufferResult::BufferUnderflow =>
break,
BufferResult::BufferOverflow =>
continue,
};
}
if self.plaintext_eof {
self.ciphertext_eof = true;
}
Ok (())
}
}
impl <Target: Write> Write for CryptoWriter <Target> {
fn write (
& mut self,
buffer: & [u8],
) -> io::Result <usize> {
if self.plaintext_eof {
panic! (
"Attempt to write to closed CryptoWriter");
}
self.encrypt_and_write (
buffer,
) ?;
Ok (buffer.len ())
}
fn flush (
& mut self,
) -> Result <(), io::Error> {
Ok (())
}
}
impl <Target: Write> CloseableWrite for CryptoWriter <Target> {
fn close (
& mut self,
) -> io::Result <()> {
self.plaintext_eof = true;
self.encrypt_and_write (
& [0u8; 0],
) ?;
self.target.flush ()
}
}