1#![no_std]
14#![doc(
15 html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/26acc39f/logo.svg",
16 html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/26acc39f/logo.svg"
17)]
18#![deny(unsafe_code)]
19#![cfg_attr(docsrs, feature(doc_cfg))]
20#![warn(missing_docs, rust_2018_idioms)]
21
22pub use cipher;
23
24use cipher::{
25 AlgorithmName, Block, BlockCipherDecBackend, BlockCipherDecClosure, BlockCipherDecrypt,
26 BlockCipherEncBackend, BlockCipherEncClosure, BlockCipherEncrypt, BlockSizeUser, InOut,
27 InvalidLength, Key, KeyInit, KeySizeUser, ParBlocksSizeUser,
28 consts::{U1, U8, U16},
29};
30use core::fmt;
31
32#[cfg(feature = "zeroize")]
33use cipher::zeroize::{Zeroize, ZeroizeOnDrop};
34
35mod consts;
36use consts::{DELTA, ROUNDS};
37
38pub struct Xtea {
40 k: [u32; 4],
41}
42
43impl KeySizeUser for Xtea {
44 type KeySize = U16;
45}
46
47impl KeyInit for Xtea {
48 fn new(key: &Key<Self>) -> Self {
49 Self::new_from_slice(key).unwrap()
50 }
51
52 fn new_from_slice(key: &[u8]) -> Result<Self, InvalidLength> {
53 if key.len() != 16 {
54 return Err(InvalidLength);
55 }
56 let key = [
57 u32::from_le_bytes(key[0..4].try_into().unwrap()),
58 u32::from_le_bytes(key[4..8].try_into().unwrap()),
59 u32::from_le_bytes(key[8..12].try_into().unwrap()),
60 u32::from_le_bytes(key[12..16].try_into().unwrap()),
61 ];
62 Ok(Xtea { k: key })
63 }
64}
65
66impl BlockSizeUser for Xtea {
67 type BlockSize = U8;
68}
69
70impl ParBlocksSizeUser for Xtea {
71 type ParBlocksSize = U1;
72}
73
74impl BlockCipherEncrypt for Xtea {
75 #[inline]
76 fn encrypt_with_backend(&self, f: impl BlockCipherEncClosure<BlockSize = Self::BlockSize>) {
77 f.call(self)
78 }
79}
80
81impl BlockCipherEncBackend for Xtea {
82 #[inline]
83 fn encrypt_block(&self, mut block: InOut<'_, '_, Block<Self>>) {
84 let v = block.get_in();
85 let mut v0 = u32::from_le_bytes(v[0..4].try_into().unwrap());
86 let mut v1 = u32::from_le_bytes(v[4..8].try_into().unwrap());
87 let mut sum = 0u32;
88
89 for _ in 0..8 {
91 v0 = v0.wrapping_add(
92 (((v1 << 4) ^ (v1 >> 5)).wrapping_add(v1))
93 ^ sum.wrapping_add(self.k[(sum & 3) as usize]),
94 );
95 sum = sum.wrapping_add(DELTA);
96 v1 = v1.wrapping_add(
97 (((v0 << 4) ^ (v0 >> 5)).wrapping_add(v0))
98 ^ sum.wrapping_add(self.k[((sum >> 11) & 3) as usize]),
99 );
100 }
101 for _ in 0..8 {
102 v0 = v0.wrapping_add(
103 (((v1 << 4) ^ (v1 >> 5)).wrapping_add(v1))
104 ^ sum.wrapping_add(self.k[(sum & 3) as usize]),
105 );
106 sum = sum.wrapping_add(DELTA);
107 v1 = v1.wrapping_add(
108 (((v0 << 4) ^ (v0 >> 5)).wrapping_add(v0))
109 ^ sum.wrapping_add(self.k[((sum >> 11) & 3) as usize]),
110 );
111 }
112 for _ in 0..8 {
113 v0 = v0.wrapping_add(
114 (((v1 << 4) ^ (v1 >> 5)).wrapping_add(v1))
115 ^ sum.wrapping_add(self.k[(sum & 3) as usize]),
116 );
117 sum = sum.wrapping_add(DELTA);
118 v1 = v1.wrapping_add(
119 (((v0 << 4) ^ (v0 >> 5)).wrapping_add(v0))
120 ^ sum.wrapping_add(self.k[((sum >> 11) & 3) as usize]),
121 );
122 }
123 for _ in 0..8 {
124 v0 = v0.wrapping_add(
125 (((v1 << 4) ^ (v1 >> 5)).wrapping_add(v1))
126 ^ sum.wrapping_add(self.k[(sum & 3) as usize]),
127 );
128 sum = sum.wrapping_add(DELTA);
129 v1 = v1.wrapping_add(
130 (((v0 << 4) ^ (v0 >> 5)).wrapping_add(v0))
131 ^ sum.wrapping_add(self.k[((sum >> 11) & 3) as usize]),
132 );
133 }
134
135 let v = block.get_out();
136 v[0..4].copy_from_slice(&v0.to_le_bytes());
137 v[4..8].copy_from_slice(&v1.to_le_bytes());
138 }
139}
140
141impl BlockCipherDecrypt for Xtea {
142 #[inline]
143 fn decrypt_with_backend(&self, f: impl BlockCipherDecClosure<BlockSize = Self::BlockSize>) {
144 f.call(self)
145 }
146}
147
148impl BlockCipherDecBackend for Xtea {
149 #[inline]
150 fn decrypt_block(&self, mut block: InOut<'_, '_, Block<Self>>) {
151 let v = block.get_in();
152 let mut v0 = u32::from_le_bytes(v[0..4].try_into().unwrap());
153 let mut v1 = u32::from_le_bytes(v[4..8].try_into().unwrap());
154 let mut sum = DELTA.wrapping_mul(ROUNDS as u32);
155
156 for _ in 0..8 {
158 v1 = v1.wrapping_sub(
159 (((v0 << 4) ^ (v0 >> 5)).wrapping_add(v0))
160 ^ sum.wrapping_add(self.k[((sum >> 11) & 3) as usize]),
161 );
162 sum = sum.wrapping_sub(DELTA);
163 v0 = v0.wrapping_sub(
164 (((v1 << 4) ^ (v1 >> 5)).wrapping_add(v1))
165 ^ sum.wrapping_add(self.k[(sum & 3) as usize]),
166 );
167 }
168 for _ in 0..8 {
169 v1 = v1.wrapping_sub(
170 (((v0 << 4) ^ (v0 >> 5)).wrapping_add(v0))
171 ^ sum.wrapping_add(self.k[((sum >> 11) & 3) as usize]),
172 );
173 sum = sum.wrapping_sub(DELTA);
174 v0 = v0.wrapping_sub(
175 (((v1 << 4) ^ (v1 >> 5)).wrapping_add(v1))
176 ^ sum.wrapping_add(self.k[(sum & 3) as usize]),
177 );
178 }
179 for _ in 0..8 {
180 v1 = v1.wrapping_sub(
181 (((v0 << 4) ^ (v0 >> 5)).wrapping_add(v0))
182 ^ sum.wrapping_add(self.k[((sum >> 11) & 3) as usize]),
183 );
184 sum = sum.wrapping_sub(DELTA);
185 v0 = v0.wrapping_sub(
186 (((v1 << 4) ^ (v1 >> 5)).wrapping_add(v1))
187 ^ sum.wrapping_add(self.k[(sum & 3) as usize]),
188 );
189 }
190 for _ in 0..8 {
191 v1 = v1.wrapping_sub(
192 (((v0 << 4) ^ (v0 >> 5)).wrapping_add(v0))
193 ^ sum.wrapping_add(self.k[((sum >> 11) & 3) as usize]),
194 );
195 sum = sum.wrapping_sub(DELTA);
196 v0 = v0.wrapping_sub(
197 (((v1 << 4) ^ (v1 >> 5)).wrapping_add(v1))
198 ^ sum.wrapping_add(self.k[(sum & 3) as usize]),
199 );
200 }
201
202 let v = block.get_out();
203 v[0..4].copy_from_slice(&v0.to_le_bytes());
204 v[4..8].copy_from_slice(&v1.to_le_bytes());
205 }
206}
207
208impl fmt::Debug for Xtea {
209 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
210 f.write_str("XTEA { ... }")
211 }
212}
213
214impl AlgorithmName for Xtea {
215 fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result {
216 f.write_str("XTEA")
217 }
218}
219
220impl Drop for Xtea {
221 fn drop(&mut self) {
222 #[cfg(feature = "zeroize")]
223 self.k.zeroize();
224 }
225}
226
227#[cfg(feature = "zeroize")]
228impl ZeroizeOnDrop for Xtea {}