1 /**
2 * CAST-256
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 
12 module botan.block.cast256;
13 
14 import botan.constants;
15 static if (BOTAN_HAS_CAST):
16 
17 import std.range : iota;
18 import botan.block.block_cipher;
19 import botan.block.cast_sboxes;
20 import botan.utils.loadstor;
21 import botan.utils.rotate;
22 import botan.utils.mem_ops;
23 
24 /**
25 * CAST-256
26 */
27 final class CAST256 : BlockCipherFixedParams!(16, 4, 32, 4), BlockCipher, SymmetricAlgorithm
28 {
29 public:
30     /*
31 * CAST-256 Encryption
32 */
33     override void encryptN(const(ubyte)* input, ubyte* output, size_t blocks)
34     {
35         foreach (size_t i; 0 .. blocks)
36         {
37             uint A = loadBigEndian!uint(input, 0);
38             uint B = loadBigEndian!uint(input, 1);
39             uint C = loadBigEndian!uint(input, 2);
40             uint D = loadBigEndian!uint(input, 3);
41             
42             round1(C, D, m_MK[ 0], m_RK[ 0]); round2(B, C, m_MK[ 1], m_RK[ 1]);
43             round3(A, B, m_MK[ 2], m_RK[ 2]); round1(D, A, m_MK[ 3], m_RK[ 3]);
44             round1(C, D, m_MK[ 4], m_RK[ 4]); round2(B, C, m_MK[ 5], m_RK[ 5]);
45             round3(A, B, m_MK[ 6], m_RK[ 6]); round1(D, A, m_MK[ 7], m_RK[ 7]);
46             round1(C, D, m_MK[ 8], m_RK[ 8]); round2(B, C, m_MK[ 9], m_RK[ 9]);
47             round3(A, B, m_MK[10], m_RK[10]); round1(D, A, m_MK[11], m_RK[11]);
48             round1(C, D, m_MK[12], m_RK[12]); round2(B, C, m_MK[13], m_RK[13]);
49             round3(A, B, m_MK[14], m_RK[14]); round1(D, A, m_MK[15], m_RK[15]);
50             round1(C, D, m_MK[16], m_RK[16]); round2(B, C, m_MK[17], m_RK[17]);
51             round3(A, B, m_MK[18], m_RK[18]); round1(D, A, m_MK[19], m_RK[19]);
52             round1(C, D, m_MK[20], m_RK[20]); round2(B, C, m_MK[21], m_RK[21]);
53             round3(A, B, m_MK[22], m_RK[22]); round1(D, A, m_MK[23], m_RK[23]);
54             round1(D, A, m_MK[27], m_RK[27]); round3(A, B, m_MK[26], m_RK[26]);
55             round2(B, C, m_MK[25], m_RK[25]); round1(C, D, m_MK[24], m_RK[24]);
56             round1(D, A, m_MK[31], m_RK[31]); round3(A, B, m_MK[30], m_RK[30]);
57             round2(B, C, m_MK[29], m_RK[29]); round1(C, D, m_MK[28], m_RK[28]);
58             round1(D, A, m_MK[35], m_RK[35]); round3(A, B, m_MK[34], m_RK[34]);
59             round2(B, C, m_MK[33], m_RK[33]); round1(C, D, m_MK[32], m_RK[32]);
60             round1(D, A, m_MK[39], m_RK[39]); round3(A, B, m_MK[38], m_RK[38]);
61             round2(B, C, m_MK[37], m_RK[37]); round1(C, D, m_MK[36], m_RK[36]);
62             round1(D, A, m_MK[43], m_RK[43]); round3(A, B, m_MK[42], m_RK[42]);
63             round2(B, C, m_MK[41], m_RK[41]); round1(C, D, m_MK[40], m_RK[40]);
64             round1(D, A, m_MK[47], m_RK[47]); round3(A, B, m_MK[46], m_RK[46]);
65             round2(B, C, m_MK[45], m_RK[45]); round1(C, D, m_MK[44], m_RK[44]);
66             
67             storeBigEndian(output, A, B, C, D);
68             
69             input += BLOCK_SIZE;
70             output += BLOCK_SIZE;
71         }
72     }
73 
74     /*
75     * CAST-256 Decryption
76     */
77     override void decryptN(const(ubyte)* input, ubyte* output, size_t blocks)
78     {
79         foreach (size_t i; 0 .. blocks)
80         {
81             uint A = loadBigEndian!uint(input, 0);
82             uint B = loadBigEndian!uint(input, 1);
83             uint C = loadBigEndian!uint(input, 2);
84             uint D = loadBigEndian!uint(input, 3);
85             
86             round1(C, D, m_MK[44], m_RK[44]); round2(B, C, m_MK[45], m_RK[45]);
87             round3(A, B, m_MK[46], m_RK[46]); round1(D, A, m_MK[47], m_RK[47]);
88             round1(C, D, m_MK[40], m_RK[40]); round2(B, C, m_MK[41], m_RK[41]);
89             round3(A, B, m_MK[42], m_RK[42]); round1(D, A, m_MK[43], m_RK[43]);
90             round1(C, D, m_MK[36], m_RK[36]); round2(B, C, m_MK[37], m_RK[37]);
91             round3(A, B, m_MK[38], m_RK[38]); round1(D, A, m_MK[39], m_RK[39]);
92             round1(C, D, m_MK[32], m_RK[32]); round2(B, C, m_MK[33], m_RK[33]);
93             round3(A, B, m_MK[34], m_RK[34]); round1(D, A, m_MK[35], m_RK[35]);
94             round1(C, D, m_MK[28], m_RK[28]); round2(B, C, m_MK[29], m_RK[29]);
95             round3(A, B, m_MK[30], m_RK[30]); round1(D, A, m_MK[31], m_RK[31]);
96             round1(C, D, m_MK[24], m_RK[24]); round2(B, C, m_MK[25], m_RK[25]);
97             round3(A, B, m_MK[26], m_RK[26]); round1(D, A, m_MK[27], m_RK[27]);
98             round1(D, A, m_MK[23], m_RK[23]); round3(A, B, m_MK[22], m_RK[22]);
99             round2(B, C, m_MK[21], m_RK[21]); round1(C, D, m_MK[20], m_RK[20]);
100             round1(D, A, m_MK[19], m_RK[19]); round3(A, B, m_MK[18], m_RK[18]);
101             round2(B, C, m_MK[17], m_RK[17]); round1(C, D, m_MK[16], m_RK[16]);
102             round1(D, A, m_MK[15], m_RK[15]); round3(A, B, m_MK[14], m_RK[14]);
103             round2(B, C, m_MK[13], m_RK[13]); round1(C, D, m_MK[12], m_RK[12]);
104             round1(D, A, m_MK[11], m_RK[11]); round3(A, B, m_MK[10], m_RK[10]);
105             round2(B, C, m_MK[ 9], m_RK[ 9]); round1(C, D, m_MK[ 8], m_RK[ 8]);
106             round1(D, A, m_MK[ 7], m_RK[ 7]); round3(A, B, m_MK[ 6], m_RK[ 6]);
107             round2(B, C, m_MK[ 5], m_RK[ 5]); round1(C, D, m_MK[ 4], m_RK[ 4]);
108             round1(D, A, m_MK[ 3], m_RK[ 3]); round3(A, B, m_MK[ 2], m_RK[ 2]);
109             round2(B, C, m_MK[ 1], m_RK[ 1]); round1(C, D, m_MK[ 0], m_RK[ 0]);
110             
111             storeBigEndian(output, A, B, C, D);
112             
113             input += BLOCK_SIZE;
114             output += BLOCK_SIZE;
115         }
116     }
117 
118     override void clear()
119     {
120         zap(m_MK);
121         zap(m_RK);
122     }
123 
124     @property string name() const { return "CAST-256"; }
125     override @property size_t parallelism() const { return 1; }
126     override BlockCipher clone() const { return new CAST256; }
127     override size_t blockSize() const { return super.blockSize(); }
128     override KeyLengthSpecification keySpec() const { return super.keySpec(); }
129 protected:
130 
131     /*
132     * CAST-256 Key Schedule
133     */
134     override void keySchedule(const(ubyte)* key, size_t length)
135     {
136         __gshared immutable uint[192] KEY_MASK = [
137             0x5A827999, 0xC95C653A, 0x383650DB, 0xA7103C7C, 0x15EA281D, 0x84C413BE,
138             0xF39DFF5F, 0x6277EB00, 0xD151D6A1, 0x402BC242, 0xAF05ADE3, 0x1DDF9984,
139             0x8CB98525, 0xFB9370C6, 0x6A6D5C67, 0xD9474808, 0x482133A9, 0xB6FB1F4A,
140             0x25D50AEB, 0x94AEF68C, 0x0388E22D, 0x7262CDCE, 0xE13CB96F, 0x5016A510,
141             0xBEF090B1, 0x2DCA7C52, 0x9CA467F3, 0x0B7E5394, 0x7A583F35, 0xE9322AD6,
142             0x580C1677, 0xC6E60218, 0x35BFEDB9, 0xA499D95A, 0x1373C4FB, 0x824DB09C,
143             0xF1279C3D, 0x600187DE, 0xCEDB737F, 0x3DB55F20, 0xAC8F4AC1, 0x1B693662,
144             0x8A432203, 0xF91D0DA4, 0x67F6F945, 0xD6D0E4E6, 0x45AAD087, 0xB484BC28,
145             0x235EA7C9, 0x9238936A, 0x01127F0B, 0x6FEC6AAC, 0xDEC6564D, 0x4DA041EE,
146             0xBC7A2D8F, 0x2B541930, 0x9A2E04D1, 0x0907F072, 0x77E1DC13, 0xE6BBC7B4,
147             0x5595B355, 0xC46F9EF6, 0x33498A97, 0xA2237638, 0x10FD61D9, 0x7FD74D7A,
148             0xEEB1391B, 0x5D8B24BC, 0xCC65105D, 0x3B3EFBFE, 0xAA18E79F, 0x18F2D340,
149             0x87CCBEE1, 0xF6A6AA82, 0x65809623, 0xD45A81C4, 0x43346D65, 0xB20E5906,
150             0x20E844A7, 0x8FC23048, 0xFE9C1BE9, 0x6D76078A, 0xDC4FF32B, 0x4B29DECC,
151             0xBA03CA6D, 0x28DDB60E, 0x97B7A1AF, 0x06918D50, 0x756B78F1, 0xE4456492,
152             0x531F5033, 0xC1F93BD4, 0x30D32775, 0x9FAD1316, 0x0E86FEB7, 0x7D60EA58,
153             0xEC3AD5F9, 0x5B14C19A, 0xC9EEAD3B, 0x38C898DC, 0xA7A2847D, 0x167C701E,
154             0x85565BBF, 0xF4304760, 0x630A3301, 0xD1E41EA2, 0x40BE0A43, 0xAF97F5E4,
155             0x1E71E185, 0x8D4BCD26, 0xFC25B8C7, 0x6AFFA468, 0xD9D99009, 0x48B37BAA,
156             0xB78D674B, 0x266752EC, 0x95413E8D, 0x041B2A2E, 0x72F515CF, 0xE1CF0170,
157             0x50A8ED11, 0xBF82D8B2, 0x2E5CC453, 0x9D36AFF4, 0x0C109B95, 0x7AEA8736,
158             0xE9C472D7, 0x589E5E78, 0xC7784A19, 0x365235BA, 0xA52C215B, 0x14060CFC,
159             0x82DFF89D, 0xF1B9E43E, 0x6093CFDF, 0xCF6DBB80, 0x3E47A721, 0xAD2192C2,
160             0x1BFB7E63, 0x8AD56A04, 0xF9AF55A5, 0x68894146, 0xD7632CE7, 0x463D1888,
161             0xB5170429, 0x23F0EFCA, 0x92CADB6B, 0x01A4C70C, 0x707EB2AD, 0xDF589E4E,
162             0x4E3289EF, 0xBD0C7590, 0x2BE66131, 0x9AC04CD2, 0x099A3873, 0x78742414,
163             0xE74E0FB5, 0x5627FB56, 0xC501E6F7, 0x33DBD298, 0xA2B5BE39, 0x118FA9DA,
164             0x8069957B, 0xEF43811C, 0x5E1D6CBD, 0xCCF7585E, 0x3BD143FF, 0xAAAB2FA0,
165             0x19851B41, 0x885F06E2, 0xF738F283, 0x6612DE24, 0xD4ECC9C5, 0x43C6B566,
166             0xB2A0A107, 0x217A8CA8, 0x90547849, 0xFF2E63EA, 0x6E084F8B, 0xDCE23B2C,
167             0x4BBC26CD, 0xBA96126E, 0x296FFE0F, 0x9849E9B0, 0x0723D551, 0x75FDC0F2,
168             0xE4D7AC93, 0x53B19834, 0xC28B83D5, 0x31656F76, 0xA03F5B17, 0x0F1946B8 ];
169         
170         __gshared immutable ubyte[32] KEY_ROT = [
171             0x13, 0x04, 0x15, 0x06, 0x17, 0x08, 0x19, 0x0A, 0x1B, 0x0C,
172             0x1D, 0x0E, 0x1F, 0x10, 0x01, 0x12, 0x03, 0x14, 0x05, 0x16,
173             0x07, 0x18, 0x09, 0x1A, 0x0B, 0x1C, 0x0D, 0x1E, 0x0F, 0x00,
174             0x11, 0x02 ];
175         
176         m_MK.resize(48);
177         m_RK.resize(48);
178         
179         SecureVector!uint K = SecureVector!uint(8);
180         foreach (size_t i; 0 .. length)
181             K[i/4] = (K[i/4] << 8) + key[i];
182         
183         uint A = K[0], B = K[1], C = K[2], D = K[3],
184             E = K[4], F = K[5], G = K[6], H = K[7];
185         
186         foreach (size_t i; iota(0, 48, 4))
187         {
188             round1(G, H, KEY_MASK[4*i+ 0], KEY_ROT[(4*i+ 0) % 32]);
189             round2(F, G, KEY_MASK[4*i+ 1], KEY_ROT[(4*i+ 1) % 32]);
190             round3(E, F, KEY_MASK[4*i+ 2], KEY_ROT[(4*i+ 2) % 32]);
191             round1(D, E, KEY_MASK[4*i+ 3], KEY_ROT[(4*i+ 3) % 32]);
192             round2(C, D, KEY_MASK[4*i+ 4], KEY_ROT[(4*i+ 4) % 32]);
193             round3(B, C, KEY_MASK[4*i+ 5], KEY_ROT[(4*i+ 5) % 32]);
194             round1(A, B, KEY_MASK[4*i+ 6], KEY_ROT[(4*i+ 6) % 32]);
195             round2(H, A, KEY_MASK[4*i+ 7], KEY_ROT[(4*i+ 7) % 32]);
196             round1(G, H, KEY_MASK[4*i+ 8], KEY_ROT[(4*i+ 8) % 32]);
197             round2(F, G, KEY_MASK[4*i+ 9], KEY_ROT[(4*i+ 9) % 32]);
198             round3(E, F, KEY_MASK[4*i+10], KEY_ROT[(4*i+10) % 32]);
199             round1(D, E, KEY_MASK[4*i+11], KEY_ROT[(4*i+11) % 32]);
200             round2(C, D, KEY_MASK[4*i+12], KEY_ROT[(4*i+12) % 32]);
201             round3(B, C, KEY_MASK[4*i+13], KEY_ROT[(4*i+13) % 32]);
202             round1(A, B, KEY_MASK[4*i+14], KEY_ROT[(4*i+14) % 32]);
203             round2(H, A, KEY_MASK[4*i+15], KEY_ROT[(4*i+15) % 32]);
204             
205             m_RK[i  ] = (A % 32);
206             m_RK[i+1] = (C % 32);
207             m_RK[i+2] = (E % 32);
208             m_RK[i+3] = (G % 32);
209             m_MK[i  ] = H;
210             m_MK[i+1] = F;
211             m_MK[i+2] = D;
212             m_MK[i+3] = B;
213         }
214     }
215 
216     SecureVector!uint m_MK;
217     SecureVector!ubyte m_RK;
218 }
219 
220 
221 private:
222     
223 import botan.utils.get_byte : get_byte;
224 /*
225 * CAST-256 Round Type 1
226 */
227 void round1(ref uint output, uint input, uint mask, uint rot) pure
228 {
229     uint temp = rotateLeft(mask + input, rot);
230     output  ^= (CAST_SBOX1[get_byte(0, temp)] ^ CAST_SBOX2[get_byte(1, temp)]) -
231                 CAST_SBOX3[get_byte(2, temp)] + CAST_SBOX4[get_byte(3, temp)];
232 }
233 
234 /*
235 * CAST-256 Round Type 2
236 */
237 void round2(ref uint output, uint input, uint mask, uint rot) pure
238 {
239     uint temp = rotateLeft(mask ^ input, rot);
240     output  ^= (CAST_SBOX1[get_byte(0, temp)]  - CAST_SBOX2[get_byte(1, temp)] +
241                 CAST_SBOX3[get_byte(2, temp)]) ^ CAST_SBOX4[get_byte(3, temp)];
242 }
243 
244 /*
245 * CAST-256 Round Type 3
246 */
247 void round3(ref uint output, uint input, uint mask, uint rot) pure
248 {
249     uint temp = rotateLeft(mask - input, rot);
250     output  ^= ((CAST_SBOX1[get_byte(0, temp)]  + CAST_SBOX2[get_byte(1, temp)]) ^
251                 CAST_SBOX3[get_byte(2, temp)]) - CAST_SBOX4[get_byte(3, temp)];
252 }