From ba9e61ace161b6f3c79f3748a1b477037a76965b Mon Sep 17 00:00:00 2001 From: ef3d0c3e Date: Sun, 18 Aug 2024 16:02:16 +0200 Subject: [PATCH] Refactored --- example/embed.png | Bin 0 -> 66807 bytes example/input.png | Bin 0 -> 64991 bytes example/test.sh | 20 ++ src/embed.rs | 140 -------------- src/header.rs | 120 ------------ src/main.rs | 359 ----------------------------------- src/{ => png_embed}/block.rs | 195 ++++++++++--------- src/png_embed/embed.rs | 54 ++++++ src/png_embed/header.rs | 139 ++++++++++++++ src/{ => png_embed}/image.rs | 0 src/png_embed/main.rs | 335 ++++++++++++++++++++++++++++++++ 11 files changed, 656 insertions(+), 706 deletions(-) create mode 100644 example/embed.png create mode 100644 example/input.png create mode 100755 example/test.sh delete mode 100644 src/embed.rs delete mode 100644 src/header.rs delete mode 100644 src/main.rs rename src/{ => png_embed}/block.rs (60%) create mode 100644 src/png_embed/embed.rs create mode 100644 src/png_embed/header.rs rename src/{ => png_embed}/image.rs (100%) create mode 100644 src/png_embed/main.rs diff --git a/example/embed.png b/example/embed.png new file mode 100644 index 0000000000000000000000000000000000000000..5e2e580d945a586475fb3c448cb501f404fe7262 GIT binary patch literal 66807 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

NAN>oH@S1zqsgML5HRgx&mE8ksEayn!@Jr-zra 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 literal 0 HcmV?d00001 diff --git a/example/input.png b/example/input.png new file mode 100644 index 0000000000000000000000000000000000000000..923315d5ef5293498f56ee71a3ae2243e51dbedb GIT binary patch literal 64991 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 literal 0 HcmV?d00001 diff --git a/example/test.sh b/example/test.sh new file mode 100755 index 0000000..f05db6b --- /dev/null +++ b/example/test.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash + +PNG_EMBED=../target/debug/png_embed +[ ! -f "${PNG_EMBED}" ] && PNG_EMBED=../target/release/png_embed +[ ! -f "${PNG_EMBED}" ] && echo "Failed to find png_embed executable" && exit + +echo "Encoding..." +for i in {1..7}; do + echo "Writing dec-lo${i}.." + $PNG_EMBED -l lo${i} -e embed.png input.png -o out-lo${i}.png +done + +echo "Decoding..." +for i in {1..7}; do + echo "Decoding out-lo${i} -> dec-lo${i}.." + $PNG_EMBED -l lo${i} -d out-lo${i}.png -o dec-lo${i}.png +done + +echo "Checksums:" +sha256sum embed.png dec-lo*.png # That's nuts! diff --git a/src/embed.rs b/src/embed.rs deleted file mode 100644 index 350ba0b..0000000 --- a/src/embed.rs +++ /dev/null @@ -1,140 +0,0 @@ -use std::fmt::Formatter; -use std::str::FromStr; - -use bitvec::slice::BitSlice; -use bitvec::vec::BitVec; - -use crate::block::BlockMode; -use crate::image::ImageInfo; - -#[derive(Debug)] -pub enum EmbedAlgorithm { - Lo(u8), -} - -impl EmbedAlgorithm { - /// Get the size of the data (in bytes) once embedded by the algorithm - pub fn embedded_size(&self, size: usize) -> usize { - match self { - EmbedAlgorithm::Lo(bits) => ((size * 8) as f64 / *bits as f64).ceil() as usize, - } - } - - pub fn max_size(&self, blockmode: &BlockMode, info: &Box) -> usize { - let blocks_num = info.size() / blockmode.len; - - match self { - EmbedAlgorithm::Lo(bits) => { - (((blockmode.len - blockmode.crc_len) * blocks_num) as f64 * (*bits as f64) / 8f64) - .floor() as usize - } - } - } - - pub fn next_block( - &self, - original_data: &mut [u8], - mut data_pos: usize, - embed_data: &BitVec, - mut embed_offset: usize, - blockmode: &BlockMode, - ) -> (usize, usize) { - match self { - EmbedAlgorithm::Lo(bits) => { - let mask = (1 << bits) - 1; - - fn bits_to_byte(slice: &BitSlice, bits: u8) -> u8 { - let mut result: u8 = 0; - for i in 0..bits { - result |= (slice[i as usize] as u8) << i; - } - result - } - - let start = embed_offset; - while embed_offset - start < (blockmode.len - blockmode.crc_len) * 8 { - let hi = std::cmp::min(*bits as usize, embed_data.len() - embed_offset); - let embed = bits_to_byte( - embed_data.get(embed_offset..embed_offset + hi).unwrap(), - hi as u8, - ); - - original_data[data_pos] &= !mask; - original_data[data_pos] |= embed; - - data_pos += 1; - embed_offset += hi; - } - - // TODO: WRITE CRC - } - } - - (data_pos, embed_offset) - } - - pub fn read_block( - &self, - encoded_data: &[u8], - mut data_pos: usize, - incoming: &mut BitVec, - blockmode: &BlockMode, - ) -> usize { - match self { - EmbedAlgorithm::Lo(bits) => { - fn push(vec: &mut BitVec, bits: u8, b: u8) { - for i in 0..bits { - vec.push((b >> i) & 0b1 == 0b1) - } - } - - let start = incoming.len(); - while incoming.len() - start < (blockmode.len - blockmode.crc_len) * 8 { - push(incoming, *bits, encoded_data[data_pos]); - data_pos += 1; - } - - // TODO: Read CRC and verify - } - } - - data_pos - } -} - -impl core::fmt::Display for EmbedAlgorithm { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - match self { - EmbedAlgorithm::Lo(bits) => write!(f, "Lo({bits})"), - } - } -} - -impl FromStr for EmbedAlgorithm { - type Err = String; - - fn from_str(s: &str) -> Result { - let (dig_pos, _) = s - .char_indices() - .find(|(_, c)| c.is_ascii_digit()) - .ok_or(format!("Unknown algorithm: {s}"))?; - - let (first, second) = s.split_at(dig_pos); - match first { - "lo" => { - let value = second.parse::().map_err(|err| { - format!("Failed to convert `{second}` to a number of bits: {err}") - })?; - // TODO: We can allow more than 8 bits, depending on the image's bit depth - if value > 8 || value == 0 { - Err(format!( - "Cannot specify {value} bits for `lo` method, must be within [1, 8]" - )) - } else { - Ok(EmbedAlgorithm::Lo(value)) - } - } - _ => Err(format!("Unknown algorithm: {s}")), - } - } -} diff --git a/src/header.rs b/src/header.rs deleted file mode 100644 index 59eb53f..0000000 --- a/src/header.rs +++ /dev/null @@ -1,120 +0,0 @@ -use bitvec::{slice::BitSlice, vec::BitVec}; -use crc::Crc; - -use crate::block::BlockMode; - -#[repr(u16)] -#[allow(non_camel_case_types)] -#[derive(Debug, Clone, Copy)] -pub enum Version { - VERSION_1, -} - -pub trait Encode { - // Encode the data - fn encode(&self, vec: &mut Vec); -} - -//pub trait Decode { -// fn decode(incoming: &mut EmbedIterator) -> (usize, Self); -//} - -#[derive(Debug)] -pub struct Header { - version: Version, - block_size: usize, - data_len: u32, - data_crc: u32, - comment: Option, -} - - -impl Header { - pub fn new(version: Version, block_size: usize, data: &[u8], comment: Option) -> Self { - assert_eq!((data.len() as u32) as usize, data.len()); - assert_eq!(1 << usize::trailing_zeros(block_size), block_size); - assert!(comment.as_ref().map_or(0, |c| c.len()) < u16::MAX as usize); - - Self { - version, - block_size, - data_len: data.len() as u32, - data_crc: Crc::::new(&crc::CRC_32_CKSUM).checksum(data), - comment, - } - } - /* - pub fn to_data(&self, version: u16, embed_len: u32) -> Vec { - let mut header = vec![]; - - // Version - header.extend_from_slice(version.to_le_bytes().as_slice()); - - // TODO: IV+Cipherinfo - // Blockmode - header.push(self.blockmode.to_data().to_le()); - - // Data len - header.extend_from_slice(embed_len.to_le_bytes().as_slice()); - - // Comment len - let comment_len = self.comment.as_ref().map(|c| c.len() as u16).unwrap_or(0 as u16); - header.extend_from_slice(comment_len.to_le_bytes().as_slice()); - - // Comment - if let Some(comment) = &self.comment { - header.extend_from_slice(comment.as_bytes()); - } - - header - } - - pub fn from_data(slice: &BitSlice) -> (u16, BlockMode, u32, u16) { - fn read_byte(slice: &bitvec::slice::BitSlice) -> u8 - { - let mut result = 0; - for i in 0..8 - { - result |= (slice[i as usize] as u8) << i; - } - result - } - - let version = ((read_byte(&slice[8..16]) as u16) << 8) | (read_byte(&slice[0..8]) as u16); - let blockmode = BlockMode::from_byte(read_byte(&slice[16..24])); - let len = ((read_byte(&slice[48..56]) as u32) << 24) - | ((read_byte(&slice[40..48]) as u32) << 16) - | ((read_byte(&slice[32..40]) as u32) << 8) - | (read_byte(&slice[24..32]) as u32); - let comment_len = ((read_byte(&slice[64..72]) as u16) << 8) | (read_byte(&slice[56..64]) as u16); - - - (version, blockmode, len, comment_len) - } - */ -} - -impl Encode for Header { - fn encode(&self, vec: &mut Vec) { - // Version - vec.extend_from_slice((self.version as u16).to_le_bytes().as_slice()); - - // Block size - vec.push((usize::trailing_zeros(self.block_size) as u8).to_le()); - - // Data Len - vec.extend_from_slice(self.data_len.to_le_bytes().as_slice()); - - // Data CRC - vec.extend_from_slice(self.data_crc.to_le_bytes().as_slice()); - - // Comment length - let comment_length = self.comment.as_ref().map_or(0u16, |c| c.len() as u16); - vec.extend_from_slice(comment_length.to_le_bytes().as_slice()); - - // Comment - if let Some(comment) = &self.comment { - vec.extend_from_slice(comment.as_bytes()); - } - } -} diff --git a/src/main.rs b/src/main.rs deleted file mode 100644 index 22252b1..0000000 --- a/src/main.rs +++ /dev/null @@ -1,359 +0,0 @@ -pub mod block; -pub mod embed; -pub mod header; -pub mod image; - -use std::env; -use std::fs::File; -use std::io::BufWriter; -use std::io::Read; -use std::io::Write; -use std::process::ExitCode; -use std::str::FromStr; - -use bitvec::vec::BitVec; -use block::BlockMode; -use block::BlockPlacement; -use embed::EmbedAlgorithm; -use getopts::Matches; -use getopts::Options; -use header::Header; -use image::ImageInfo; -use rand::SeedableRng; -use rand_chacha::ChaCha8Rng; -use rand::Rng; -use rand::prelude::SliceRandom; -use bitvec::prelude::*; - -fn print_usage(program: &str, opts: Options) { - let brief = format!( - "Usage: {0} -(e|d|i) FILE [opts] - Encode: {0} -e file.tar -l rgba8 -c \"(.tar) my archive\" > out.png - Decode: {0} -d out.png > file.tar - Info: {0} -i out.png # (.tar) my archive", - program - ); - print!("{}", opts.usage(&brief)); -} - -fn print_version() { - print!( - "png_data -- Embed data into PNG\n -Public domain\n" - ); -} - -/* -impl ImageInfo for png::OutputInfo { - fn width(&self) -> u32 { self.width } - - fn height(&self) -> u32 { self.height } - - fn size(&self) -> usize { self.buffer_size() } - - fn encode(&self, w: &mut BufWriter>, data: Vec) { - let mut encoder = png::Encoder::new(w, self.width(), self.height()); - encoder.set_color(self.color_type); - encoder.set_depth(self.bit_depth); - let mut writer = encoder.write_header().unwrap(); - writer.write_image_data(data.as_slice()).unwrap(); - println!("Ok"); - } -} - -fn get_algorithm(s: Option) -> Result { - if let Some(s) = &s { - EmbedAlgorithm::from_str(s.as_str()) - } else { - Err("Missing required algorithm parameter".into()) - } -} - -fn get_blockmode(s: Option) -> Result { - if let Some(s) = &s { - BlockMode::from_str(s) - } else { - Err("Missing requires blockmode parameter".into()) - } -} - -fn decode_image(image: String) -> Result<(Vec, Box), String> { - match image.split_at(image.find('.').unwrap_or(0)).1 { - ".png" => { - let decoder = png::Decoder::new( - File::open(&image).map_err(|err| format!("Failed to read `{image}`: {err}"))?, - ); - let mut reader = decoder - .read_info() - .map_err(|err| format!("Failed to read png info for `{image}`: {err}"))?; - let mut result = Vec::with_capacity(reader.output_buffer_size()); - result.resize(reader.output_buffer_size(), 0); - let info = reader - .next_frame(result.as_mut_slice()) - .map_err(|err| format!("Failed to read png info for `{image}`: {err}"))?; - result.resize(info.buffer_size(), 0); - - Ok((result, Box::new(info))) - } - _ => Err(format!("Unable get image type for {image}")), - } -} - -fn derive_seed(seed: &str) -> Result<[u8; 32], String> { - let mut result = [0u8; 32]; - argon2::Argon2::default().hash_password_into(seed.as_bytes(), b"SEED SALT", &mut result) - .map_err(|err| format!("Failed to derive seed `{seed}`: {err}"))?; - Ok(result) -} - -fn decode(image: String, matches: Matches, header_only: bool) -> Result<(), String> { - let algorithm = get_algorithm(matches.opt_str("l"))?; - let crc = false; - - let (data, info) = decode_image(image)?; - let blockmode = BlockMode::from_length(info.size(), crc); - let seed = derive_seed( - matches - .opt_str("s") - .unwrap_or(format!("{}x{}", info.width(), info.height())) - .as_str(), - )?; - - println!("Blockmode: {blockmode}"); - - // Read header - let mut read_data = BitVec::::new(); - let mut data_pos = 0; - while read_data.len() < 9*8 - { - data_pos = algorithm.read_block(&data, data_pos, &mut read_data, &blockmode); - } - - let (version, blockmode, data_len, comment_len) = Header::from_data(read_data.as_bitslice()); - // Read header comment - while read_data.len() < (9+comment_len as usize)*8 - { - data_pos = algorithm.read_block(&data, data_pos, &mut read_data, &blockmode); - } - - // Extract comment: - let comment = String::from_utf8_lossy( - &read_data.as_raw_slice()[9..(9+comment_len as usize)] - ); - - println!("=== HEADER ==="); - println!("Version : {version}"); - println!("Data Len: {data_len}"); - println!("Comment : `{comment}`"); - println!("=============="); - - fn read_byte(slice: &bitvec::slice::BitSlice) -> u8 - { - let mut result = 0; - for i in 0..8 - { - result |= (slice[i as usize] as u8) << i; - } - result - } - - let data_start = 9+comment_len as usize; - while read_data.len() < (data_start + data_len as usize)*8 - { - data_pos = algorithm.read_block(&data, data_pos, &mut read_data, &blockmode); - } - - for i in 60..80 - { - let b = read_byte(&read_data[(data_start+i)*8..(data_start+1+i)*8]); - println!("{i} : {b:08b} ({})", b as char); - } - - - - let mut outfile = File::create("decode.png").unwrap(); - outfile.write( - &read_data.as_raw_slice()[data_start..data_start+data_len as usize] - ).unwrap(); - - - Ok(()) -} - -fn encode(image: String, matches: Matches) -> Result, String> { - let algorithm = get_algorithm(matches.opt_str("l"))?; - let crc = false; - let embed_file = matches - .opt_str("i") - .ok_or(format!("Embed file is required"))?; - - let (mut data, info) = decode_image(image)?; - let blockmode = BlockMode::from_length(info.size(), crc); - let seed = derive_seed( - matches - .opt_str("s") - .unwrap_or(format!("{}x{}", info.width(), info.height())) - .as_str(), - )?; - - - let max_size = algorithm.max_size(&blockmode, &info); - - let embed_data = std::fs::read(&embed_file) - .map_err(|err| format!("Failed to read embed file `{embed_file}`: {err}"))?; - - let mut rand = ChaCha8Rng::from_seed(seed); - let placement = BlockPlacement::new(data.as_mut_slice(), blockmode.len, &algorithm, embed_data.len(), &mut rand)?; - - return Ok(vec![]); - - // Get header - let header = Header { - blockmode, - comment: matches.opt_str("c"), - }; - let header_data = header.to_data(1, embed_data.len() as u32); - - // Check length - if embed_data.len() + header_data.len() > max_size { - Err(format!( - "Cannot embed {}bytes into {}bytes using the {algorithm} algorithm with blockmode {}. Max embeddable size: {max_size}bytes", - embed_data.len()+header_data.len(), - data.len(), - header.blockmode, - ))?; - } - - // Blocks to write - let blocks_num = ((header_data.len()+embed_data.len()) as f64 / (header.blockmode.len-header.blockmode.crc_len) as f64).ceil() as usize; - - // Get data - let mut bv = BitVec::::from_vec(header_data); - bv.extend_from_raw_slice(embed_data.as_slice()); - // zero-padding - while bv.len()/8 < blocks_num*header.blockmode.len - { - for i in 0..8 - { - bv.push(false); - } - } - - // Shuffle the blocks - //let mut rand = ChaCha8Rng::from_seed(seed); - //let mut blocks_pos = (0..blocks_num).collect::>(); - //blocks_pos.shuffle(&mut rand); - - - println!("-------------"); - println!("Writing: {blocks_num}x{} [{}] blocks", header.blockmode.len, header.blockmode.crc_len); - println!("Data length: {} bytes", bv.len()/8); - println!("-------------"); - - //for i in 0..9*4 { - // let b = data[i] & 0b1111; - // println!("{b:b}"); - //} - println!("====="); - - // TODO: make sure the rounding error keep this offset safe - // i.e that two blocks can't overlap - //let coffset = data.len() / (blocks_num+1); - - - let mut embed_offset = 0; - let mut data_pos = 0; - for i in 0 .. blocks_num - { - println!("block: {i}/{embed_offset}/{data_pos}"); - (data_pos, embed_offset) = algorithm.next_block( - &mut data.as_mut_slice(), - data_pos, - &bv, - embed_offset, - &header.blockmode); - } - println!("{}", bv.len()); - - - for i in 10..80 { - let b = (data[i*2] & 0b1111) | ((data[i*2+1] & 0b1111) << 4); - println!("{i}: {b:08b}, {}", b as char); - fn read_byte(slice: &bitvec::slice::BitSlice) -> u8 - { - let mut result = 0; - for i in 0..8 - { - result |= (slice[i as usize] as u8) << i; - } - result - } - println!("{i}+ {b:08b}, {}", read_byte(&bv[i*8..(i+1)*8]) as char); - } - let outfile = File::create("out.png").unwrap(); - let ref mut w = BufWriter::new(Box::new(outfile) as Box); - info.encode(w, data); - - Ok(vec![]) -} -*/ - -fn main() -> ExitCode { - let args: Vec = env::args().collect(); - let program = args[0].clone(); - - let mut opts = Options::new(); - opts.optopt("i", "input", "Input file", "PATH"); - opts.optflag("e", "encode", "Encode file"); - opts.optflag("d", "decode", "Decode mode"); - opts.optopt("c", "comment", "Header comment", "TXT"); - opts.optopt("s", "seed", "Force seed", "TXT"); - opts.optflag("", "no-crc", "Disables CRC"); - opts.optflag("z", "info", "Read information"); - opts.optopt("l", "algorithm", "Embed algorithm", "lo3"); - opts.optflag("h", "help", "Print this help menu"); - opts.optflag("v", "version", "Print program version and licenses"); - - let matches = match opts.parse(&args[1..]) { - Ok(m) => m, - Err(f) => { - panic!("{}", f.to_string()) - } - }; - if matches.opt_present("v") { - print_version(); - return ExitCode::SUCCESS; - } - if matches.opt_present("h") { - print_usage(&program, opts); - return ExitCode::SUCCESS; - } - if matches.free.is_empty() { - print_usage(&program, opts); - return ExitCode::FAILURE; - } - - /* - let input = matches.free[0].clone(); - - if matches.opt_present("z") { - match decode(input, matches, true) { - Ok(_) => todo!(""), - Err(e) => { - eprintln!("{e}"); - return ExitCode::FAILURE; - } - } - } else if matches.opt_present("e") { - match encode(input, matches) { - Ok(_) => todo!(""), - Err(e) => { - eprintln!("{e}"); - return ExitCode::FAILURE; - } - } - } - */ - - ExitCode::SUCCESS -} diff --git a/src/block.rs b/src/png_embed/block.rs similarity index 60% rename from src/block.rs rename to src/png_embed/block.rs index 3618523..3e5f9d3 100644 --- a/src/block.rs +++ b/src/png_embed/block.rs @@ -1,6 +1,3 @@ -use std::fmt::Formatter; -use std::str::FromStr; - use bitvec::slice::BitSlice; use bitvec::vec::BitVec; use rand::prelude::SliceRandom; @@ -8,80 +5,29 @@ use rand::Rng; use crate::embed::EmbedAlgorithm; -/// Block mode for embedded data -#[derive(Debug)] -pub struct BlockMode { - pub len: usize, - pub crc_len: usize, -} - -impl BlockMode { - /// Gets the best [`BlockMode`] and the remainder - pub fn from_length(len: usize, crc: bool) -> Self { - let mut best_remainder = len; - let mut best_p = 0; - for p in 4..16 { - let remainder = len % (1 << p); - if remainder <= best_remainder { - best_remainder = remainder; - best_p = p; - } - } - - Self { - len: 1 << best_p, - crc_len: (best_p / 4) * crc as usize, +/// Gets the best blocksize (i.e. that minimize remaining space) for a certain data length. +/// The blocksize is a number in range [16, 65536] +pub fn best_blocksize(len: usize) -> usize { + let mut best_remainder = len; + let mut best_p = 0; + for p in 4..16 { + let remainder = len % (1 << p); + if remainder <= best_remainder { + best_remainder = remainder; + best_p = p; } } - pub fn to_data(&self) -> u8 { - ((self.crc_len != 0) as u8) | ((u8::leading_zeros(self.len as u8) + 1) << 1) as u8 - } - - pub fn from_byte(byte: u8) -> BlockMode { - let crc = byte & 0b1; - let len = byte >> 1; - - Self { - len: 1usize << len, - crc_len: (crc * len) as usize, - } - } -} - -impl core::fmt::Display for BlockMode { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!(f, "(len: {}, crc_len: {})", self.len, self.crc_len) - } -} - -impl FromStr for BlockMode { - type Err = String; - - fn from_str(s: &str) -> Result { - let size = s - .parse::() - .map_err(|err| format!("Failed to parse `{}` as block size: {err}", s))?; - - if size < 6 || size > 16 { - Err(format!( - "Invalid block size specified: `{size}` expected value within [6; 16]" - ))?; - } - - Ok(BlockMode { - len: 1 << size, - crc_len: size, - }) - } + 1 << best_p } +/// Struct to hold the positions of data blocks #[derive(Debug)] pub struct BlockPlacement<'a> { algorithm: &'a EmbedAlgorithm, data: &'a mut [u8], block_size: usize, - blocks: Vec, + pub blocks: Vec, } impl<'a> BlockPlacement<'a> { @@ -91,8 +37,8 @@ impl<'a> BlockPlacement<'a> { // // Will fail if the data is too small to hold all the blocks pub fn new( - data: &'a mut [u8], algorithm: &'a EmbedAlgorithm, + data: &'a mut [u8], block_size: usize, embed_size: usize, rng: &mut R, @@ -132,7 +78,35 @@ impl<'a> BlockPlacement<'a> { }) } - pub fn write_embed(&mut self) + // Embeds the data into the original image + pub fn write_embed(&mut self, embed: &BitSlice) { + assert_eq!(embed.len() % 8, 0); + + fn bits_to_byte(slice: &BitSlice, bits: u8) -> u8 { + let mut result: u8 = 0; + for i in 0..bits { + result |= (slice[i as usize] as u8) << i; + } + result + } + + let mut index = 0; + match self.algorithm { + EmbedAlgorithm::Lo(bits) => { + for block in &self.blocks { + for i in 0..self.block_size { + let pos = block * self.block_size + i; + let hi = std::cmp::min(*bits as usize, embed.len() - index); + + self.data[pos] &= !((1 << hi) - 1); + self.data[pos] |= bits_to_byte(&embed[index..], hi as u8); + + index += hi; + } + } + } + } + } } // Iterator over blocks in the resulting image @@ -145,9 +119,12 @@ pub struct BlockPlacementIterator<'a> { index: usize, // Position of the blocks blocks: Vec, + // Iterator over the current block + block_it: Option>, } impl<'a> BlockPlacementIterator<'a> { + /// Creates a new embed iterator pub fn new( algorithm: &'a EmbedAlgorithm, data: &'a [u8], @@ -163,29 +140,50 @@ impl<'a> BlockPlacementIterator<'a> { // Shuffle the block order blocks.shuffle(rng); + let first_block_pos = blocks[0] * block_size; + let first_block = &data[first_block_pos..first_block_pos + block_size]; + Self { algorithm, data, block_size, index: 0, blocks, + block_it: Some(BlockIterator::new(Block(algorithm, first_block), None)), } } } impl<'a> Iterator for BlockPlacementIterator<'a> { - type Item = Block<'a>; + type Item = u8; + /// Gets the next embedded byte in the image + /// + /// # Note + /// + /// Even when the [`next()`] is Some(..), if the iterator is past the embed's length, it will + /// return garbage data. fn next(&mut self) -> Option { - if self.index == self.blocks.len() { - return None; + self.block_it.as_ref()?; + + if let Some(byte) = self.block_it.as_mut().unwrap().next() { + Some(byte) + } else { + self.index += 1; + // Get next block + if self.index == self.blocks.len() { + return None; + } + + let block_pos = self.blocks[self.index] * self.block_size; + let block = &self.data[block_pos..block_pos + self.block_size]; + self.block_it = Some(BlockIterator::new( + Block(self.algorithm, block), + self.block_it.take(), + )); + + self.next() } - - let pos = self.blocks[self.index] * self.block_size; - let slice = &self.data[pos..pos + self.block_size]; - self.index += 1; - - Some(Block(self.algorithm, slice)) } } @@ -196,7 +194,7 @@ pub struct Block<'a>(&'a EmbedAlgorithm, &'a [u8]); // Iterator to read embedded data inside a block pub struct BlockIterator<'a> { // Block of the iterator - block: &'a Block<'a>, + block: Block<'a>, // Byte position in [`data`] index: usize, @@ -206,7 +204,7 @@ pub struct BlockIterator<'a> { } impl<'a> BlockIterator<'a> { - pub fn new(block: &'a Block, previous: Option) -> Self { + pub fn new(block: Block<'a>, previous: Option) -> Self { if let Some(previous) = previous { Self { block, @@ -275,6 +273,28 @@ mod tests { use super::*; + #[test] + fn test_write() { + let algorithm = EmbedAlgorithm::Lo(2); + + let mut data = vec![0u8; 8]; + let embed = vec![0xFF, 0xFF]; + + let embed_bits = BitVec::::from_slice(embed.as_slice()); + let mut rand = ChaCha8Rng::from_seed([1u8; 32]); + let mut placement = BlockPlacement::new::<_>( + &algorithm, + data.as_mut_slice(), + 4, + embed_bits.len() / 8, + &mut rand, + ) + .unwrap(); + placement.write_embed(embed_bits.as_bitslice()); + + assert_eq!(data, vec![0b00000011; 8]); + } + #[test] fn block_iterator() { let algorithm = EmbedAlgorithm::Lo(3); @@ -284,17 +304,17 @@ mod tests { ]; let block = Block(&algorithm, &data); - let mut it = BlockIterator::new(&block, None); + let mut it = BlockIterator::new(block, None); assert_eq!(it.next(), Some(0b10_001_000)); - assert_eq!(it.next(), Some(0b0_100_011_0)); - assert_eq!(it.next(), Some(0b000_111_11)); + assert_eq!(it.next(), Some(0b0100_0110)); + assert_eq!(it.next(), Some(0b0001_1111)); } #[test] fn blockplacement_iterator() { let algorithm = EmbedAlgorithm::Lo(4); - let mut data = vec![ + let data = vec![ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, @@ -307,9 +327,10 @@ mod tests { let mut positions = (0..8).collect::>(); positions.shuffle(&mut rand); - for i in 0..8 { - let block = it.next().unwrap(); - assert_eq!(block.1[0] / 4, positions[i]); + for i in 0..data.len() / 2 { + let byte = it.next().unwrap(); + // TODO... + //assert_eq!(byte, data[positions[i/4]*4+(i%4)]); } } } diff --git a/src/png_embed/embed.rs b/src/png_embed/embed.rs new file mode 100644 index 0000000..b34c999 --- /dev/null +++ b/src/png_embed/embed.rs @@ -0,0 +1,54 @@ +use std::fmt::Formatter; +use std::str::FromStr; + +/// Algorithm to embed data +#[derive(Debug)] +pub enum EmbedAlgorithm { + Lo(u8), +} + +impl EmbedAlgorithm { + /// Get the size of the data (in bytes) once embedded by the algorithm + pub fn embedded_size(&self, size: usize) -> usize { + match self { + EmbedAlgorithm::Lo(bits) => ((size * 8) as f64 / *bits as f64).ceil() as usize, + } + } +} + +impl core::fmt::Display for EmbedAlgorithm { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + match self { + EmbedAlgorithm::Lo(bits) => write!(f, "Lo({bits})"), + } + } +} + +impl FromStr for EmbedAlgorithm { + type Err = String; + + fn from_str(s: &str) -> Result { + let (dig_pos, _) = s + .char_indices() + .find(|(_, c)| c.is_ascii_digit()) + .ok_or(format!("Unknown algorithm: {s}"))?; + + let (first, second) = s.split_at(dig_pos); + match first { + "lo" => { + let value = second.parse::().map_err(|err| { + format!("Failed to convert `{second}` to a number of bits: {err}") + })?; + // TODO: We can allow more than 8 bits, depending on the image's bit depth + if value > 7 || value == 0 { + Err(format!( + "Cannot specify {value} bits for `lo` method, must be within [1, 7]" + )) + } else { + Ok(EmbedAlgorithm::Lo(value)) + } + } + _ => Err(format!("Unknown algorithm: {s}")), + } + } +} diff --git a/src/png_embed/header.rs b/src/png_embed/header.rs new file mode 100644 index 0000000..0eebbe1 --- /dev/null +++ b/src/png_embed/header.rs @@ -0,0 +1,139 @@ +use crc::Crc; + +use crate::block::BlockPlacementIterator; + +/// The program's version. +/// Used for compatibility reasons. +#[repr(u16)] +#[allow(non_camel_case_types)] +#[derive(Debug, Clone, Copy)] +pub enum Version { + VERSION_1, +} + +impl TryFrom for Version { + type Error = String; + + fn try_from(value: u16) -> Result { + match value { + 0 => Ok(Version::VERSION_1), + ver => Err(format!("Unknown version: {ver}")), + } + } +} + +pub trait Encode { + /// Encode the data into a vector + fn encode(&self, vec: &mut Vec); +} + +pub trait Decode { + type Type; + + /// Decode the data from an iterator + fn decode(it: &mut BlockPlacementIterator) -> Result; +} + +/// Embed data header: +/// +---------+----------+----------+-------------+---------+ +/// | Version | Data Len | Data CRC | Comment Len | Comment | +/// +---------+----------+----------+-------------+---------+ +/// | 2 | 4 | 4 | 2 | varies | +/// +---------+----------+----------+-------------+---------+ +#[derive(Debug)] +pub struct Header { + pub version: Version, + pub data_len: u32, + pub data_crc: u32, + pub comment: Option, +} + +impl Header { + /// Construct a new header from the embedded data + pub fn new(version: Version, data: &[u8], comment: Option) -> Result { + if data.len() > u32::MAX as usize { + return Err(format!( + "Embedded data length: {} is greater than maximum {}", + data.len(), + u32::MAX + )); + } else if let Some(len) = comment.as_ref().map(|c| c.len()) { + if len > u16::MAX as usize { + return Err(format!( + "Embedded comment is too long, maximum length: {}, got {len}", + u16::MAX + )); + } + } + + Ok(Self { + version, + data_len: data.len() as u32, + data_crc: Crc::::new(&crc::CRC_32_CKSUM).checksum(data), + comment, + }) + } +} + +impl Encode for Header { + fn encode(&self, vec: &mut Vec) { + // Version + vec.extend_from_slice((self.version as u16).to_le_bytes().as_slice()); + + // Data Len + vec.extend_from_slice(self.data_len.to_le_bytes().as_slice()); + + // Data CRC + vec.extend_from_slice(self.data_crc.to_le_bytes().as_slice()); + + // Comment length + let comment_length = self.comment.as_ref().map_or(0u16, |c| c.len() as u16); + vec.extend_from_slice(comment_length.to_le_bytes().as_slice()); + + // Comment + if let Some(comment) = &self.comment { + vec.extend_from_slice(comment.as_bytes()); + } + } +} + +impl Decode for Header { + type Type = Header; + + fn decode(it: &mut BlockPlacementIterator) -> Result { + let mut count = 0; + let mut next = || -> Result { + let result = it + .next() + .ok_or(format!("Failed to get byte at index: {count}")); + count += 1; + result + }; + + let version = u16::from_le_bytes([next()?, next()?]); + let data_len = u32::from_le_bytes([next()?, next()?, next()?, next()?]); + let data_crc = u32::from_le_bytes([next()?, next()?, next()?, next()?]); + let comment_length = u16::from_le_bytes([next()?, next()?]); + + let comment = if comment_length != 0 { + let mut comment_data = Vec::with_capacity(comment_length as usize); + for _ in 0..comment_length { + comment_data.push(next()?); + } + + Some( + String::from_utf8(comment_data) + .map_err(|e| format!("Failed to retrieve comment: {e}"))?, + ) + } else { + None + }; + + Ok(Header { + version: Version::try_from(version)?, + data_len, + data_crc, + comment, + }) + } +} diff --git a/src/image.rs b/src/png_embed/image.rs similarity index 100% rename from src/image.rs rename to src/png_embed/image.rs diff --git a/src/png_embed/main.rs b/src/png_embed/main.rs new file mode 100644 index 0000000..b01c0eb --- /dev/null +++ b/src/png_embed/main.rs @@ -0,0 +1,335 @@ +pub mod block; +pub mod embed; +pub mod header; +pub mod image; + +use std::env; +use std::fs::File; +use std::io::BufWriter; +use std::io::Write; +use std::process::ExitCode; +use std::str::FromStr; + +use bitvec::prelude::*; +use block::best_blocksize; +use block::BlockPlacement; +use block::BlockPlacementIterator; +use crc::Crc; +use embed::EmbedAlgorithm; +use getopts::Matches; +use getopts::Options; +use header::Decode; +use header::Encode; +use header::Header; +use image::ImageInfo; +use rand::SeedableRng; +use rand_chacha::ChaCha8Rng; + +fn print_usage(program: &str, opts: Options) { + let brief = format!( + "Usage: {0} -l ALGORITHM -(e|d|z) [EMBED] FILE -o OUTPUT [opts] + Encode: {0} -l lo3 -e embed.jpg input.png -o out.png -c \"Embedded JPEG file\" + Info: {0} -l lo3 out.png # Embedded JPEG file + Decode: {0} -l lo3 out.png > decoded.jpg", + program + ); + print!("{}", opts.usage(&brief)); +} + +fn print_version() { + print!( + r#"png_embed (c) ef3d0c3e -- Embed data into PNGs +Copyright (c) 2024 +NML is licensed under the GNU Affero General Public License version 3 (AGPLv3), +under the terms of the Free Software Foundation . + +This program is free software; you may modify and redistribute it. +There is NO WARRANTY, to the extent permitted by law."# + ); +} + +impl ImageInfo for png::OutputInfo { + fn width(&self) -> u32 { self.width } + + fn height(&self) -> u32 { self.height } + + fn size(&self) -> usize { self.buffer_size() } + + fn encode(&self, w: &mut BufWriter>, data: Vec) { + let mut encoder = png::Encoder::new(w, self.width(), self.height()); + encoder.set_color(self.color_type); + encoder.set_depth(self.bit_depth); + let mut writer = encoder.write_header().unwrap(); + writer.write_image_data(data.as_slice()).unwrap(); + } +} + +fn decode_image(image: &str) -> Result<(Vec, Box), String> { + match image.split_at(image.find('.').unwrap_or(0)).1 { + ".png" => { + let decoder = png::Decoder::new( + File::open(image).map_err(|err| format!("Failed to read `{image}`: {err}"))?, + ); + let mut reader = decoder + .read_info() + .map_err(|err| format!("Failed to read png info for `{image}`: {err}"))?; + let mut result = vec![0; reader.output_buffer_size()]; + let info = reader + .next_frame(result.as_mut_slice()) + .map_err(|err| format!("Failed to read png info for `{image}`: {err}"))?; + result.resize(info.buffer_size(), 0); + + Ok((result, Box::new(info))) + } + _ => Err(format!("Unable get image type for {image}")), + } +} + +// Derives the seed from a given string. +// Currently using Argon with salt: `png_data embed` +fn derive_seed(seed: &str) -> Result<[u8; 32], String> { + let mut result = [0u8; 32]; + argon2::Argon2::default() + .hash_password_into(seed.as_bytes(), b"png_data embed", &mut result) + .map_err(|err| format!("Failed to derive seed `{seed}`: {err}"))?; + Ok(result) +} + +fn encode( + input: String, + embed: String, + output: String, + algorithm: String, + matches: Matches, +) -> Result<(), String> { + let algorithm = EmbedAlgorithm::from_str(algorithm.as_str())?; + + let (mut data, info) = decode_image(input.as_str())?; + let block_size = best_blocksize(info.size()); + let seed = derive_seed( + matches + .opt_str("s") + .unwrap_or(format!("{}x{}", info.width(), info.height())) + .as_str(), + )?; + let comment = matches.opt_str("c"); + + // Data + let embed_file_data = std::fs::read(&embed) + .map_err(|err| format!("Failed to read embed file `{embed}`: {err}"))?; + + // Header + let header = Header::new( + header::Version::VERSION_1, + embed_file_data.as_slice(), + comment, + )?; + + // Result + let mut embed_data = vec![]; + header.encode(&mut embed_data); + embed_data.extend(embed_file_data); + + eprintln!("=== HEADER ==="); + eprintln!("Version: {:#?}", header.version); + eprintln!( + "Comment: {}", + header.comment.as_ref().map_or("", |c| c.as_str()) + ); + eprintln!("Data: {}bytes CRC[{:X}]", header.data_len, header.data_crc); + eprintln!("Block: {block_size}bytes"); + + let mut rand = ChaCha8Rng::from_seed(seed); + let mut placement = BlockPlacement::new( + &algorithm, + data.as_mut_slice(), + block_size, + embed_data.len(), + &mut rand, + )?; + + eprintln!("Required blocks: {}", placement.blocks.len()); + eprintln!("=============="); + + placement.write_embed(embed_data.as_slice().view_bits::()); + + let outfile = File::create(&output).unwrap(); + let w = &mut BufWriter::new(Box::new(outfile) as Box); + info.encode(w, data); + + Ok(()) +} + +fn decode_header(input: String, algorithm: String, matches: Matches) -> Result<(), String> { + let algorithm = EmbedAlgorithm::from_str(algorithm.as_str())?; + + let (data, info) = decode_image(input.as_str())?; + let block_size = best_blocksize(info.size()); + let seed = derive_seed( + matches + .opt_str("s") + .unwrap_or(format!("{}x{}", info.width(), info.height())) + .as_str(), + )?; + + let mut rand = ChaCha8Rng::from_seed(seed); + let mut it = BlockPlacementIterator::new(&algorithm, data.as_slice(), block_size, &mut rand); + + let header = Header::decode(&mut it)?; + + eprintln!("=== HEADER ==="); + eprintln!("Version: {:#?}", header.version); + eprintln!( + "Comment: \"{}\"", + header.comment.as_ref().map_or("", |c| c.as_str()) + ); + eprintln!("Data: {}bytes CRC[{:X}]", header.data_len, header.data_crc); + eprintln!("=============="); + + Ok(()) +} + +fn decode( + input: String, + output: String, + algorithm: String, + matches: Matches, +) -> Result<(), String> { + let algorithm = EmbedAlgorithm::from_str(algorithm.as_str())?; + + let (data, info) = decode_image(input.as_str())?; + let block_size = best_blocksize(info.size()); + let seed = derive_seed( + matches + .opt_str("s") + .unwrap_or(format!("{}x{}", info.width(), info.height())) + .as_str(), + )?; + + let mut rand = ChaCha8Rng::from_seed(seed); + let mut it = BlockPlacementIterator::new(&algorithm, data.as_slice(), block_size, &mut rand); + + let header = Header::decode(&mut it)?; + + let mut data = Vec::with_capacity(header.data_len as usize); + while data.len() < header.data_len as usize { + data.push( + it.next() + .ok_or(format!("Failed to read data byte at {}", data.len()))?, + ); + } + + // Check CRC + let data_crc = Crc::::new(&crc::CRC_32_CKSUM).checksum(data.as_slice()); + if data_crc != header.data_crc { + Err(format!( + "Data CRC do not match: HEADER={:X} GOT={data_crc:X}", + header.data_crc + ))?; + } + + let outfile = File::create(&output) + .map_err(|e| format!("Failed to create output file `{output}`: {e}"))?; + let w = &mut BufWriter::new(Box::new(outfile) as Box); + w.write_all(data.as_slice()) + .map_err(|e| format!("Failed to write to output file `{output}`: {e}"))?; + + eprintln!("File written to `{output}`"); + + Ok(()) +} + +fn main() -> ExitCode { + let args: Vec = env::args().collect(); + let program = args[0].clone(); + + let mut opts = Options::new(); + opts.optopt("e", "embed", "Embed file", "PATH"); + opts.optopt("o", "output", "Output file", "PATH"); + opts.optflag("d", "decode", "Decode mode"); + opts.optopt("c", "comment", "Header comment", "TXT"); + opts.optopt( + "s", + "seed", + "Force a seed, defaults to \"{width}x{height}\"", + "TXT", + ); + opts.optflag("z", "info", "Read header"); + opts.optopt("l", "algorithm", "Embed algorithm", "lo3"); + opts.optflag("h", "help", "Print this help menu"); + opts.optflag("v", "version", "Print program version and licenses"); + + let matches = match opts.parse(&args[1..]) { + Ok(m) => m, + Err(f) => { + panic!("{}", f.to_string()) + } + }; + if matches.opt_present("v") { + print_version(); + return ExitCode::SUCCESS; + } + if matches.opt_present("h") { + print_usage(&program, opts); + return ExitCode::SUCCESS; + } + + // Get input file + if matches.free.is_empty() { + eprintln!("Missing input file"); + print_usage(&program, opts); + return ExitCode::FAILURE; + } + let input_file = matches.free[0].clone(); + + // Check options + if matches.opt_present("e") as usize + + matches.opt_present("d") as usize + + matches.opt_present("z") as usize + > 1 + { + eprintln!("Specify either `-e(--embed)`, -z(--info) or `-d(--decode)`"); + return ExitCode::FAILURE; + } else if !matches.opt_present("l") { + eprintln!("Missing algorithm name"); + return ExitCode::FAILURE; + } + + // Get algorithm + let algorithm = matches.opt_str("l").unwrap(); + + if matches.opt_present("e") { + let embed_file = matches.opt_str("e").unwrap(); + if !matches.opt_present("o") { + eprintln!("Missing -o(utput) file"); + return ExitCode::FAILURE; + } + let output_file = matches.opt_str("o").unwrap(); + + if let Err(e) = encode(input_file, embed_file, output_file, algorithm, matches) { + eprintln!("{e}"); + return ExitCode::FAILURE; + } + } else if matches.opt_present("z") { + if let Err(e) = decode_header(input_file, algorithm, matches) { + eprintln!("{e}"); + return ExitCode::FAILURE; + } + } else if matches.opt_present("d") { + if !matches.opt_present("o") { + eprintln!("Missing -o(utput) file"); + return ExitCode::FAILURE; + } + let output_file = matches.opt_str("o").unwrap(); + + if let Err(e) = decode(input_file, output_file, algorithm, matches) { + eprintln!("{e}"); + return ExitCode::FAILURE; + } + } else { + print_usage(&program, opts); + return ExitCode::FAILURE; + } + + ExitCode::SUCCESS +}