happy_cracking/crypto/
des_cipher.rs1use anyhow::{Context, Result};
2use clap::Subcommand;
3
4use des::cipher::{Array, BlockCipherDecrypt, BlockCipherEncrypt, KeyInit};
5use des::{Des, TdesEde3};
6
7#[derive(Subcommand)]
8pub enum DesCipherAction {
9 #[command(about = "DES ECB encrypt (hex key 8 bytes, hex plaintext)")]
10 Encrypt {
11 #[arg(help = "Plaintext (hex string, must be multiple of 8 bytes)")]
12 input: String,
13 #[arg(short, long, help = "Key (hex string, 8 bytes / 16 hex chars)")]
14 key: String,
15 },
16 #[command(about = "DES ECB decrypt (hex key 8 bytes, hex ciphertext)")]
17 Decrypt {
18 #[arg(help = "Ciphertext (hex string, must be multiple of 8 bytes)")]
19 input: String,
20 #[arg(short, long, help = "Key (hex string, 8 bytes / 16 hex chars)")]
21 key: String,
22 },
23 #[command(about = "Triple-DES (EDE3) encrypt (hex key 24 bytes, hex plaintext)")]
24 TdesEncrypt {
25 #[arg(help = "Plaintext (hex string, must be multiple of 8 bytes)")]
26 input: String,
27 #[arg(short, long, help = "Key (hex string, 24 bytes / 48 hex chars)")]
28 key: String,
29 },
30 #[command(about = "Triple-DES (EDE3) decrypt (hex key 24 bytes, hex ciphertext)")]
31 TdesDecrypt {
32 #[arg(help = "Ciphertext (hex string, must be multiple of 8 bytes)")]
33 input: String,
34 #[arg(short, long, help = "Key (hex string, 24 bytes / 48 hex chars)")]
35 key: String,
36 },
37}
38
39pub fn run(action: DesCipherAction) -> Result<()> {
40 match action {
41 DesCipherAction::Encrypt { input, key } => {
42 println!("{}", des_encrypt(&input, &key)?);
43 }
44 DesCipherAction::Decrypt { input, key } => {
45 println!("{}", des_decrypt(&input, &key)?);
46 }
47 DesCipherAction::TdesEncrypt { input, key } => {
48 println!("{}", tdes_encrypt(&input, &key)?);
49 }
50 DesCipherAction::TdesDecrypt { input, key } => {
51 println!("{}", tdes_decrypt(&input, &key)?);
52 }
53 }
54 Ok(())
55}
56
57fn parse_des_blocks(hex_input: &str) -> Result<Vec<u8>> {
58 let bytes = hex::decode(hex_input.trim()).context("Failed to decode hex input")?;
59 if bytes.is_empty() {
60 anyhow::bail!("Input must not be empty");
61 }
62 if bytes.len() % 8 != 0 {
63 anyhow::bail!(
64 "Input length must be a multiple of 8 bytes, got {} bytes",
65 bytes.len()
66 );
67 }
68 Ok(bytes)
69}
70
71pub fn des_encrypt(hex_input: &str, hex_key: &str) -> Result<String> {
72 let key_bytes = hex::decode(hex_key.trim()).context("Failed to decode hex key")?;
73 if key_bytes.len() != 8 {
74 anyhow::bail!(
75 "DES key must be exactly 8 bytes (16 hex chars), got {} bytes",
76 key_bytes.len()
77 );
78 }
79 let plaintext = parse_des_blocks(hex_input)?;
80 let cipher =
81 Des::new(&Array::try_from(key_bytes.as_slice()).context("DES key must be 8 bytes")?);
82
83 let mut output = Vec::with_capacity(plaintext.len());
84 for block in plaintext.chunks(8) {
85 let mut block_array = Array::try_from(block).context("DES block must be 8 bytes")?;
86 cipher.encrypt_block(&mut block_array);
87 output.extend_from_slice(&block_array);
88 }
89 Ok(hex::encode(output))
90}
91
92pub fn des_decrypt(hex_input: &str, hex_key: &str) -> Result<String> {
93 let key_bytes = hex::decode(hex_key.trim()).context("Failed to decode hex key")?;
94 if key_bytes.len() != 8 {
95 anyhow::bail!(
96 "DES key must be exactly 8 bytes (16 hex chars), got {} bytes",
97 key_bytes.len()
98 );
99 }
100 let ciphertext = parse_des_blocks(hex_input)?;
101 let cipher =
102 Des::new(&Array::try_from(key_bytes.as_slice()).context("DES key must be 8 bytes")?);
103
104 let mut output = Vec::with_capacity(ciphertext.len());
105 for block in ciphertext.chunks(8) {
106 let mut block_array = Array::try_from(block).context("DES block must be 8 bytes")?;
107 cipher.decrypt_block(&mut block_array);
108 output.extend_from_slice(&block_array);
109 }
110 Ok(hex::encode(output))
111}
112
113pub fn tdes_encrypt(hex_input: &str, hex_key: &str) -> Result<String> {
114 let key_bytes = hex::decode(hex_key.trim()).context("Failed to decode hex key")?;
115 if key_bytes.len() != 24 {
116 anyhow::bail!(
117 "Triple-DES key must be exactly 24 bytes (48 hex chars), got {} bytes",
118 key_bytes.len()
119 );
120 }
121 let plaintext = parse_des_blocks(hex_input)?;
122 let cipher = TdesEde3::new(
123 &Array::try_from(key_bytes.as_slice()).context("Triple-DES key must be 24 bytes")?,
124 );
125
126 let mut output = Vec::with_capacity(plaintext.len());
127 for block in plaintext.chunks(8) {
128 let mut block_array = Array::try_from(block).context("DES block must be 8 bytes")?;
129 cipher.encrypt_block(&mut block_array);
130 output.extend_from_slice(&block_array);
131 }
132 Ok(hex::encode(output))
133}
134
135pub fn tdes_decrypt(hex_input: &str, hex_key: &str) -> Result<String> {
136 let key_bytes = hex::decode(hex_key.trim()).context("Failed to decode hex key")?;
137 if key_bytes.len() != 24 {
138 anyhow::bail!(
139 "Triple-DES key must be exactly 24 bytes (48 hex chars), got {} bytes",
140 key_bytes.len()
141 );
142 }
143 let ciphertext = parse_des_blocks(hex_input)?;
144 let cipher = TdesEde3::new(
145 &Array::try_from(key_bytes.as_slice()).context("Triple-DES key must be 24 bytes")?,
146 );
147
148 let mut output = Vec::with_capacity(ciphertext.len());
149 for block in ciphertext.chunks(8) {
150 let mut block_array = Array::try_from(block).context("DES block must be 8 bytes")?;
151 cipher.decrypt_block(&mut block_array);
152 output.extend_from_slice(&block_array);
153 }
154 Ok(hex::encode(output))
155}