First commit

This commit is contained in:
ef3d0c3e 2024-08-15 20:12:42 +02:00
commit f9728d490d
7 changed files with 891 additions and 0 deletions

476
Cargo.lock generated Normal file
View file

@ -0,0 +1,476 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "adler"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
[[package]]
name = "aead"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0"
dependencies = [
"crypto-common",
"generic-array",
]
[[package]]
name = "aes"
version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0"
dependencies = [
"cfg-if",
"cipher",
"cpufeatures",
]
[[package]]
name = "aes-gcm"
version = "0.10.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "831010a0f742e1209b3bcea8fab6a8e149051ba6099432c8cb2cc117dec3ead1"
dependencies = [
"aead",
"aes",
"cipher",
"ctr",
"ghash",
"subtle",
]
[[package]]
name = "argon2"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c3610892ee6e0cbce8ae2700349fcf8f98adb0dbfbee85aec3c9179d29cc072"
dependencies = [
"base64ct",
"blake2",
"cpufeatures",
"password-hash",
]
[[package]]
name = "base64ct"
version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b"
[[package]]
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bitvec"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c"
dependencies = [
"funty",
"radium",
"tap",
"wyz",
]
[[package]]
name = "blake2"
version = "0.10.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe"
dependencies = [
"digest",
]
[[package]]
name = "block-buffer"
version = "0.10.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
dependencies = [
"generic-array",
]
[[package]]
name = "byteorder"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "cipher"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad"
dependencies = [
"crypto-common",
"inout",
]
[[package]]
name = "cpufeatures"
version = "0.2.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51e852e6dc9a5bed1fae92dd2375037bf2b768725bf3be87811edee3249d09ad"
dependencies = [
"libc",
]
[[package]]
name = "crc32fast"
version = "1.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3"
dependencies = [
"cfg-if",
]
[[package]]
name = "crypto-common"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
dependencies = [
"generic-array",
"rand_core",
"typenum",
]
[[package]]
name = "ctr"
version = "0.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835"
dependencies = [
"cipher",
]
[[package]]
name = "digest"
version = "0.10.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
dependencies = [
"block-buffer",
"crypto-common",
"subtle",
]
[[package]]
name = "fdeflate"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4f9bfee30e4dedf0ab8b422f03af778d9612b63f502710fc500a334ebe2de645"
dependencies = [
"simd-adler32",
]
[[package]]
name = "flate2"
version = "1.0.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f211bbe8e69bbd0cfdea405084f128ae8b4aaa6b0b522fc8f2b009084797920"
dependencies = [
"crc32fast",
"miniz_oxide",
]
[[package]]
name = "funty"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c"
[[package]]
name = "generic-array"
version = "0.14.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
dependencies = [
"typenum",
"version_check",
]
[[package]]
name = "getopts"
version = "0.2.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5"
dependencies = [
"unicode-width",
]
[[package]]
name = "getrandom"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
dependencies = [
"cfg-if",
"libc",
"wasi",
]
[[package]]
name = "ghash"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0d8a4362ccb29cb0b265253fb0a2728f592895ee6854fd9bc13f2ffda266ff1"
dependencies = [
"opaque-debug",
"polyval",
]
[[package]]
name = "inout"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5"
dependencies = [
"generic-array",
]
[[package]]
name = "libc"
version = "0.2.155"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
[[package]]
name = "miniz_oxide"
version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08"
dependencies = [
"adler",
"simd-adler32",
]
[[package]]
name = "opaque-debug"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381"
[[package]]
name = "password-hash"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "346f04948ba92c43e8469c1ee6736c7563d71012b17d40745260fe106aac2166"
dependencies = [
"base64ct",
"rand_core",
"subtle",
]
[[package]]
name = "png"
version = "0.17.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06e4b0d3d1312775e782c86c91a111aa1f910cbb65e1337f9975b5f9a554b5e1"
dependencies = [
"bitflags",
"crc32fast",
"fdeflate",
"flate2",
"miniz_oxide",
]
[[package]]
name = "png_data2"
version = "0.1.0"
dependencies = [
"aes-gcm",
"argon2",
"bitvec",
"getopts",
"png",
"rand",
"rand_chacha",
]
[[package]]
name = "polyval"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25"
dependencies = [
"cfg-if",
"cpufeatures",
"opaque-debug",
"universal-hash",
]
[[package]]
name = "ppv-lite86"
version = "0.2.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04"
dependencies = [
"zerocopy",
]
[[package]]
name = "proc-macro2"
version = "1.0.86"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
dependencies = [
"proc-macro2",
]
[[package]]
name = "radium"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09"
[[package]]
name = "rand"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
dependencies = [
"libc",
"rand_chacha",
"rand_core",
]
[[package]]
name = "rand_chacha"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
dependencies = [
"ppv-lite86",
"rand_core",
]
[[package]]
name = "rand_core"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
dependencies = [
"getrandom",
]
[[package]]
name = "simd-adler32"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe"
[[package]]
name = "subtle"
version = "2.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
[[package]]
name = "syn"
version = "2.0.74"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fceb41e3d546d0bd83421d3409b1460cc7444cd389341a4c880fe7a042cb3d7"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "tap"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
[[package]]
name = "typenum"
version = "1.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
[[package]]
name = "unicode-ident"
version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
[[package]]
name = "unicode-width"
version = "0.1.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d"
[[package]]
name = "universal-hash"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea"
dependencies = [
"crypto-common",
"subtle",
]
[[package]]
name = "version_check"
version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
[[package]]
name = "wasi"
version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "wyz"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed"
dependencies = [
"tap",
]
[[package]]
name = "zerocopy"
version = "0.7.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
dependencies = [
"byteorder",
"zerocopy-derive",
]
[[package]]
name = "zerocopy-derive"
version = "0.7.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
dependencies = [
"proc-macro2",
"quote",
"syn",
]

13
Cargo.toml Normal file
View file

@ -0,0 +1,13 @@
[package]
name = "png_data2"
version = "0.1.0"
edition = "2021"
[dependencies]
aes-gcm = "0.10.3"
argon2 = "0.5.3"
bitvec = "1.0.1"
getopts = "0.2.21"
png = "0.17.13"
rand = "0.8.5"
rand_chacha = "0.3.1"

58
src/block.rs Normal file
View file

@ -0,0 +1,58 @@
use std::{fmt::Formatter, intrinsics::ctlz, str::FromStr};
/// 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,
}
}
pub fn to_data(&self) -> u8 {
((self.crc_len != 0) as u8) | (ctlz(self.len) << 1) as u8
}
}
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<Self, Self::Err> {
let size = s
.parse::<usize>()
.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,
})
}
}

93
src/embed.rs Normal file
View file

@ -0,0 +1,93 @@
use std::fmt::Formatter;
use std::str::FromStr;
use bitvec::prelude::*;
use bitvec::vec::BitVec;
use crate::block::BlockMode;
use crate::image::ImageInfo;
pub enum EmbedAlgorithm {
Lo(u8),
}
impl EmbedAlgorithm {
pub fn max_size(&self, blockmode: &BlockMode, info: &Box<dyn ImageInfo>) -> 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: &[u8], embed_data: &BitVec<u8>, mut embed_offset: usize, blockmode: &BlockMode) -> (Vec<u8>, usize) {
let mut result = Vec::<u8>::with_capacity(blockmode.len);
match self {
EmbedAlgorithm::Lo(bits) => {
let mask = (1<<bits) -1;
fn bits_to_byte(slice: &BitSlice<u8>, bits: u8) -> u8
{
let mut result : u8 = 0;
for i in 0..bits
{
result |= (slice[i as usize] as u8) << i;
}
result
}
for i in 0..(blockmode.len-blockmode.crc_len)
{
let embed = bits_to_byte(embed_data.get(embed_offset..embed_offset+*bits as usize).unwrap(), *bits);
let b = original_data[i];
result.push((b & !mask) | embed);
embed_offset += *bits as usize;
}
}
}
(result, embed_offset)
}
}
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<Self, Self::Err> {
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::<u8>().map_err(|err| {
format!("Failed to convert `{second}` to a number of bits: {err}")
})?;
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}")),
}
}
}

33
src/header.rs Normal file
View file

@ -0,0 +1,33 @@
use crate::block::BlockMode;
pub struct Header {
pub blockmode: BlockMode,
pub comment: Option<String>,
}
impl Header {
pub fn to_data(&self, version: u16, embed_len: u32) -> Vec<u8> {
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()).unwrap_or(0);
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
}
}

5
src/image.rs Normal file
View file

@ -0,0 +1,5 @@
pub trait ImageInfo {
fn width(&self) -> u32;
fn height(&self) -> u32;
fn size(&self) -> usize;
}

213
src/main.rs Normal file
View file

@ -0,0 +1,213 @@
#![feature(core_intrinsics)]
pub mod block;
pub mod embed;
pub mod header;
pub mod image;
use std::env;
use std::fs::File;
use std::process::ExitCode;
use std::str::FromStr;
use bitvec::slice::BitSlice;
use bitvec::vec::BitVec;
use block::BlockMode;
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;
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 get_algorithm(s: Option<String>) -> Result<EmbedAlgorithm, String> {
if let Some(s) = &s {
EmbedAlgorithm::from_str(s.as_str())
} else {
Err("Missing required algorithm parameter".into())
}
}
fn get_blockmode(s: Option<String>) -> Result<BlockMode, String> {
if let Some(s) = &s {
BlockMode::from_str(s)
} else {
Err("Missing requires blockmode parameter".into())
}
}
fn decode_image(image: String) -> Result<(Vec<u8>, Box<dyn ImageInfo>), 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 encode(image: String, matches: Matches) -> Result<Vec<u8>, 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 (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}"))?;
// 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,
))?;
}
// Shuffle the blocks
let mut rand = ChaCha8Rng::from_seed(seed);
let blocks_num = info.size() / (header.blockmode.len-header.blockmode.crc_len);
let mut blocks_pos = (0..blocks_num).collect::<Vec<_>>();
blocks_pos.shuffle(&mut rand);
let mut bv = BitVec::<u8>::from_vec(header_data);
bv.extend_from_raw_slice(embed_data.as_slice());
let mut embed_offset = 0;
for i in 0 .. blocks_num
{
println!("{:#?}", bv.len());
let (block, mut new_offset) = algorithm.next_block(
&data.as_slice()[i*header.blockmode.len..],
&bv,
embed_offset,
&header.blockmode);
new_offset += header.blockmode.crc_len*8;
embed_offset = new_offset;
}
algorithm.next_block(data.as_slice(), &bv, 48, &header.blockmode);
// TODO: WRITE CRC
println!("Ok");
Ok(vec![])
}
fn main() -> ExitCode {
let args: Vec<String> = 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("e") {
match encode(input, matches) {
Ok(_) => todo!(""),
Err(e) => {
eprintln!("{e}");
return ExitCode::FAILURE;
}
}
}
ExitCode::SUCCESS
}