1 /**
2 * XTEA
3 * 
4 * Copyright:
5 * (C) 1999-2007 Jack Lloyd
6 * (C) 2014-2015 Etienne Cimon
7 *
8 * License:
9 * Botan is released under the Simplified BSD License (see LICENSE.md)
10 */
11 module botan.block.xtea;
12 
13 import botan.constants;
14 static if (BOTAN_HAS_XTEA):
15 
16 import std.range : iota;
17 import botan.block.block_cipher;
18 import botan.utils.loadstor;
19 import botan.utils.mem_ops;
20 
21 /**
22 * XTEA
23 */
24 class XTEA : BlockCipherFixedParams!(8, 16), BlockCipher, SymmetricAlgorithm
25 {
26 public:
27     /*
28     * XTEA Encryption
29     */
30     override void encryptN(const(ubyte)* input, ubyte* output, size_t blocks)
31     {
32         while (blocks >= 4)
33         {
34             xtea_encrypt_4(*cast(ubyte[32]*) input, *cast(ubyte[32]*) output, *cast(uint[64]*) m_EK.ptr);
35             input += 4 * BLOCK_SIZE;
36             output += 4 * BLOCK_SIZE;
37             blocks -= 4;
38         }
39         
40         foreach (size_t i; 0 .. blocks)
41         {
42             uint L = loadBigEndian!uint(input, 0);
43             uint R = loadBigEndian!uint(input, 1);
44             
45             foreach (size_t j; 0 .. 32)
46             {
47                 L += (((R << 4) ^ (R >> 5)) + R) ^ m_EK[2*j];
48                 R += (((L << 4) ^ (L >> 5)) + L) ^ m_EK[2*j+1];
49             }
50             
51             storeBigEndian(output, L, R);
52             
53             input += BLOCK_SIZE;
54             output += BLOCK_SIZE;
55         }
56     }
57     
58     /*
59     * XTEA Decryption
60     */
61     override void decryptN(const(ubyte)* input, ubyte* output, size_t blocks)
62     {
63         while (blocks >= 4)
64         {
65             xtea_decrypt_4(*cast(ubyte[32]*) input, *cast(ubyte[32]*) output, *cast(uint[64]*) m_EK.ptr);
66             input += 4 * BLOCK_SIZE;
67             output += 4 * BLOCK_SIZE;
68             blocks -= 4;
69         }
70         
71         foreach (size_t i; 0 .. blocks)
72         {
73             uint L = loadBigEndian!uint(input, 0);
74             uint R = loadBigEndian!uint(input, 1);
75             
76             foreach (size_t j; 0 .. 32)
77             {
78                 R -= (((L << 4) ^ (L >> 5)) + L) ^ m_EK[63 - 2*j];
79                 L -= (((R << 4) ^ (R >> 5)) + R) ^ m_EK[62 - 2*j];
80             }
81             
82             storeBigEndian(output, L, R);
83             
84             input += BLOCK_SIZE;
85             output += BLOCK_SIZE;
86         }
87     }
88 
89     override void clear()
90     {
91         zap(m_EK);
92     }
93 
94     override @property string name() const { return "XTEA"; }
95     override @property size_t parallelism() const { return 1; }
96     override BlockCipher clone() const { return new XTEA; }
97     override size_t blockSize() const { return super.blockSize(); }
98     override KeyLengthSpecification keySpec() const { return super.keySpec(); }
99 protected:
100     /**
101     * Returns: const reference to the key schedule
102     */
103     ref const(SecureVector!uint) getEK() const { return m_EK; }
104 
105 protected:
106     /*
107     * XTEA Key Schedule
108     */
109     override void keySchedule(const(ubyte)* key, size_t)
110     {
111         m_EK.resize(64);
112         
113         SecureVector!uint UK = SecureVector!uint(4);
114         foreach (size_t i; 0 .. 4)
115             UK[i] = loadBigEndian!uint(key, i);
116         
117         uint D = 0;
118         foreach (size_t i; iota(0, 64, 2))
119         {
120             m_EK[i  ] = D + UK[D % 4];
121             D += 0x9E3779B9;
122             m_EK[i+1] = D + UK[(D >> 11) % 4];
123         }
124     }
125 
126     SecureVector!uint m_EK;
127 }
128 
129 package:
130 
131 void xtea_encrypt_4(in ubyte[32] input, ref ubyte[32] output, in uint[64] EK)
132 {
133     uint L0, R0, L1, R1, L2, R2, L3, R3;
134     loadBigEndian(input.ptr, L0, R0, L1, R1, L2, R2, L3, R3);
135     
136     foreach (size_t i; 0 .. 32)
137     {
138         L0 += (((R0 << 4) ^ (R0 >> 5)) + R0) ^ EK[2*i];
139         L1 += (((R1 << 4) ^ (R1 >> 5)) + R1) ^ EK[2*i];
140         L2 += (((R2 << 4) ^ (R2 >> 5)) + R2) ^ EK[2*i];
141         L3 += (((R3 << 4) ^ (R3 >> 5)) + R3) ^ EK[2*i];
142         
143         R0 += (((L0 << 4) ^ (L0 >> 5)) + L0) ^ EK[2*i+1];
144         R1 += (((L1 << 4) ^ (L1 >> 5)) + L1) ^ EK[2*i+1];
145         R2 += (((L2 << 4) ^ (L2 >> 5)) + L2) ^ EK[2*i+1];
146         R3 += (((L3 << 4) ^ (L3 >> 5)) + L3) ^ EK[2*i+1];
147     }
148     
149     storeBigEndian(output.ptr, L0, R0, L1, R1, L2, R2, L3, R3);
150 }
151 
152 void xtea_decrypt_4(in ubyte[32] input, ref ubyte[32] output, in uint[64] EK)
153 {
154     uint L0, R0, L1, R1, L2, R2, L3, R3;
155     loadBigEndian(input.ptr, L0, R0, L1, R1, L2, R2, L3, R3);
156     
157     foreach (size_t i; 0 .. 32)
158     {
159         R0 -= (((L0 << 4) ^ (L0 >> 5)) + L0) ^ EK[63 - 2*i];
160         R1 -= (((L1 << 4) ^ (L1 >> 5)) + L1) ^ EK[63 - 2*i];
161         R2 -= (((L2 << 4) ^ (L2 >> 5)) + L2) ^ EK[63 - 2*i];
162         R3 -= (((L3 << 4) ^ (L3 >> 5)) + L3) ^ EK[63 - 2*i];
163         
164         L0 -= (((R0 << 4) ^ (R0 >> 5)) + R0) ^ EK[62 - 2*i];
165         L1 -= (((R1 << 4) ^ (R1 >> 5)) + R1) ^ EK[62 - 2*i];
166         L2 -= (((R2 << 4) ^ (R2 >> 5)) + R2) ^ EK[62 - 2*i];
167         L3 -= (((R3 << 4) ^ (R3 >> 5)) + R3) ^ EK[62 - 2*i];
168     }
169     
170     storeBigEndian(output.ptr, L0, R0, L1, R1, L2, R2, L3, R3);
171 }