1 /**
2 * RC6
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.rc6;
12 
13 import botan.constants;
14 static if (BOTAN_HAS_RC6):
15 
16 import botan.block.block_cipher;
17 import botan.utils.loadstor;
18 import botan.utils.rotate;
19 import std.algorithm;
20 import botan.utils.mem_ops;
21 
22 /**
23 * RC6, Ron Rivest's AES candidate
24 */
25 final class RC6 : BlockCipherFixedParams!(16, 1, 32), BlockCipher, SymmetricAlgorithm
26 {
27 public:
28     /*
29     * RC6 Encryption
30     */
31     override void encryptN(const(ubyte)* input, ubyte* output, size_t blocks)
32     {
33         foreach (size_t i; 0 .. blocks)
34         {
35             uint A = loadLittleEndian!uint(input, 0);
36             uint B = loadLittleEndian!uint(input, 1);
37             uint C = loadLittleEndian!uint(input, 2);
38             uint D = loadLittleEndian!uint(input, 3);
39             
40             B += m_S[0]; D += m_S[1];
41             
42             for (size_t j = 0; j != 20; j += 4)
43             {
44                 uint T1, T2;
45                 
46                 T1 = rotateLeft(B*(2*B+1), 5);
47                 T2 = rotateLeft(D*(2*D+1), 5);
48                 A = rotateLeft(A ^ T1, T2 % 32) + m_S[2*j+2];
49                 C = rotateLeft(C ^ T2, T1 % 32) + m_S[2*j+3];
50                 
51                 T1 = rotateLeft(C*(2*C+1), 5);
52                 T2 = rotateLeft(A*(2*A+1), 5);
53                 B = rotateLeft(B ^ T1, T2 % 32) + m_S[2*j+4];
54                 D = rotateLeft(D ^ T2, T1 % 32) + m_S[2*j+5];
55                 
56                 T1 = rotateLeft(D*(2*D+1), 5);
57                 T2 = rotateLeft(B*(2*B+1), 5);
58                 C = rotateLeft(C ^ T1, T2 % 32) + m_S[2*j+6];
59                 A = rotateLeft(A ^ T2, T1 % 32) + m_S[2*j+7];
60                 
61                 T1 = rotateLeft(A*(2*A+1), 5);
62                 T2 = rotateLeft(C*(2*C+1), 5);
63                 D = rotateLeft(D ^ T1, T2 % 32) + m_S[2*j+8];
64                 B = rotateLeft(B ^ T2, T1 % 32) + m_S[2*j+9];
65             }
66             
67             A += m_S[42]; C += m_S[43];
68             
69             storeLittleEndian(output, A, B, C, D);
70             
71             input += BLOCK_SIZE;
72             output += BLOCK_SIZE;
73         }
74     }
75     /*
76     * RC6 Decryption
77     */
78     override void decryptN(const(ubyte)* input, ubyte* output, size_t blocks)
79     {
80         foreach (size_t i; 0 .. blocks)
81         {
82             uint A = loadLittleEndian!uint(input, 0);
83             uint B = loadLittleEndian!uint(input, 1);
84             uint C = loadLittleEndian!uint(input, 2);
85             uint D = loadLittleEndian!uint(input, 3);
86             
87             C -= m_S[43]; A -= m_S[42];
88             
89             for (size_t j = 0; j != 20; j += 4)
90             {
91                 uint T1, T2;
92                 
93                 T1 = rotateLeft(A*(2*A+1), 5);
94                 T2 = rotateLeft(C*(2*C+1), 5);
95                 B = rotateRight(B - m_S[41 - 2*j], T1 % 32) ^ T2;
96                 D = rotateRight(D - m_S[40 - 2*j], T2 % 32) ^ T1;
97                 
98                 T1 = rotateLeft(D*(2*D+1), 5);
99                 T2 = rotateLeft(B*(2*B+1), 5);
100                 A = rotateRight(A - m_S[39 - 2*j], T1 % 32) ^ T2;
101                 C = rotateRight(C - m_S[38 - 2*j], T2 % 32) ^ T1;
102                 
103                 T1 = rotateLeft(C*(2*C+1), 5);
104                 T2 = rotateLeft(A*(2*A+1), 5);
105                 D = rotateRight(D - m_S[37 - 2*j], T1 % 32) ^ T2;
106                 B = rotateRight(B - m_S[36 - 2*j], T2 % 32) ^ T1;
107                 
108                 T1 = rotateLeft(B*(2*B+1), 5);
109                 T2 = rotateLeft(D*(2*D+1), 5);
110                 C = rotateRight(C - m_S[35 - 2*j], T1 % 32) ^ T2;
111                 A = rotateRight(A - m_S[34 - 2*j], T2 % 32) ^ T1;
112             }
113             
114             D -= m_S[1]; B -= m_S[0];
115             
116             storeLittleEndian(output, A, B, C, D);
117             
118             input += BLOCK_SIZE;
119             output += BLOCK_SIZE;
120         }
121     }
122 
123     override void clear()
124     {
125         zap(m_S);
126     }
127 
128     override @property string name() const { return "RC6"; }
129     override @property size_t parallelism() const { return 1; }
130     override BlockCipher clone() const { return new RC6; }
131     override size_t blockSize() const { return super.blockSize(); }
132     override KeyLengthSpecification keySpec() const { return super.keySpec(); }
133 protected:
134     /*
135     * RC6 Key Schedule
136     */
137     override void keySchedule(const(ubyte)* key, size_t length)
138     {
139         m_S.resize(44);
140         
141         const size_t WORD_KEYLENGTH = (((length - 1) / 4) + 1);
142         const size_t MIX_ROUNDS      = 3 * std.algorithm.max(WORD_KEYLENGTH, m_S.length);
143         
144         m_S[0] = 0xB7E15163;
145         foreach (size_t i; 1 .. m_S.length)
146             m_S[i] = m_S[i-1] + 0x9E3779B9;
147         
148         SecureVector!uint K = SecureVector!uint(8);
149         
150         for (int i = cast(int) length-1; i >= 0; --i)
151             K[i/4] = (K[i/4] << 8) + key[i];
152         
153         uint A = 0, B = 0;
154         foreach (size_t i; 0 .. MIX_ROUNDS)
155         {
156             A = rotateLeft(m_S[i % m_S.length] + A + B, 3);
157             B = rotateLeft(K[i % WORD_KEYLENGTH] + A + B, (A + B) % 32);
158             m_S[i % m_S.length] = A;
159             K[i % WORD_KEYLENGTH] = B;
160         }
161     }
162 
163     SecureVector!uint m_S;
164 }