old_crypto_rs/autoclave/
autocrypt.rs

1//! Autocrypt is the autoclave system where the ciphertext is used as key, instead of repeating the
2//! key several times.  This is the equivalent on an IV in modern systems, and this is the ancestor
3//! of the CBC mode for modern ciphers.
4//!
5
6use crate::Block;
7
8#[derive(Debug)]
9pub struct AutocryptCipher {
10    /// The numeric key values (0-25) derived from the key string.
11    /// 
12    key: Vec<u8>,
13}
14
15impl AutocryptCipher {
16    pub fn new(key: &str) -> Self {
17        let key_vec = key.as_bytes().iter()
18            .map(|&b| b - b'A')
19            .collect::<Vec<_>>();
20        AutocryptCipher {
21            key: key_vec,
22        }
23    }
24}
25
26impl Block for AutocryptCipher {
27    fn block_size(&self) -> usize {
28        1
29    }
30
31    /// Encrypts plaintext using the Autocrypt cipher with ciphertext feedback.
32    ///
33    /// This method implements the autocrypt encryption scheme where:
34    /// - The first `key.len()` characters are encrypted using the original key
35    /// - Subsequent characters use previously generated ciphertext as the key (CBC-like mode)
36    ///
37    /// # Arguments
38    ///
39    /// * `dst` - The destination buffer where ciphertext will be written
40    /// * `src` - The source plaintext to encrypt (assumes uppercase A-Z characters)
41    ///
42    /// # Returns
43    ///
44    /// The number of bytes written to `dst`, which is `min(src.len(), dst.len())`
45    ///
46    /// # Example
47    ///
48    /// ```rust
49    /// use old_crypto_rs::AutocryptCipher;
50    /// use old_crypto_rs::Block;
51    ///
52    /// let cipher = AutocryptCipher::new("KEY");
53    /// let plaintext = b"HELLO";
54    /// let mut ciphertext = vec![0u8; plaintext.len()];
55    /// cipher.encrypt(&mut ciphertext, plaintext);
56    /// assert_eq!(&ciphertext, b"RIJCW");
57    /// ```
58    ///
59    fn encrypt(&self, dst: &mut [u8], src: &[u8]) -> usize {
60        if src.is_empty() {
61            return 0;
62        }
63
64        for (i, &p) in src.iter().enumerate() {
65            if i >= dst.len() {
66                break;
67            }
68            // Assumes src is A-Z (ASCII 65-90)
69            //
70            let p_val = if p >= b'A' && p <= b'Z' { p - b'A' } else { p };
71
72            // Build the key: use original key for first few chars, then ciphertext
73            //
74            let key_val = if i < self.key.len() {
75                self.key[i]
76            } else {
77                // Use previously encrypted ciphertext (CBC mode)
78                // dst[i - self.key.len()] is already encrypted, convert back to 0-25
79                //
80                dst[i - self.key.len()] - b'A'
81            };
82
83            // Encrypt this character
84            //
85            let c_val = (p_val + key_val) % 26;
86            dst[i] = c_val + b'A';
87        }
88
89        src.len().min(dst.len())
90    }
91
92    /// Decrypts ciphertext using the Autocrypt cipher with ciphertext feedback.
93    ///
94    /// This method implements the autocrypt decryption scheme where:
95    /// - The first `key.len()` characters are decrypted using the original key
96    /// - Subsequent characters use previously processed ciphertext as the key (CBC-like mode)
97    ///
98    /// # Arguments
99    ///
100    /// * `dst` - The destination buffer where plaintext will be written
101    /// * `src` - The source ciphertext to decrypt (assumes uppercase A-Z characters)
102    ///
103    /// # Returns
104    ///
105    /// The number of bytes written to `dst`, which is `min(src.len(), dst.len())`
106    ///
107    /// # Example
108    ///
109    /// ```rust
110    /// use old_crypto_rs::AutocryptCipher;
111    /// use old_crypto_rs::Block;
112    ///
113    /// let cipher = AutocryptCipher::new("KEY");
114    /// let ciphertext = b"RIJCW";
115    /// let mut plaintext = vec![0u8; ciphertext.len()];
116    /// cipher.decrypt(&mut plaintext, ciphertext);
117    /// assert_eq!(&plaintext, b"HELLO");
118    /// ```
119    ///
120    fn decrypt(&self, dst: &mut [u8], src: &[u8]) -> usize {
121        if src.is_empty() {
122            return 0;
123        }
124
125        for (i, &c) in src.iter().enumerate() {
126            if i >= dst.len() {
127                break;
128            }
129            // Assumes src is A-Z (ASCII 65-90)
130            //
131            let c_val = if c >= b'A' && c <= b'Z' { c - b'A' } else { c };
132
133            // Build the key: use original key for first few chars, then ciphertext
134            //
135            let key_val = if i < self.key.len() {
136                self.key[i]
137            } else {
138                // Use previous ciphertext value for the key
139                //
140                src[i - self.key.len()] - b'A'
141            };
142
143            // Decrypt this character
144            //
145            let p_val = (c_val + 26 - key_val) % 26;
146            dst[i] = p_val + b'A';
147        }
148
149        src.len().min(dst.len())
150    }
151}
152
153#[cfg(test)]
154mod tests {
155    use super::*;
156
157    #[test]
158    fn test_autocrypt_basic() {
159        let cipher = AutocryptCipher::new("KEY");
160        let pt = b"HELLO";
161        let mut ct = vec![0u8; pt.len()];
162        cipher.encrypt(&mut ct, pt);
163
164        // Keystream: K, E, Y, R, I (key "KEY", then ciphertext "RI...")
165        // H(7) + K(10) = 17 = R
166        // E(4) + E(4) = 8 = I
167        // L(11) + Y(24) = 35 % 26 = 9 = J
168        // L(11) + R(17) = 28 % 26 = 2 = C
169        // O(14) + I(8) = 22 = W
170        //
171        assert_eq!(&ct, b"RIJCW");
172
173        let mut dec = vec![0u8; ct.len()];
174        cipher.decrypt(&mut dec, &ct);
175        assert_eq!(&dec, pt);
176    }
177
178    #[test]
179    fn test_autocrypt_longer_message() {
180        let cipher = AutocryptCipher::new("SECRET");
181        let pt = b"ATTACKATDAWN";
182        let mut ct = vec![0u8; pt.len()];
183        cipher.encrypt(&mut ct, pt);
184
185        let mut dec = vec![0u8; ct.len()];
186        cipher.decrypt(&mut dec, &ct);
187        assert_eq!(&dec, pt);
188    }
189
190    #[test]
191    fn test_autocrypt_single_char_key() {
192        let cipher = AutocryptCipher::new("A");
193        let pt = b"ATTACK";
194        let mut ct = vec![0u8; pt.len()];
195        cipher.encrypt(&mut ct, pt);
196
197        // Keystream: A, A, T, M, M, O (key "A", then ciphertext "ATMMO")
198        // A(0) + A(0) = 0 = A
199        // T(19) + A(0) = 19 = T
200        // T(19) + T(19) = 38 % 26 = 12 = M
201        // A(0) + M(12) = 12 = M
202        // C(2) + M(12) = 14 = O
203        // K(10) + O(14) = 24 = Y
204        //
205        assert_eq!(&ct, b"ATMMOY");
206
207        let mut dec = vec![0u8; ct.len()];
208        cipher.decrypt(&mut dec, &ct);
209        assert_eq!(&dec, pt);
210    }
211
212    #[test]
213    fn test_autocrypt_key_longer_than_message() {
214        let cipher = AutocryptCipher::new("VERYLONGKEY");
215        let pt = b"HI";
216        let mut ct = vec![0u8; pt.len()];
217        cipher.encrypt(&mut ct, pt);
218        // H(7) + V(21) = 28 % 26 = 2 = C
219        // I(8) + E(4) = 12 = M
220        //
221        assert_eq!(&ct, b"CM");
222
223        let mut dec = vec![0u8; ct.len()];
224        cipher.decrypt(&mut dec, &ct);
225        assert_eq!(&dec, pt);
226    }
227
228    #[test]
229    fn test_autocrypt_repeated_chars() {
230        let cipher = AutocryptCipher::new("B");
231        let pt = b"AAAA";
232        let mut ct = vec![0u8; pt.len()];
233        cipher.encrypt(&mut ct, pt);
234
235        // Keystream: B, B, B, B (key "B", then ciphertext "BBB")
236        // A(0) + B(1) = 1 = B
237        // A(0) + B(1) = 1 = B
238        // A(0) + B(1) = 1 = B
239        // A(0) + B(1) = 1 = B
240        //
241        assert_eq!(&ct, b"BBBB");
242
243        let mut dec = vec![0u8; ct.len()];
244        cipher.decrypt(&mut dec, &ct);
245        assert_eq!(&dec, pt);
246    }
247
248    #[test]
249    fn test_autocrypt_empty_input() {
250        let cipher = AutocryptCipher::new("KEY");
251        let pt = b"";
252        let mut ct = vec![0u8; pt.len()];
253        let written = cipher.encrypt(&mut ct, pt);
254        assert_eq!(written, 0);
255    }
256
257    #[test]
258    fn test_autocrypt_wrap_around() {
259        let cipher = AutocryptCipher::new("XYZ");
260        let pt = b"ABCDE";
261        let mut ct = vec![0u8; pt.len()];
262        cipher.encrypt(&mut ct, pt);
263
264        // A(0) + X(23) = 23 = X
265        // B(1) + Y(24) = 25 = Z
266        // C(2) + Z(25) = 27 % 26 = 1 = B
267        // D(3) + X(23) = 26 % 26 = 0 = A
268        // E(4) + Z(25) = 29 % 26 = 3 = D
269        //
270        assert_eq!(&ct, b"XZBAD");
271
272        let mut dec = vec![0u8; ct.len()];
273        cipher.decrypt(&mut dec, &ct);
274        assert_eq!(&dec, pt);
275    }
276
277    #[test]
278    fn test_autocrypt_vs_autokey_different() {
279        // Autocrypt (ciphertext feedback) should produce different output than Autokey (plaintext feedback)
280        //
281        use crate::autoclave::autokey::AutokeyCipher;
282
283        let autocrypt = AutocryptCipher::new("KEY");
284        let autokey = AutokeyCipher::new("KEY");
285        let pt = b"HELLO";
286
287        let mut ct_autocrypt = vec![0u8; pt.len()];
288        autocrypt.encrypt(&mut ct_autocrypt, pt);
289
290        let mut ct_autokey = vec![0u8; pt.len()];
291        autokey.encrypt(&mut ct_autokey, pt);
292
293        // They should produce different ciphertexts
294        //
295        assert_ne!(&ct_autocrypt, &ct_autokey);
296        assert_eq!(&ct_autocrypt, b"RIJCW"); // ciphertext feedback
297        assert_eq!(&ct_autokey, b"RIJSS");   // plaintext feedback
298    }
299
300    #[test]
301    fn test_autocrypt_all_zs() {
302        let cipher = AutocryptCipher::new("Z");
303        let pt = b"ZZZ";
304        let mut ct = vec![0u8; pt.len()];
305        cipher.encrypt(&mut ct, pt);
306
307        // Z(25) + Z(25) = 50 % 26 = 24 = Y
308        // Z(25) + Y(24) = 49 % 26 = 23 = X
309        // Z(25) + X(23) = 48 % 26 = 22 = W
310        //
311        assert_eq!(&ct, b"YXW");
312
313        let mut dec = vec![0u8; ct.len()];
314        cipher.decrypt(&mut dec, &ct);
315        assert_eq!(&dec, pt);
316    }
317
318    #[test]
319    fn test_autocrypt_long_text() {
320        let cipher = AutocryptCipher::new("CRYPTOGRAPHY");
321        let pt = b"THEQUICKBROWNFOXJUMPSOVERTHELAZYDOG";
322        let mut ct = vec![0u8; pt.len()];
323        cipher.encrypt(&mut ct, pt);
324
325        let mut dec = vec![0u8; ct.len()];
326        cipher.decrypt(&mut dec, &ct);
327        assert_eq!(&dec, pt);
328    }
329}