From ad03e176c32ba31854d6bc8a26757d528ef37478 Mon Sep 17 00:00:00 2001 From: ddidderr Date: Wed, 14 Feb 2024 22:23:57 +0100 Subject: [PATCH] on the way to a usable version --- Cargo.lock | 343 ++++++++++++++++++++++++++++++++------------------ Cargo.toml | 9 +- src/crypto.rs | 99 ++++++++------- src/error.rs | 1 + src/main.rs | 66 +++++----- src/reader.rs | 100 +++++++++++++++ src/utils.rs | 20 ++- 7 files changed, 437 insertions(+), 201 deletions(-) create mode 100644 src/reader.rs diff --git a/Cargo.lock b/Cargo.lock index 49ff6c6..451d3ee 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,35 +4,61 @@ version = 3 [[package]] name = "aead" -version = "0.4.3" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b613b8e1e3cf911a086f53f03bf286f52fd7a7258e4fa606f0ef220d39d8877" +checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" dependencies = [ + "crypto-common", "generic-array", ] [[package]] -name = "atty" -version = "0.2.14" +name = "anstream" +version = "0.6.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +checksum = "6e2e1ebcb11de5c03c67de28a7df593d32191b44939c482e97702baaaa6ab6a5" dependencies = [ - "hermit-abi", - "libc", - "winapi", + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "utf8parse", ] [[package]] -name = "autocfg" -version = "1.1.0" +name = "anstyle" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc" [[package]] -name = "bitflags" -version = "1.3.2" +name = "anstyle-parse" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" +dependencies = [ + "anstyle", + "windows-sys", +] [[package]] name = "cfg-if" @@ -42,21 +68,20 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chacha20" -version = "0.8.1" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01b72a433d0cf2aef113ba70f62634c56fddb0f244e6377185c56a7cadbd8f91" +checksum = "c3613f74bd2eac03dad61bd53dbe620703d4371614fe0bc3b9f04dd36fe4e818" dependencies = [ "cfg-if", "cipher", "cpufeatures", - "zeroize", ] [[package]] name = "chacha20poly1305" -version = "0.9.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b84ed6d1d5f7aa9bdde921a5090e0ca4d934d250ea3b402a5fab3a994e28a2a" +checksum = "10cd79432192d1c0f4e1a0fef9527696cc039165d729fb41b3f4f4f354c2dc35" dependencies = [ "aead", "chacha20", @@ -67,37 +92,81 @@ dependencies = [ [[package]] name = "cipher" -version = "0.3.0" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" dependencies = [ - "generic-array", + "crypto-common", + "inout", + "zeroize", ] [[package]] name = "clap" -version = "3.1.8" +version = "4.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71c47df61d9e16dc010b55dba1952a57d8c215dbb533fd13cdd13369aac73b1c" +checksum = "80c21025abd42669a92efc996ef13cfb2c5c627858421ea58d5c3b331a6c134f" dependencies = [ - "atty", - "bitflags", - "indexmap", - "os_str_bytes", - "strsim", - "termcolor", - "textwrap", + "clap_builder", + "clap_derive", ] [[package]] -name = "cpufeatures" -version = "0.2.2" +name = "clap_builder" +version = "4.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59a6001667ab124aebae2a495118e11d30984c3a653e99d86d58971708cf5e4b" +checksum = "458bf1f341769dfcf849846f65dffdf9146daa56bcd2a47cb4e1de9915567c99" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "307bc0538d5f0f83b8248db3087aa92fe504e4691294d0c96c0eabc33f47ba47" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" + +[[package]] +name = "colorchoice" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" + +[[package]] +name = "cpufeatures" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" dependencies = [ "libc", ] +[[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 = "fcry" version = "0.9.0" @@ -109,9 +178,9 @@ dependencies = [ [[package]] name = "generic-array" -version = "0.14.5" +version = "0.14.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd48d33ec7f05fbfa152300fdad764757cbded343c1aa1cff2fbaf4134851803" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "typenum", "version_check", @@ -119,9 +188,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.6" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9be70c98951c83b8d2f8f60d7065fa6d5146873094452a1008da8c2f1e4205ad" +checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" dependencies = [ "cfg-if", "libc", @@ -129,41 +198,25 @@ dependencies = [ ] [[package]] -name = "hashbrown" -version = "0.11.2" +name = "heck" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" [[package]] -name = "hermit-abi" -version = "0.1.19" +name = "inout" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" dependencies = [ - "libc", -] - -[[package]] -name = "indexmap" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f647032dfaa1f8b6dc29bd3edb7bbef4861b8b8007ebb118d6db284fd59f6ee" -dependencies = [ - "autocfg", - "hashbrown", + "generic-array", ] [[package]] name = "libc" -version = "0.2.122" +version = "0.2.153" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec647867e2bf0772e28c8bcde4f0d19a9216916e890543b5a03ed8ef27b8f259" - -[[package]] -name = "memchr" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" [[package]] name = "opaque-debug" @@ -171,20 +224,11 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" -[[package]] -name = "os_str_bytes" -version = "6.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e22443d1643a904602595ba1cd8f7d896afe56d26712531c5ff73a15b2fbf64" -dependencies = [ - "memchr", -] - [[package]] name = "poly1305" -version = "0.7.2" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "048aeb476be11a4b6ca432ca569e375810de9294ae78f4774e78ea98a9246ede" +checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf" dependencies = [ "cpufeatures", "opaque-debug", @@ -193,9 +237,27 @@ dependencies = [ [[package]] name = "ppv-lite86" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "proc-macro2" +version = "1.0.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +dependencies = [ + "proc-macro2", +] [[package]] name = "rand" @@ -220,56 +282,64 @@ dependencies = [ [[package]] name = "rand_core" -version = "0.6.3" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ "getrandom", ] [[package]] name = "strsim" -version = "0.10.0" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +checksum = "5ee073c9e4cd00e28217186dbe12796d692868f432bf2e97ee73bed0c56dfa01" [[package]] name = "subtle" -version = "2.4.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" +checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" [[package]] -name = "termcolor" -version = "1.1.3" +name = "syn" +version = "2.0.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" +checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" dependencies = [ - "winapi-util", + "proc-macro2", + "quote", + "unicode-ident", ] -[[package]] -name = "textwrap" -version = "0.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb" - [[package]] name = "typenum" -version = "1.15.0" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "universal-hash" -version = "0.4.1" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f214e8f697e925001e66ec2c6e37a4ef93f0f78c2eed7814394e10c62025b05" +checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" dependencies = [ - "generic-array", + "crypto-common", "subtle", ] +[[package]] +name = "utf8parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" + [[package]] name = "version_check" version = "0.9.4" @@ -278,43 +348,78 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "wasi" -version = "0.10.2+wasi-snapshot-preview1" +version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] -name = "winapi" -version = "0.3.9" +name = "windows-sys" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", + "windows-targets", ] [[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" +name = "windows-targets" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-util" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" dependencies = [ - "winapi", + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", ] [[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" +name = "windows_aarch64_gnullvm" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" [[package]] name = "zeroize" -version = "1.4.3" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d68d9dcec5f9b43a30d38c49f91dfedfaac384cb8f085faca366c26207dd1619" +checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" diff --git a/Cargo.toml b/Cargo.toml index 1103e45..3987df7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,12 +5,13 @@ name = "fcry" version = "0.9.0" [dependencies] -chacha20poly1305 = {version = "0.9.0", features = ["stream"]} -clap = "3" +chacha20poly1305 = {version = "0.10", features = ["stream"]} +clap = {version = "4", features = ["derive"]} rand = {version = "0.8"} [profile.release] -codegen-units = 1 -debug = false lto = true +debug = false +strip = true panic = "unwind" +codegen-units = 1 diff --git a/src/crypto.rs b/src/crypto.rs index 2f255ce..3676994 100644 --- a/src/crypto.rs +++ b/src/crypto.rs @@ -1,54 +1,61 @@ // SPDX-License-Identifier: GPL-3.0-only -use chacha20poly1305::{ - aead::{stream, NewAead}, - ChaCha20Poly1305, -}; + +use chacha20poly1305::{aead::stream, KeyInit, XChaCha20Poly1305}; use rand::{rngs::OsRng, RngCore}; use crate::error::*; +use crate::reader::ReadInfo; +use crate::utils::BUFSIZE; use crate::utils::*; -const BUFSIZE: usize = 64 * 1024; // 64 KiB - -fn new_random_nonce() -> Result<[u8; 7], FcryError> { - let mut nonce = [0u8; 7]; - OsRng.try_fill_bytes(&mut nonce)?; - Ok(nonce) -} - pub fn encrypt>( input_file: Option, output_file: Option, key: [u8; 32], ) -> Result<(), FcryError> { - let mut f_plain = read_from_file_or_stdin(input_file); + let mut f_plain = read_from_file_or_stdin(input_file, BUFSIZE); let mut f_encrypted = write_to_file_or_stdout(output_file); - let nonce = new_random_nonce()?; + let mut nonce = [0u8; 19]; + OsRng.fill_bytes(&mut nonce); + + // let key = XChaCha20Poly1305::generate_key(&mut OsRng); + f_encrypted.write_all(&nonce)?; - let aead = ChaCha20Poly1305::new(&key.into()); + let aead = XChaCha20Poly1305::new(&key.into()); let mut stream_encryptor = stream::EncryptorBE32::from_aead(aead, &nonce.into()); let mut buf = vec![0; BUFSIZE]; - let mut read_bytes; loop { - read_bytes = f_plain.read(&mut buf)?; + let read_result = f_plain.read_ahead(&mut buf)?; - if read_bytes < BUFSIZE { - break; + match read_result { + ReadInfo::NormalChunk(n) => { + assert_eq!(n, BUFSIZE); + assert_eq!(buf.len(), BUFSIZE); + println!("[encrypt]: read normal chunk"); + stream_encryptor.encrypt_next_in_place(&[], &mut buf)?; + f_encrypted.write_all(&buf)?; + // buf grows after encrypt_next_in_place because of tag that is added + // we shrink it to the BUFSIZE in order to read the correct size + buf.truncate(BUFSIZE); + } + ReadInfo::LastChunk(n) => { + println!("[encrypt]: read last chunk"); + buf.truncate(n); + stream_encryptor.encrypt_last_in_place(&[], &mut buf)?; + f_encrypted.write_all(&buf)?; + break; + } + ReadInfo::EmptyChunk => { + println!("[encrypt]: read empty chunk"); + panic!("[ERROR] Empty Chunk while reading"); + } } - - stream_encryptor.encrypt_next_in_place(&[], &mut buf)?; - f_encrypted.write_all(&buf)?; - buf.truncate(BUFSIZE); } - buf.truncate(read_bytes); - stream_encryptor.encrypt_last_in_place(&[], &mut buf)?; - f_encrypted.write_all(&buf)?; - Ok(()) } @@ -57,33 +64,41 @@ pub fn decrypt>( output_file: Option, key: [u8; 32], ) -> Result<(), FcryError> { - let mut f_encrypted = read_from_file_or_stdin(input_file); + let mut f_encrypted = read_from_file_or_stdin(input_file, BUFSIZE + 16); let mut f_plain = write_to_file_or_stdout(output_file); - let mut nonce = [0u8; 7]; + let mut nonce = [0u8; 19]; f_encrypted.read_exact(&mut nonce)?; - let aead = ChaCha20Poly1305::new(&key.into()); + let aead = XChaCha20Poly1305::new(&key.into()); let mut stream_decryptor = stream::DecryptorBE32::from_aead(aead, &nonce.into()); let mut buf = vec![0; BUFSIZE + 16]; - let mut read_bytes; loop { - read_bytes = f_encrypted.read(&mut buf)?; + let read_result = f_encrypted.read_ahead(&mut buf)?; - if read_bytes < BUFSIZE + 16 { - break; + match read_result { + ReadInfo::NormalChunk(n) => { + assert_eq!(n, BUFSIZE + 16); + println!("[decrypt]: read normal chunk"); + stream_decryptor.decrypt_next_in_place(&[], &mut buf)?; + f_plain.write_all(&buf)?; + buf.resize(BUFSIZE + 16, 0); + } + ReadInfo::LastChunk(n) => { + println!("[decrypt]: read last chunk"); + buf.truncate(n); + stream_decryptor.decrypt_last_in_place(&[], &mut buf)?; + f_plain.write_all(&buf)?; + break; + } + ReadInfo::EmptyChunk => { + println!("[decrypt]: read empty chunk"); + panic!("Empty Chunk while reading"); + } } - - stream_decryptor.decrypt_next_in_place(&[], &mut buf)?; - f_plain.write_all(&buf)?; - buf.resize(BUFSIZE + 16, 0); } - buf.truncate(read_bytes); - stream_decryptor.decrypt_last_in_place(&[], &mut buf)?; - f_plain.write_all(&buf)?; - Ok(()) } diff --git a/src/error.rs b/src/error.rs index c65a0c7..dbebeaf 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,4 +1,5 @@ // SPDX-License-Identifier: GPL-3.0-only + use chacha20poly1305::aead; use std::io; diff --git a/src/main.rs b/src/main.rs index 987a259..b0780a3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,47 +1,48 @@ // SPDX-License-Identifier: GPL-3.0-only + mod crypto; mod error; +mod reader; mod utils; -use clap::{Arg, ArgMatches, Command}; - use crypto::*; use error::FcryError; -fn build_cmdline_args() -> ArgMatches { - Command::new("fcry - [f]ile[cry]pt").version(env!("CARGO_PKG_VERSION")) - .about("A file en-/decryption tool for easy use.") - .arg(Arg::new("decrypt") - .short('d') - .long("decrypt") - .help("Decrypt instead of encrypt. Encrypting is the default.") - .takes_value(false)) - .arg(Arg::new("input_file") - .short('i') - .long("input-file") - .help("The input file to en-/decrypt") - .takes_value(true)) - .arg(Arg::new("output_file") - .short('o') - .long("output-file") - .help("The output file. If not specified, en-/decrypted bytes will be sent to stdout.") - .takes_value(true)) - .arg(Arg::new("raw-key") - .required(true) - .long("raw-key") - .help("The raw bytes of the crypto key. Has to be exactly 32 bytes.\n*** DANGEROUS, use for testing purposes only! ***") - .takes_value(true)) - .get_matches() +use clap::Parser; + +/// fcry - [f]ile[cry]pt: A file en-/decryption tool for easy use +#[derive(Parser, Debug)] +#[clap(author, version, about)] +struct Cli { + /// decrypt instead of encrypt (encryption is the default) + #[clap(short, long)] + decrypt: bool, + + /// The input file to en-/decrypt + #[clap(short, long)] + input_file: Option, + + /// The output file. + /// If not specified, en-/decrypted bytes will be sent to stdout + #[clap(short, long)] + output_file: Option, + + /// The raw bytes of the crypto key. + /// Has to be exactly 32 bytes + /// *** DANGEROUS, use for testing purposes only! *** + #[clap(short, long)] + raw_key: String, } -fn run(args: ArgMatches) -> Result<(), FcryError> { - let input_file = args.value_of("input_file"); - let output_file = args.value_of("output_file"); +fn run(cli: Cli) -> Result<(), FcryError> { + let input_file = cli.input_file; + let output_file = cli.output_file; let mut key = [0u8; 32]; - key.clone_from_slice(args.value_of("raw-key").unwrap().as_bytes()); + dbg!(&cli.raw_key); + key.clone_from_slice(cli.raw_key.as_bytes()); - if args.is_present("decrypt") { + if cli.decrypt { decrypt(input_file, output_file, key)? } else { encrypt(input_file, output_file, key)? @@ -51,7 +52,8 @@ fn run(args: ArgMatches) -> Result<(), FcryError> { } fn main() { - if let Err(e) = run(build_cmdline_args()) { + let cli = Cli::parse(); + if let Err(e) = run(cli) { println!("Error: {:?}", e); } } diff --git a/src/reader.rs b/src/reader.rs new file mode 100644 index 0000000..1e0fc65 --- /dev/null +++ b/src/reader.rs @@ -0,0 +1,100 @@ +// SPDX-License-Identifier: GPL-3.0-only + +use std::io; +use std::io::{BufRead, Read}; + +pub enum ReadInfo { + NormalChunk(usize), + LastChunk(usize), + EmptyChunk, +} + +pub struct AheadReader { + inner: Box, + buf: Vec, + bufsz: usize, + capacity: usize, +} + +impl AheadReader { + pub fn from(reader: Box, capacity: usize) -> Self { + Self { + inner: reader, + buf: vec![0; capacity], + bufsz: 0, + capacity, + } + } + + fn read_until_full(&mut self, mut buf: &mut [u8]) -> io::Result { + let mut total = 0; + loop { + match self.inner.read(buf) { + Ok(0) => break, + Ok(n) => { + total += n; + let tmp = buf; + buf = &mut tmp[n..]; + } + Err(e) => match e.kind() { + io::ErrorKind::Interrupted => continue, + _ => return Err(e), + }, + } + } + + Ok(total) + } + + pub fn read_ahead(&mut self, userbuf: &mut [u8]) -> io::Result { + // 1st read + if self.bufsz == 0 { + println!("[reader] first read"); + return self.first_read(userbuf); + } + + println!("[reader] normal read"); + // normal read (not the 1st one) + self.normal_read(userbuf) + } + + pub fn read_exact(&mut self, userbuf: &mut [u8]) -> io::Result<()> { + self.inner.read_exact(userbuf) + } + + fn first_read(&mut self, userbuf: &mut [u8]) -> io::Result { + // 1st read directly to userbuf (we have no cached data yet) + let n = self.read_until_full(userbuf)?; + if n == 0 { + return Ok(ReadInfo::EmptyChunk); + } + + // 2nd read directly into our internal buf + let mut tmp = vec![0u8; self.capacity]; + let n2 = self.read_until_full(&mut tmp)?; + self.buf = tmp; + self.bufsz = n2; + if n2 == 0 { + return Ok(ReadInfo::LastChunk(n)); + } + + Ok(ReadInfo::NormalChunk(n)) + } + + fn normal_read(&mut self, userbuf: &mut [u8]) -> io::Result { + // copy internal buf to userbuf + userbuf.copy_from_slice(&self.buf); + let userbuf_sz = self.bufsz; + + // 2nd read directly into our internal buf + let mut tmp = vec![0u8; self.capacity]; + let n2 = self.read_until_full(&mut tmp)?; + self.buf = tmp; + self.bufsz = n2; + if n2 == 0 { + return Ok(ReadInfo::LastChunk(userbuf_sz)); + } + + Ok(ReadInfo::NormalChunk(userbuf_sz)) + } +} diff --git a/src/utils.rs b/src/utils.rs index 0d4ac82..317c1bd 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,13 +1,25 @@ // SPDX-License-Identifier: GPL-3.0-only + +use crate::reader::AheadReader; + +use std::io::BufReader; use std::{ fs::File, - io::{self, Read, Write}, + io::{self, Write}, }; -pub(crate) fn read_from_file_or_stdin>(input_file: Option) -> Box { +pub const BUFSIZE: usize = 64 * 1024; // 64 KiB + +pub(crate) fn read_from_file_or_stdin>( + input_file: Option, + bufsz: usize, +) -> AheadReader { match input_file { - Some(f) => Box::new(File::open(f.as_ref()).unwrap()), - None => Box::new(io::stdin()), + Some(f) => AheadReader::from( + Box::new(BufReader::new(File::open(f.as_ref()).unwrap())), + bufsz, + ), + None => AheadReader::from(Box::new(io::stdin().lock()), bufsz), } }