mirror of
https://github.com/kristoferssolo/des-rs.git
synced 2025-12-20 11:04:38 +00:00
feat: add cli app
This commit is contained in:
parent
20ff162d71
commit
93696b5d68
235
Cargo.lock
generated
235
Cargo.lock
generated
@ -11,6 +11,56 @@ dependencies = [
|
|||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstream"
|
||||||
|
version = "0.6.21"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a"
|
||||||
|
dependencies = [
|
||||||
|
"anstyle",
|
||||||
|
"anstyle-parse",
|
||||||
|
"anstyle-query",
|
||||||
|
"anstyle-wincon",
|
||||||
|
"colorchoice",
|
||||||
|
"is_terminal_polyfill",
|
||||||
|
"utf8parse",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstyle"
|
||||||
|
version = "1.0.13"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstyle-parse"
|
||||||
|
version = "0.2.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2"
|
||||||
|
dependencies = [
|
||||||
|
"utf8parse",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstyle-query"
|
||||||
|
version = "1.1.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9e231f6134f61b71076a3eab506c379d4f36122f2af15a9ff04415ea4c3339e2"
|
||||||
|
dependencies = [
|
||||||
|
"windows-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstyle-wincon"
|
||||||
|
version = "3.0.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3e0633414522a32ffaac8ac6cc8f748e090c5717661fddeea04219e2344f5f2a"
|
||||||
|
dependencies = [
|
||||||
|
"anstyle",
|
||||||
|
"once_cell_polyfill",
|
||||||
|
"windows-sys",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cfg-if"
|
name = "cfg-if"
|
||||||
version = "1.0.3"
|
version = "1.0.3"
|
||||||
@ -23,6 +73,61 @@ version = "0.8.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bba18ee93d577a8428902687bcc2b6b45a56b1981a1f6d779731c86cc4c5db18"
|
checksum = "bba18ee93d577a8428902687bcc2b6b45a56b1981a1f6d779731c86cc4c5db18"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap"
|
||||||
|
version = "4.5.48"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e2134bb3ea021b78629caa971416385309e0131b351b25e01dc16fb54e1b5fae"
|
||||||
|
dependencies = [
|
||||||
|
"clap_builder",
|
||||||
|
"clap_derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap_builder"
|
||||||
|
version = "4.5.48"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c2ba64afa3c0a6df7fa517765e31314e983f51dda798ffba27b988194fb65dc9"
|
||||||
|
dependencies = [
|
||||||
|
"anstream",
|
||||||
|
"anstyle",
|
||||||
|
"clap_lex",
|
||||||
|
"strsim",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap_derive"
|
||||||
|
version = "4.5.47"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bbfd7eae0b0f1a6e63d4b13c9c478de77c2eb546fba158ad50b4203dc24b9f9c"
|
||||||
|
dependencies = [
|
||||||
|
"heck",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap_lex"
|
||||||
|
version = "0.7.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "colorchoice"
|
||||||
|
version = "1.0.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "des"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"clap",
|
||||||
|
"des-lib",
|
||||||
|
"thiserror",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "des-lib"
|
name = "des-lib"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
@ -105,6 +210,12 @@ version = "0.16.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d"
|
checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "heck"
|
||||||
|
version = "0.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "indexmap"
|
name = "indexmap"
|
||||||
version = "2.11.4"
|
version = "2.11.4"
|
||||||
@ -115,6 +226,12 @@ dependencies = [
|
|||||||
"hashbrown",
|
"hashbrown",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "is_terminal_polyfill"
|
||||||
|
version = "1.70.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.176"
|
version = "0.2.176"
|
||||||
@ -127,6 +244,12 @@ version = "2.7.6"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273"
|
checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "once_cell_polyfill"
|
||||||
|
version = "1.70.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pin-project-lite"
|
name = "pin-project-lite"
|
||||||
version = "0.2.16"
|
version = "0.2.16"
|
||||||
@ -315,6 +438,12 @@ version = "0.4.11"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589"
|
checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "strsim"
|
||||||
|
version = "0.11.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "2.0.106"
|
version = "2.0.106"
|
||||||
@ -326,6 +455,26 @@ dependencies = [
|
|||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "thiserror"
|
||||||
|
version = "2.0.17"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8"
|
||||||
|
dependencies = [
|
||||||
|
"thiserror-impl",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "thiserror-impl"
|
||||||
|
version = "2.0.17"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "toml_datetime"
|
name = "toml_datetime"
|
||||||
version = "0.7.2"
|
version = "0.7.2"
|
||||||
@ -362,6 +511,12 @@ version = "1.0.19"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d"
|
checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "utf8parse"
|
||||||
|
version = "0.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasi"
|
name = "wasi"
|
||||||
version = "0.14.7+wasi-0.2.4"
|
version = "0.14.7+wasi-0.2.4"
|
||||||
@ -380,6 +535,86 @@ dependencies = [
|
|||||||
"wit-bindgen",
|
"wit-bindgen",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-link"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "45e46c0661abb7180e7b9c281db115305d49ca1709ab8242adf09666d2173c65"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-sys"
|
||||||
|
version = "0.60.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb"
|
||||||
|
dependencies = [
|
||||||
|
"windows-targets",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-targets"
|
||||||
|
version = "0.53.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2d42b7b7f66d2a06854650af09cfdf8713e427a439c97ad65a6375318033ac4b"
|
||||||
|
dependencies = [
|
||||||
|
"windows-link",
|
||||||
|
"windows_aarch64_gnullvm",
|
||||||
|
"windows_aarch64_msvc",
|
||||||
|
"windows_i686_gnu",
|
||||||
|
"windows_i686_gnullvm",
|
||||||
|
"windows_i686_msvc",
|
||||||
|
"windows_x86_64_gnu",
|
||||||
|
"windows_x86_64_gnullvm",
|
||||||
|
"windows_x86_64_msvc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_aarch64_gnullvm"
|
||||||
|
version = "0.53.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_aarch64_msvc"
|
||||||
|
version = "0.53.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_gnu"
|
||||||
|
version = "0.53.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_gnullvm"
|
||||||
|
version = "0.53.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_msvc"
|
||||||
|
version = "0.53.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_gnu"
|
||||||
|
version = "0.53.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_gnullvm"
|
||||||
|
version = "0.53.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_msvc"
|
||||||
|
version = "0.53.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winnow"
|
name = "winnow"
|
||||||
version = "0.7.13"
|
version = "0.7.13"
|
||||||
|
|||||||
@ -1,11 +1,15 @@
|
|||||||
[workspace]
|
[workspace]
|
||||||
resolver = "2"
|
resolver = "2"
|
||||||
members = ["des-lib"]
|
members = ["des", "des-lib"]
|
||||||
|
|
||||||
[workspace.dependencies]
|
[workspace.dependencies]
|
||||||
|
des-lib = { path = "des-lib" }
|
||||||
|
|
||||||
claims = "0.8"
|
claims = "0.8"
|
||||||
|
clap = { version = "4.5", features = ["derive"] }
|
||||||
rand = "0.9"
|
rand = "0.9"
|
||||||
rstest = "0.26"
|
rstest = "0.26"
|
||||||
|
thiserror = "2"
|
||||||
|
|
||||||
[workspace.lints.clippy]
|
[workspace.lints.clippy]
|
||||||
pedantic = "warn"
|
pedantic = "warn"
|
||||||
|
|||||||
@ -10,18 +10,6 @@ fn des_instance() -> Des {
|
|||||||
Des::new(TEST_KEY)
|
Des::new(TEST_KEY)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_ecb_mode_equivalence() {
|
|
||||||
// If you implement ECB mode, test it matches single block
|
|
||||||
let key = 0x1334_5779_9BBC_DFF1;
|
|
||||||
let des = Des::new(key);
|
|
||||||
let plain = 0x0123_4567_89AB_CDEF;
|
|
||||||
|
|
||||||
let _single_block = des.encrypt(plain);
|
|
||||||
// let ecb_result = encrypt_ecb(&[plain]);
|
|
||||||
// assert_eq!(single_block, ecb_result[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
#[case(TEST_PLAINTEXT, TEST_CIPHERTEXT, TEST_KEY)]
|
#[case(TEST_PLAINTEXT, TEST_CIPHERTEXT, TEST_KEY)]
|
||||||
fn encrypt_decrypt_roundtrip(
|
fn encrypt_decrypt_roundtrip(
|
||||||
|
|||||||
15
des/Cargo.toml
Normal file
15
des/Cargo.toml
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
[package]
|
||||||
|
name = "des"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Kristofers Solo <dev@kristofers.xyz>"]
|
||||||
|
edition = "2024"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
clap.workspace = true
|
||||||
|
des-lib.workspace = true
|
||||||
|
thiserror.workspace = true
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
|
||||||
|
[lints]
|
||||||
|
workspace = true
|
||||||
208
des/src/args.rs
Normal file
208
des/src/args.rs
Normal file
@ -0,0 +1,208 @@
|
|||||||
|
use clap::{Parser, Subcommand, ValueEnum};
|
||||||
|
use std::{
|
||||||
|
fmt::{Display, LowerHex, UpperHex},
|
||||||
|
fs::read_to_string,
|
||||||
|
num::IntErrorKind,
|
||||||
|
path::PathBuf,
|
||||||
|
str::FromStr,
|
||||||
|
};
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
|
#[derive(Debug, Error)]
|
||||||
|
pub enum ValueError {
|
||||||
|
#[error("String contains no content")]
|
||||||
|
EmptyString,
|
||||||
|
|
||||||
|
#[error("File '{0}' contains no content")]
|
||||||
|
EmptyFile(PathBuf),
|
||||||
|
|
||||||
|
#[error("Failed to find file '{0}'. File does not exist")]
|
||||||
|
MissingFile(PathBuf),
|
||||||
|
|
||||||
|
#[error("Failed to read file '{0}'. Cannot read file contents")]
|
||||||
|
FileReadingError(PathBuf),
|
||||||
|
|
||||||
|
#[error("Invalid number format: {0}")]
|
||||||
|
InvalidFormat(String),
|
||||||
|
|
||||||
|
#[error("Invalid byte string: must be exactly 8 ASCII characters")]
|
||||||
|
InvalidByteString,
|
||||||
|
|
||||||
|
#[error("String-to-u64 conversion error: {0}")]
|
||||||
|
ConversionError(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Parser)]
|
||||||
|
#[command(version, about, long_about = None)]
|
||||||
|
pub struct Args {
|
||||||
|
#[command(subcommand)]
|
||||||
|
pub operation: Operation,
|
||||||
|
|
||||||
|
/// Key used to encrypt/decrypt data (64-bit number, string, or path to file)
|
||||||
|
#[arg(short = 'k', long, value_parser = Value::from_str, required = true)]
|
||||||
|
pub key: Value,
|
||||||
|
|
||||||
|
/// The text to encrypt/decrypt data (64-bit number, string, or path to file)
|
||||||
|
#[arg(value_name = "TEXT", value_parser = Value::from_str, required = true)]
|
||||||
|
pub text: Value,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Subcommand, Default)]
|
||||||
|
pub enum Operation {
|
||||||
|
/// Encrypt data
|
||||||
|
#[default]
|
||||||
|
Encrypt,
|
||||||
|
/// Decrypt data
|
||||||
|
Decrypt {
|
||||||
|
/// Output format for decrypted data
|
||||||
|
#[arg(short = 'f', long, value_enum)]
|
||||||
|
output_format: Option<OutputFormat>,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Default, ValueEnum)]
|
||||||
|
pub enum OutputFormat {
|
||||||
|
/// Binary output
|
||||||
|
Binary,
|
||||||
|
/// Octal output (fixed typo)
|
||||||
|
Octal,
|
||||||
|
/// Decimal output
|
||||||
|
Decimal,
|
||||||
|
/// Hexadecimal output
|
||||||
|
#[default]
|
||||||
|
Hex,
|
||||||
|
/// Text output (ASCII)
|
||||||
|
Text,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub struct Value(u64);
|
||||||
|
|
||||||
|
impl Value {
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub fn as_64(self) -> u64 {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Value> for u64 {
|
||||||
|
fn from(value: Value) -> Self {
|
||||||
|
value.as_64()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<u64> for Value {
|
||||||
|
fn from(value: u64) -> Self {
|
||||||
|
Self(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for Value {
|
||||||
|
type Err = ValueError;
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
if let Ok(num) = s.parse::<u64>() {
|
||||||
|
return Ok(Self(num));
|
||||||
|
}
|
||||||
|
|
||||||
|
let path = PathBuf::from(s);
|
||||||
|
if path.exists() && path.is_file() {
|
||||||
|
if let Ok(contents) = read_to_string(&path) {
|
||||||
|
let value = parse_string_to_u64(&contents)?;
|
||||||
|
return Ok(Self(value));
|
||||||
|
}
|
||||||
|
return Err(ValueError::FileReadingError(path));
|
||||||
|
}
|
||||||
|
|
||||||
|
let value = parse_string_to_u64(&s)?;
|
||||||
|
Ok(Self(value))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_string_to_u64(s: &str) -> Result<u64, ValueError> {
|
||||||
|
let trimmed = s.trim();
|
||||||
|
|
||||||
|
if trimmed.is_empty() {
|
||||||
|
return Err(ValueError::EmptyString);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hexadecimal with 0x/0X prefix
|
||||||
|
if trimmed.starts_with("0x") || trimmed.starts_with("0X") {
|
||||||
|
let hex_str = &trimmed[2..].trim_start_matches('0');
|
||||||
|
if hex_str.is_empty() {
|
||||||
|
return Ok(0); // 0x000 ->
|
||||||
|
}
|
||||||
|
return u64::from_str_radix(hex_str, 16)
|
||||||
|
.map_err(|e| ValueError::InvalidFormat(format!("Hex parsing failed: {e}")));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Binary with 0b/0B prefix
|
||||||
|
if trimmed.starts_with("0b") || trimmed.starts_with("0B") {
|
||||||
|
let bin_str = &trimmed[2..].trim_start_matches('0');
|
||||||
|
if bin_str.is_empty() {
|
||||||
|
return Ok(0); // 0b000 -> 0
|
||||||
|
}
|
||||||
|
if !bin_str.chars().all(|ch| ch == '0' || ch == '1') {
|
||||||
|
return Err(ValueError::InvalidFormat(
|
||||||
|
"Binary string contains invalid characters".into(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
return u64::from_str_radix(bin_str, 2)
|
||||||
|
.map_err(|e| ValueError::InvalidFormat(format!("Binary parsing failed: {e}")));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 8-character ASCII string conversion to u64
|
||||||
|
if trimmed.len() == 8 {
|
||||||
|
return ascii_string_to_u64(trimmed);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Regular decimal parsing
|
||||||
|
trimmed.parse::<u64>().map_err(|e| {
|
||||||
|
ValueError::InvalidFormat(match e.kind() {
|
||||||
|
IntErrorKind::InvalidDigit => "contains invalid digits".into(),
|
||||||
|
IntErrorKind::PosOverflow => "number too large for u64".into(),
|
||||||
|
IntErrorKind::NegOverflow => "negative numbers not allowed".into(),
|
||||||
|
IntErrorKind::Empty => "empty string".into(),
|
||||||
|
IntErrorKind::Zero => "invalid zero".into(),
|
||||||
|
_ => format!("parsing error: {e}"),
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ascii_string_to_u64(s: &str) -> Result<u64, ValueError> {
|
||||||
|
if s.len() != 8 {
|
||||||
|
return Err(ValueError::InvalidByteString);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure all characters are valid ASCII (0-127)
|
||||||
|
if !s.bytes().all(|b| b <= 127) {
|
||||||
|
return Err(ValueError::ConversionError(
|
||||||
|
"String contains non-ASCII characters".into(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut bytes = [0; 8];
|
||||||
|
for (idx, byte) in s.bytes().enumerate() {
|
||||||
|
bytes[idx] = byte;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(u64::from_le_bytes(bytes))
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for Value {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "{:0b}", self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UpperHex for Value {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "{:016X}", self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LowerHex for Value {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "{:016x}", self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
21
des/src/main.rs
Normal file
21
des/src/main.rs
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
mod args;
|
||||||
|
|
||||||
|
use crate::args::{Args, Operation};
|
||||||
|
use clap::Parser;
|
||||||
|
use des_lib::Des;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let args = Args::parse();
|
||||||
|
let des = Des::new(args.key.as_64());
|
||||||
|
|
||||||
|
match args.operation {
|
||||||
|
Operation::Encrypt => {
|
||||||
|
let ciphertext = des.encrypt(args.text.as_64());
|
||||||
|
println!("{ciphertext:016X}");
|
||||||
|
}
|
||||||
|
Operation::Decrypt { output_format } => {
|
||||||
|
let plaintext = des.decrypt(args.text.as_64());
|
||||||
|
println!("{plaintext:016X}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user