asbs/binary/carrier.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
use crate::{binary::bits, Conceal};
use std::io::{self, BufReader, BufWriter, Read, Write};
/// A binary carrier that can conceal a steganographic message.
///
/// It writes to the carrier writer in the [`conceal`][crate::Conceal::conceal] method until
/// either occurs:
///
/// 1. The writer no longer accepts any writes, which may be possible if the writer
/// is unable to contain the concealed message in its entirety, or
/// 2. The payload is empty, in which case the remainder of the cover is copied into
/// the writer, or
/// 3. The cover is empty, in which case the message remains partially written; it may
/// be possible if the cover is unable to contain the message in its concealed form.
/// In this case it is recommended to either use a bigger cover or pick a different
/// bit pattern.
///
/// # Examples
///
/// Concealing a secret message in the supplied cover:
///
/// ```no_run
/// use asbs::{binary, Conceal};
/// use std::fs::File;
///
/// let pattern = |i| Some(1u8 << (i % 3));
///
/// let cover = File::open("cover")?;
/// let payload = b"a very secret message";
///
/// let mut package = Vec::new();
///
/// let mut carrier = binary::Carrier::new(pattern, &mut package);
/// carrier.conceal(payload.as_slice(), cover)?;
/// # Ok::<(), std::io::Error>(())
/// ```
#[derive(Debug)]
pub struct Carrier<P, W>
where
P: FnMut(usize) -> Option<u8>,
W: Write,
{
pattern: P,
writer: BufWriter<W>,
}
impl<P, W> Carrier<P, W>
where
P: FnMut(usize) -> Option<u8>,
W: Write,
{
/// Creates a new [`Carrier<P, W>`] with the supplied pattern and writer.
///
/// This imposes no limits upon the number of bytes written.
///
/// # Examples
///
/// ```no_run
/// use asbs::binary;
/// use std::fs::File;
///
/// let pattern = |i| Some(if i % 2 == 0 { 1u8 << ((i % 2) + 1) } else { 0b_0001_0010 });
/// let package = File::create_new("package")?;
///
/// let mut carrier = binary::Carrier::new(pattern, package);
/// # Ok::<(), std::io::Error>(())
/// ```
#[must_use]
pub fn new(pattern: P, writer: W) -> Self {
Self {
pattern,
writer: BufWriter::new(writer),
}
}
}
impl<M, W> Conceal for &mut Carrier<M, W>
where
M: FnMut(usize) -> Option<u8>,
W: Write,
{
type Err = io::Error;
fn conceal<P: Read, C: Read>(self, payload: P, cover: C) -> io::Result<usize> {
let mut payload_bytes = BufReader::new(payload).bytes();
let mut payload_byte = match payload_bytes.next() {
Some(byte) => byte?,
None => return Ok(0),
};
let mut cover = BufReader::new(cover);
let mut bytes_written = 0usize;
let mut bit_count = 0usize;
for (index, cover_byte) in cover.by_ref().bytes().enumerate() {
let Some(mask) = (self.pattern)(index) else {
break;
};
let mut package_byte = cover_byte? & !mask;
for pow in bits::Ones::from(mask) {
package_byte |= (payload_byte & 1) << pow;
payload_byte >>= 1;
bit_count += 1;
if bit_count < 8 {
continue;
}
payload_byte = match payload_bytes.next() {
Some(byte) => byte?,
None => break,
};
bit_count = 0;
}
bytes_written += self.writer.write(&[package_byte])?;
if bit_count == 8 {
break;
}
}
bytes_written += io::copy(&mut cover, &mut self.writer)? as usize;
self.writer.flush()?;
Ok(bytes_written)
}
}