Skip to main content

encryption/encryptor/
threefish512cbc.rs

1// Copyright (c) 2026 erik <erik@erik.xyz> — https://erik.xyz
2
3//! Threefish-512-CBC + HMAC-SHA256(encrypt-then-MAC,PKCS#7 填充);
4//! 载荷:`v1 | IV(64) | MAC(32) | 密文`。块长与密钥均为 512 位。
5
6use cbc::cipher::{BlockDecryptMut, BlockEncryptMut, KeyIvInit, block_padding::Pkcs7};
7use cbc::{Decryptor, Encryptor};
8use rand_core::{OsRng, RngCore};
9use threefish::Threefish512;
10
11use crate::contract::{Identified, SymmetricCipher};
12use crate::error::{Error, Result};
13use crate::internal::etm;
14use crate::key::Key;
15
16const LABEL: &str = "Threefish-512-CBC";
17/// Threefish-512 的块长是 512 位(64 字节),IV 与之等长。
18const IV_LEN: usize = 64;
19
20/// Threefish-512-CBC 加密器(CBC + HMAC;Skein 家族块密码)。
21#[derive(Debug)]
22pub struct Threefish512CbcEncryptor {
23    key: Key<64>,
24}
25
26impl Threefish512CbcEncryptor {
27    pub const IDENTIFIER: &'static str = "threefish-512-cbc-hmac";
28
29    pub fn new(key: [u8; 64]) -> Self {
30        Self { key: Key::new(key) }
31    }
32
33    pub fn from_slice(key: &[u8]) -> Result<Self> {
34        Ok(Self {
35            key: Key::from_slice(key, LABEL)?,
36        })
37    }
38}
39
40impl Identified for Threefish512CbcEncryptor {
41    fn identifier(&self) -> &str {
42        Self::IDENTIFIER
43    }
44}
45
46impl SymmetricCipher for Threefish512CbcEncryptor {
47    fn encrypt(&self, plaintext: &[u8]) -> Result<Vec<u8>> {
48        let mut iv = [0u8; IV_LEN];
49        OsRng.fill_bytes(&mut iv);
50
51        let ciphertext = Encryptor::<Threefish512>::new_from_slices(self.key.as_bytes(), &iv)
52            .expect("key and iv lengths are fixed")
53            .encrypt_padded_vec_mut::<Pkcs7>(plaintext);
54
55        Ok(etm::pack(&iv, &ciphertext, self.key.as_bytes()))
56    }
57
58    fn decrypt(&self, ciphertext: &[u8]) -> Result<Vec<u8>> {
59        let (iv, body) = etm::unpack_and_verify(ciphertext, IV_LEN, self.key.as_bytes(), LABEL)?;
60
61        Decryptor::<Threefish512>::new_from_slices(self.key.as_bytes(), iv)
62            .expect("key and iv lengths were verified")
63            .decrypt_padded_vec_mut::<Pkcs7>(body)
64            .map_err(|_| Error::DecryptionFailed { label: LABEL })
65    }
66}
67
68#[cfg(test)]
69mod tests {
70    use super::*;
71
72    /// 十六进制字符串 → 字节:KAT 向量照抄官方测试向量文本,避免手工转写。
73    fn unhex(s: &str) -> Vec<u8> {
74        (0..s.len() / 2)
75            .map(|i| u8::from_str_radix(&s[2 * i..2 * i + 2], 16).unwrap())
76            .collect()
77    }
78
79    /// Skein/Threefish 官方 KAT(Threefish-512,tweak 全零 = `KeyInit` 的默认 tweak):
80    /// 前两条链式向量(零密钥 → 以第一段密文为第二段密钥)。直接调用裸块密码 ——
81    /// 封装层往返测试抓不出「轮函数 / 密钥表整体错位」。
82    ///
83    /// 注:threefish 0.5.2 自带的 tests/mod.rs 首行是 `#![cfg(featue = "cipher")]`
84    /// (拼写错误),整个测试目标被 cfg 掉、从未跑过;本向量是该实现的事实锚点。
85    #[test]
86    fn bare_block_cipher_matches_official_kat() {
87        use cbc::cipher::{Block, BlockEncrypt, KeyInit};
88
89        let vectors = [
90            (
91                "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
92                "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
93                concat!(
94                    "b1a2bbc6ef6025bc40eb3822161f36e375d1bb0aee3186fbd19e47c5d479947b",
95                    "7bc2f8586e35f0cff7e7f03084b0b7b1f1ab3961a580a3e97eb41ea14a6d7bbe"
96                ),
97            ),
98            (
99                concat!(
100                    "b1a2bbc6ef6025bc40eb3822161f36e375d1bb0aee3186fbd19e47c5d479947b",
101                    "7bc2f8586e35f0cff7e7f03084b0b7b1f1ab3961a580a3e97eb41ea14a6d7bbe"
102                ),
103                "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
104                concat!(
105                    "f13ca06760dd9bbeab87b6c56f3bbbdb",
106                    "e9d08a77978b942ac02d471dc10268f2",
107                    "261c3d4330d6ca341f4bd4115dee16a2",
108                    "1dcda2a34a0a76fba976174e4cf1e306"
109                ),
110            ),
111        ];
112
113        for (key, plaintext, expected) in vectors {
114            let key = unhex(key);
115            let plaintext = unhex(plaintext);
116            let expected = unhex(expected);
117
118            let cipher = Threefish512::new_from_slice(&key).unwrap();
119            let mut block = Block::<Threefish512>::clone_from_slice(&plaintext);
120            cipher.encrypt_block(&mut block);
121            assert_eq!(block.as_slice(), expected.as_slice());
122        }
123    }
124
125    #[test]
126    fn roundtrip_at_padding_boundaries() {
127        let encryptor = Threefish512CbcEncryptor::new([5u8; 64]);
128        for plaintext in [
129            b"".as_slice(),
130            b"x",
131            b"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
132            b"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdefg",
133        ] {
134            let blob = encryptor.encrypt(plaintext).unwrap();
135            assert_eq!(encryptor.decrypt(&blob).unwrap(), plaintext);
136        }
137    }
138
139    /// 帧布局:`v1 | IV(64) | MAC(32) | 密文`;64 字节 IV 的线宽是
140    /// `etm::unpack_and_verify` 的 `iv_len` 参数唯一容易接错的地方。
141    #[test]
142    fn frame_uses_64_byte_iv() {
143        let encryptor = Threefish512CbcEncryptor::new([5u8; 64]);
144        let blob = encryptor.encrypt(b"x").unwrap();
145        // v1(2) + IV(64) + MAC(32) + 一个填充后的整块(64)
146        assert_eq!(blob.len(), 2 + 64 + 32 + 64);
147        assert_eq!(&blob[..2], b"v1");
148    }
149
150    #[test]
151    fn tampered_blob_fails_mac_before_decrypt() {
152        let encryptor = Threefish512CbcEncryptor::new([5u8; 64]);
153        let mut blob = encryptor.encrypt(b"secret").unwrap();
154        let last = blob.len() - 1;
155        blob[last] ^= 0x01;
156        assert_eq!(
157            encryptor.decrypt(&blob).unwrap_err(),
158            Error::MacVerificationFailed { label: LABEL }
159        );
160    }
161
162    #[test]
163    fn wrong_key_fails_mac() {
164        let blob = Threefish512CbcEncryptor::new([5u8; 64])
165            .encrypt(b"secret")
166            .unwrap();
167        let other = Threefish512CbcEncryptor::new([6u8; 64]);
168        assert_eq!(
169            other.decrypt(&blob).unwrap_err(),
170            Error::MacVerificationFailed { label: LABEL }
171        );
172    }
173
174    #[test]
175    fn iv_is_fresh_per_encryption() {
176        let encryptor = Threefish512CbcEncryptor::new([5u8; 64]);
177        let first = encryptor.encrypt(b"same plaintext").unwrap();
178        let second = encryptor.encrypt(b"same plaintext").unwrap();
179        assert_ne!(first, second);
180        // 变化必须发生在 IV 段(2..66),不是别的字段。
181        assert_ne!(first[2..66], second[2..66]);
182    }
183
184    #[test]
185    fn invalid_prefix_and_too_short_are_rejected() {
186        let encryptor = Threefish512CbcEncryptor::new([5u8; 64]);
187        assert_eq!(
188            encryptor.decrypt(b"v9 not a blob").unwrap_err(),
189            Error::InvalidPrefix { label: LABEL }
190        );
191        assert_eq!(
192            encryptor.decrypt(b"v1 short").unwrap_err(),
193            Error::TooShort { label: LABEL }
194        );
195    }
196
197    #[test]
198    fn key_length_is_checked() {
199        assert_eq!(
200            Threefish512CbcEncryptor::from_slice(&[0u8; 32]).unwrap_err(),
201            Error::InvalidKeyLength {
202                label: LABEL,
203                expected: 64,
204                got: 32
205            }
206        );
207    }
208}