1 /**
2 * MARS
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.mars;
12 
13 import botan.constants;
14 static if (BOTAN_HAS_MARS):
15 
16 import std.range : iota;
17 import botan.block.block_cipher;
18 import botan.utils.loadstor;
19 import botan.utils.rotate;
20 import botan.utils.get_byte;
21 import botan.utils.mem_ops;
22 
23 /**
24 * MARS, IBM's candidate for AES
25 */
26 final class MARS : BlockCipherFixedParams!(16, 16, 32, 4), BlockCipher, SymmetricAlgorithm
27 {
28 public:
29     /*
30     * MARS Encryption
31     */
32     override void encryptN(const(ubyte)* input, ubyte* output, size_t blocks)
33     {
34         foreach (size_t i; 0 .. blocks)
35         {
36             uint A = loadLittleEndian!uint(input, 0) + m_EK[0];
37             uint B = loadLittleEndian!uint(input, 1) + m_EK[1];
38             uint C = loadLittleEndian!uint(input, 2) + m_EK[2];
39             uint D = loadLittleEndian!uint(input, 3) + m_EK[3];
40             
41             forward_mix(A, B, C, D);
42             
43             encrypt_round(A, B, C, D, m_EK[ 4], m_EK[ 5]);
44             encrypt_round(B, C, D, A, m_EK[ 6], m_EK[ 7]);
45             encrypt_round(C, D, A, B, m_EK[ 8], m_EK[ 9]);
46             encrypt_round(D, A, B, C, m_EK[10], m_EK[11]);
47             encrypt_round(A, B, C, D, m_EK[12], m_EK[13]);
48             encrypt_round(B, C, D, A, m_EK[14], m_EK[15]);
49             encrypt_round(C, D, A, B, m_EK[16], m_EK[17]);
50             encrypt_round(D, A, B, C, m_EK[18], m_EK[19]);
51             
52             encrypt_round(A, D, C, B, m_EK[20], m_EK[21]);
53             encrypt_round(B, A, D, C, m_EK[22], m_EK[23]);
54             encrypt_round(C, B, A, D, m_EK[24], m_EK[25]);
55             encrypt_round(D, C, B, A, m_EK[26], m_EK[27]);
56             encrypt_round(A, D, C, B, m_EK[28], m_EK[29]);
57             encrypt_round(B, A, D, C, m_EK[30], m_EK[31]);
58             encrypt_round(C, B, A, D, m_EK[32], m_EK[33]);
59             encrypt_round(D, C, B, A, m_EK[34], m_EK[35]);
60             
61             reverse_mix(A, B, C, D);
62             
63             A -= m_EK[36]; B -= m_EK[37]; C -= m_EK[38]; D -= m_EK[39];
64             
65             storeLittleEndian(output, A, B, C, D);
66             
67             input += BLOCK_SIZE;
68             output += BLOCK_SIZE;
69         }
70     }
71 
72     /*
73     * MARS Decryption
74     */
75     override void decryptN(const(ubyte)* input, ubyte* output, size_t blocks)
76     {
77         foreach (size_t i; 0 .. blocks)
78         {
79             uint A = loadLittleEndian!uint(input, 3) + m_EK[39];
80             uint B = loadLittleEndian!uint(input, 2) + m_EK[38];
81             uint C = loadLittleEndian!uint(input, 1) + m_EK[37];
82             uint D = loadLittleEndian!uint(input, 0) + m_EK[36];
83             
84             forward_mix(A, B, C, D);
85             
86             decrypt_round(A, B, C, D, m_EK[35], m_EK[34]);
87             decrypt_round(B, C, D, A, m_EK[33], m_EK[32]);
88             decrypt_round(C, D, A, B, m_EK[31], m_EK[30]);
89             decrypt_round(D, A, B, C, m_EK[29], m_EK[28]);
90             decrypt_round(A, B, C, D, m_EK[27], m_EK[26]);
91             decrypt_round(B, C, D, A, m_EK[25], m_EK[24]);
92             decrypt_round(C, D, A, B, m_EK[23], m_EK[22]);
93             decrypt_round(D, A, B, C, m_EK[21], m_EK[20]);
94             
95             decrypt_round(A, D, C, B, m_EK[19], m_EK[18]);
96             decrypt_round(B, A, D, C, m_EK[17], m_EK[16]);
97             decrypt_round(C, B, A, D, m_EK[15], m_EK[14]);
98             decrypt_round(D, C, B, A, m_EK[13], m_EK[12]);
99             decrypt_round(A, D, C, B, m_EK[11], m_EK[10]);
100             decrypt_round(B, A, D, C, m_EK[ 9], m_EK[ 8]);
101             decrypt_round(C, B, A, D, m_EK[ 7], m_EK[ 6]);
102             decrypt_round(D, C, B, A, m_EK[ 5], m_EK[ 4]);
103             
104             reverse_mix(A, B, C, D);
105             
106             A -= m_EK[3]; B -= m_EK[2]; C -= m_EK[1]; D -= m_EK[0];
107             
108             storeLittleEndian(output, D, C, B, A);
109             
110             input += BLOCK_SIZE;
111             output += BLOCK_SIZE;
112         }
113     }
114 
115     override void clear()
116     {
117         zap(m_EK);
118     }
119 
120     @property string name() const { return "MARS"; }
121     override @property size_t parallelism() const { return 1; }
122     override BlockCipher clone() const { return new MARS; }
123     override size_t blockSize() const { return super.blockSize(); }
124     override KeyLengthSpecification keySpec() const { return super.keySpec(); }
125 
126 protected:
127     /*
128     * MARS Key Schedule
129     */
130     override void keySchedule(const(ubyte)* key, size_t length)
131     {
132         SecureVector!uint T = SecureVector!uint(15);
133         foreach (size_t i; 0 .. (length / 4))
134             T[i] = loadLittleEndian!uint(key, i);
135         
136         T[length / 4] = cast(uint)(length) / 4;
137         
138         m_EK.resize(40);
139         
140         for (uint i = 0; i != 4; ++i)
141         {
142             T[ 0] ^= rotateLeft(T[ 8] ^ T[13], 3) ^ (i      );
143             T[ 1] ^= rotateLeft(T[ 9] ^ T[14], 3) ^ (i +  4);
144             T[ 2] ^= rotateLeft(T[10] ^ T[ 0], 3) ^ (i +  8);
145             T[ 3] ^= rotateLeft(T[11] ^ T[ 1], 3) ^ (i + 12);
146             T[ 4] ^= rotateLeft(T[12] ^ T[ 2], 3) ^ (i + 16);
147             T[ 5] ^= rotateLeft(T[13] ^ T[ 3], 3) ^ (i + 20);
148             T[ 6] ^= rotateLeft(T[14] ^ T[ 4], 3) ^ (i + 24);
149             T[ 7] ^= rotateLeft(T[ 0] ^ T[ 5], 3) ^ (i + 28);
150             T[ 8] ^= rotateLeft(T[ 1] ^ T[ 6], 3) ^ (i + 32);
151             T[ 9] ^= rotateLeft(T[ 2] ^ T[ 7], 3) ^ (i + 36);
152             T[10] ^= rotateLeft(T[ 3] ^ T[ 8], 3) ^ (i + 40);
153             T[11] ^= rotateLeft(T[ 4] ^ T[ 9], 3) ^ (i + 44);
154             T[12] ^= rotateLeft(T[ 5] ^ T[10], 3) ^ (i + 48);
155             T[13] ^= rotateLeft(T[ 6] ^ T[11], 3) ^ (i + 52);
156             T[14] ^= rotateLeft(T[ 7] ^ T[12], 3) ^ (i + 56);
157             
158             foreach (size_t j; 0 .. 4)
159             {
160                 T[ 0] = rotateLeft(T[ 0] + SBOX[T[14] % 512], 9);
161                 T[ 1] = rotateLeft(T[ 1] + SBOX[T[ 0] % 512], 9);
162                 T[ 2] = rotateLeft(T[ 2] + SBOX[T[ 1] % 512], 9);
163                 T[ 3] = rotateLeft(T[ 3] + SBOX[T[ 2] % 512], 9);
164                 T[ 4] = rotateLeft(T[ 4] + SBOX[T[ 3] % 512], 9);
165                 T[ 5] = rotateLeft(T[ 5] + SBOX[T[ 4] % 512], 9);
166                 T[ 6] = rotateLeft(T[ 6] + SBOX[T[ 5] % 512], 9);
167                 T[ 7] = rotateLeft(T[ 7] + SBOX[T[ 6] % 512], 9);
168                 T[ 8] = rotateLeft(T[ 8] + SBOX[T[ 7] % 512], 9);
169                 T[ 9] = rotateLeft(T[ 9] + SBOX[T[ 8] % 512], 9);
170                 T[10] = rotateLeft(T[10] + SBOX[T[ 9] % 512], 9);
171                 T[11] = rotateLeft(T[11] + SBOX[T[10] % 512], 9);
172                 T[12] = rotateLeft(T[12] + SBOX[T[11] % 512], 9);
173                 T[13] = rotateLeft(T[13] + SBOX[T[12] % 512], 9);
174                 T[14] = rotateLeft(T[14] + SBOX[T[13] % 512], 9);
175             }
176             
177             m_EK[10*i + 0] = T[ 0];
178             m_EK[10*i + 1] = T[ 4];
179             m_EK[10*i + 2] = T[ 8];
180             m_EK[10*i + 3] = T[12];
181             m_EK[10*i + 4] = T[ 1];
182             m_EK[10*i + 5] = T[ 5];
183             m_EK[10*i + 6] = T[ 9];
184             m_EK[10*i + 7] = T[13];
185             m_EK[10*i + 8] = T[ 2];
186             m_EK[10*i + 9] = T[ 6];
187         }
188         
189         foreach (size_t i; iota(5, 37, 2))
190         {
191             const uint key3 = m_EK[i] & 3;
192             m_EK[i] |= 3;
193             m_EK[i] ^= rotateLeft(SBOX[265 + key3], m_EK[i-1] % 32) & gen_mask(m_EK[i]);
194         }
195     }
196 
197     SecureVector!uint m_EK;
198 }
199 
200 
201 private:
202 
203 /**
204 * The MARS sbox
205 */
206 __gshared immutable uint[512] SBOX = [
207     0x09D0C479, 0x28C8FFE0, 0x84AA6C39, 0x9DAD7287, 0x7DFF9BE3, 0xD4268361,
208     0xC96DA1D4, 0x7974CC93, 0x85D0582E, 0x2A4B5705, 0x1CA16A62, 0xC3BD279D,
209     0x0F1F25E5, 0x5160372F, 0xC695C1FB, 0x4D7FF1E4, 0xAE5F6BF4, 0x0D72EE46,
210     0xFF23DE8A, 0xB1CF8E83, 0xF14902E2, 0x3E981E42, 0x8BF53EB6, 0x7F4BF8AC,
211     0x83631F83, 0x25970205, 0x76AFE784, 0x3A7931D4, 0x4F846450, 0x5C64C3F6,
212     0x210A5F18, 0xC6986A26, 0x28F4E826, 0x3A60A81C, 0xD340A664, 0x7EA820C4,
213     0x526687C5, 0x7EDDD12B, 0x32A11D1D, 0x9C9EF086, 0x80F6E831, 0xAB6F04AD,
214     0x56FB9B53, 0x8B2E095C, 0xB68556AE, 0xD2250B0D, 0x294A7721, 0xE21FB253,
215     0xAE136749, 0xE82AAE86, 0x93365104, 0x99404A66, 0x78A784DC, 0xB69BA84B,
216     0x04046793, 0x23DB5C1E, 0x46CAE1D6, 0x2FE28134, 0x5A223942, 0x1863CD5B,
217     0xC190C6E3, 0x07DFB846, 0x6EB88816, 0x2D0DCC4A, 0xA4CCAE59, 0x3798670D,
218     0xCBFA9493, 0x4F481D45, 0xEAFC8CA8, 0xDB1129D6, 0xB0449E20, 0x0F5407FB,
219     0x6167D9A8, 0xD1F45763, 0x4DAA96C3, 0x3BEC5958, 0xABABA014, 0xB6CCD201,
220     0x38D6279F, 0x02682215, 0x8F376CD5, 0x092C237E, 0xBFC56593, 0x32889D2C,
221     0x854B3E95, 0x05BB9B43, 0x7DCD5DCD, 0xA02E926C, 0xFAE527E5, 0x36A1C330,
222     0x3412E1AE, 0xF257F462, 0x3C4F1D71, 0x30A2E809, 0x68E5F551, 0x9C61BA44,
223     0x5DED0AB8, 0x75CE09C8, 0x9654F93E, 0x698C0CCA, 0x243CB3E4, 0x2B062B97,
224     0x0F3B8D9E, 0x00E050DF, 0xFC5D6166, 0xE35F9288, 0xC079550D, 0x0591AEE8,
225     0x8E531E74, 0x75FE3578, 0x2F6D829A, 0xF60B21AE, 0x95E8EB8D, 0x6699486B,
226     0x901D7D9B, 0xFD6D6E31, 0x1090ACEF, 0xE0670DD8, 0xDAB2E692, 0xCD6D4365,
227     0xE5393514, 0x3AF345F0, 0x6241FC4D, 0x460DA3A3, 0x7BCF3729, 0x8BF1D1E0,
228     0x14AAC070, 0x1587ED55, 0x3AFD7D3E, 0xD2F29E01, 0x29A9D1F6, 0xEFB10C53,
229     0xCF3B870F, 0xB414935C, 0x664465ED, 0x024ACAC7, 0x59A744C1, 0x1D2936A7,
230     0xDC580AA6, 0xCF574CA8, 0x040A7A10, 0x6CD81807, 0x8A98BE4C, 0xACCEA063,
231     0xC33E92B5, 0xD1E0E03D, 0xB322517E, 0x2092BD13, 0x386B2C4A, 0x52E8DD58,
232     0x58656DFB, 0x50820371, 0x41811896, 0xE337EF7E, 0xD39FB119, 0xC97F0DF6,
233     0x68FEA01B, 0xA150A6E5, 0x55258962, 0xEB6FF41B, 0xD7C9CD7A, 0xA619CD9E,
234     0xBCF09576, 0x2672C073, 0xF003FB3C, 0x4AB7A50B, 0x1484126A, 0x487BA9B1,
235     0xA64FC9C6, 0xF6957D49, 0x38B06A75, 0xDD805FCD, 0x63D094CF, 0xF51C999E,
236     0x1AA4D343, 0xB8495294, 0xCE9F8E99, 0xBFFCD770, 0xC7C275CC, 0x378453A7,
237     0x7B21BE33, 0x397F41BD, 0x4E94D131, 0x92CC1F98, 0x5915EA51, 0x99F861B7,
238     0xC9980A88, 0x1D74FD5F, 0xB0A495F8, 0x614DEED0, 0xB5778EEA, 0x5941792D,
239     0xFA90C1F8, 0x33F824B4, 0xC4965372, 0x3FF6D550, 0x4CA5FEC0, 0x8630E964,
240     0x5B3FBBD6, 0x7DA26A48, 0xB203231A, 0x04297514, 0x2D639306, 0x2EB13149,
241     0x16A45272, 0x532459A0, 0x8E5F4872, 0xF966C7D9, 0x07128DC0, 0x0D44DB62,
242     0xAFC8D52D, 0x06316131, 0xD838E7CE, 0x1BC41D00, 0x3A2E8C0F, 0xEA83837E,
243     0xB984737D, 0x13BA4891, 0xC4F8B949, 0xA6D6ACB3, 0xA215CDCE, 0x8359838B,
244     0x6BD1AA31, 0xF579DD52, 0x21B93F93, 0xF5176781, 0x187DFDDE, 0xE94AEB76,
245     0x2B38FD54, 0x431DE1DA, 0xAB394825, 0x9AD3048F, 0xDFEA32AA, 0x659473E3,
246     0x623F7863, 0xF3346C59, 0xAB3AB685, 0x3346A90B, 0x6B56443E, 0xC6DE01F8,
247     0x8D421FC0, 0x9B0ED10C, 0x88F1A1E9, 0x54C1F029, 0x7DEAD57B, 0x8D7BA426,
248     0x4CF5178A, 0x551A7CCA, 0x1A9A5F08, 0xFCD651B9, 0x25605182, 0xE11FC6C3,
249     0xB6FD9676, 0x337B3027, 0xB7C8EB14, 0x9E5FD030, 0x6B57E354, 0xAD913CF7,
250     0x7E16688D, 0x58872A69, 0x2C2FC7DF, 0xE389CCC6, 0x30738DF1, 0x0824A734,
251     0xE1797A8B, 0xA4A8D57B, 0x5B5D193B, 0xC8A8309B, 0x73F9A978, 0x73398D32,
252     0x0F59573E, 0xE9DF2B03, 0xE8A5B6C8, 0x848D0704, 0x98DF93C2, 0x720A1DC3,
253     0x684F259A, 0x943BA848, 0xA6370152, 0x863B5EA3, 0xD17B978B, 0x6D9B58EF,
254     0x0A700DD4, 0xA73D36BF, 0x8E6A0829, 0x8695BC14, 0xE35B3447, 0x933AC568,
255     0x8894B022, 0x2F511C27, 0xDDFBCC3C, 0x006662B6, 0x117C83FE, 0x4E12B414,
256     0xC2BCA766, 0x3A2FEC10, 0xF4562420, 0x55792E2A, 0x46F5D857, 0xCEDA25CE,
257     0xC3601D3B, 0x6C00AB46, 0xEFAC9C28, 0xB3C35047, 0x611DFEE3, 0x257C3207,
258     0xFDD58482, 0x3B14D84F, 0x23BECB64, 0xA075F3A3, 0x088F8EAD, 0x07ADF158,
259     0x7796943C, 0xFACABF3D, 0xC09730CD, 0xF7679969, 0xDA44E9ED, 0x2C854C12,
260     0x35935FA3, 0x2F057D9F, 0x690624F8, 0x1CB0BAFD, 0x7B0DBDC6, 0x810F23BB,
261     0xFA929A1A, 0x6D969A17, 0x6742979B, 0x74AC7D05, 0x010E65C4, 0x86A3D963,
262     0xF907B5A0, 0xD0042BD3, 0x158D7D03, 0x287A8255, 0xBBA8366F, 0x096EDC33,
263     0x21916A7B, 0x77B56B86, 0x951622F9, 0xA6C5E650, 0x8CEA17D1, 0xCD8C62BC,
264     0xA3D63433, 0x358A68FD, 0x0F9B9D3C, 0xD6AA295B, 0xFE33384A, 0xC000738E,
265     0xCD67EB2F, 0xE2EB6DC2, 0x97338B02, 0x06C9F246, 0x419CF1AD, 0x2B83C045,
266     0x3723F18A, 0xCB5B3089, 0x160BEAD7, 0x5D494656, 0x35F8A74B, 0x1E4E6C9E,
267     0x000399BD, 0x67466880, 0xB4174831, 0xACF423B2, 0xCA815AB3, 0x5A6395E7,
268     0x302A67C5, 0x8BDB446B, 0x108F8FA4, 0x10223EDA, 0x92B8B48B, 0x7F38D0EE,
269     0xAB2701D4, 0x0262D415, 0xAF224A30, 0xB3D88ABA, 0xF8B2C3AF, 0xDAF7EF70,
270     0xCC97D3B7, 0xE9614B6C, 0x2BAEBFF4, 0x70F687CF, 0x386C9156, 0xCE092EE5,
271     0x01E87DA6, 0x6CE91E6A, 0xBB7BCC84, 0xC7922C20, 0x9D3B71FD, 0x060E41C6,
272     0xD7590F15, 0x4E03BB47, 0x183C198E, 0x63EEB240, 0x2DDBF49A, 0x6D5CBA54,
273     0x923750AF, 0xF9E14236, 0x7838162B, 0x59726C72, 0x81B66760, 0xBB2926C1,
274     0x48A0CE0D, 0xA6C0496D, 0xAD43507B, 0x718D496A, 0x9DF057AF, 0x44B1BDE6,
275     0x054356DC, 0xDE7CED35, 0xD51A138B, 0x62088CC9, 0x35830311, 0xC96EFCA2,
276     0x686F86EC, 0x8E77CB68, 0x63E1D6B8, 0xC80F9778, 0x79C491FD, 0x1B4C67F2,
277     0x72698D7D, 0x5E368C31, 0xF7D95E2E, 0xA1D3493F, 0xDCD9433E, 0x896F1552,
278     0x4BC4CA7A, 0xA6D1BAF4, 0xA5A96DCC, 0x0BEF8B46, 0xA169FDA7, 0x74DF40B7,
279     0x4E208804, 0x9A756607, 0x038E87C8, 0x20211E44, 0x8B7AD4BF, 0xC6403F35,
280     0x1848E36D, 0x80BDB038, 0x1E62891C, 0x643D2107, 0xBF04D6F8, 0x21092C8C,
281     0xF644F389, 0x0778404E, 0x7B78ADB8, 0xA2C52D53, 0x42157ABE, 0xA2253E2E,
282     0x7BF3F4AE, 0x80F594F9, 0x953194E7, 0x77EB92ED, 0xB3816930, 0xDA8D9336,
283     0xBF447469, 0xF26D9483, 0xEE6FAED5, 0x71371235, 0xDE425F73, 0xB4E59F43,
284     0x7DBE2D4E, 0x2D37B185, 0x49DC9A63, 0x98C39D98, 0x1301C9A2, 0x389B1BBF,
285     0x0C18588D, 0xA421C1BA, 0x7AA3865C, 0x71E08558, 0x3C5CFCAA, 0x7D239CA4,
286     0x0297D9DD, 0xD7DC2830, 0x4B37802B, 0x7428AB54, 0xAEEE0347, 0x4B3FBB85,
287     0x692F2F08, 0x134E578E, 0x36D9E0BF, 0xAE8B5FCF, 0xEDB93ECF, 0x2B27248E,
288     0x170EB1EF, 0x7DC57FD6, 0x1E760F16, 0xB1136601, 0x864E1B9B, 0xD7EA7319,
289     0x3AB871BD, 0xCFA4D76F, 0xE31BD782, 0x0DBEB469, 0xABB96061, 0x5370F85D,
290     0xFFB07E37, 0xDA30D0FB, 0xEBC977B6, 0x0B98B40F, 0x3A4D0FE6, 0xDF4FC26B,
291     0x159CF22A, 0xC298D6E2, 0x2B78EF6A, 0x61A94AC0, 0xAB561187, 0x14EEA0F0,
292     0xDF0D4164, 0x19AF70EE ];
293 
294 /*
295 * MARS Encryption Round
296 */
297 void encrypt_round(ref uint A, ref uint B, ref uint C, ref uint D,
298                    uint EK1, uint EK2) pure
299 {
300     const uint X = A + EK1;
301     A  = rotateLeft(A, 13);
302     uint Y = A * EK2;
303     uint Z = SBOX[X % 512];
304     
305     Y  = rotateLeft(Y, 5);
306     Z ^= Y;
307     C += rotateLeft(X, Y % 32);
308     Y  = rotateLeft(Y, 5);
309     Z ^= Y;
310     D ^= Y;
311     B += rotateLeft(Z, Y % 32);
312 }
313 
314 /*
315 * MARS Decryption Round
316 */
317 void decrypt_round(ref uint A, ref uint B, ref uint C, ref uint D,
318                    uint EK1, uint EK2) pure
319 {
320     uint Y = A * EK1;
321     A = rotateRight(A, 13);
322     const uint X = A + EK2;
323     uint Z = SBOX[X % 512];
324     
325     Y  = rotateLeft(Y, 5);
326     Z ^= Y;
327     C -= rotateLeft(X, Y % 32);
328     Y  = rotateLeft(Y, 5);
329     Z ^= Y;
330     D ^= Y;
331     B -= rotateLeft(Z, Y % 32);
332 }
333 
334 /*
335 * MARS Forward Mixing Operation
336 */
337 void forward_mix(ref uint A, ref uint B, ref uint C, ref uint D) pure
338 {
339     foreach (size_t j; 0 .. 2)
340     {
341         B ^= SBOX[get_byte(3, A)]; B += SBOX[get_byte(2, A) + 256];
342         C += SBOX[get_byte(1, A)]; D ^= SBOX[get_byte(0, A) + 256];
343         A = rotateRight(A, 24) + D;
344         
345         C ^= SBOX[get_byte(3, B)]; C += SBOX[get_byte(2, B) + 256];
346         D += SBOX[get_byte(1, B)]; A ^= SBOX[get_byte(0, B) + 256];
347         B = rotateRight(B, 24) + C;
348         
349         D ^= SBOX[get_byte(3, C)]; D += SBOX[get_byte(2, C) + 256];
350         A += SBOX[get_byte(1, C)]; B ^= SBOX[get_byte(0, C) + 256];
351         C = rotateRight(C, 24);
352         
353         A ^= SBOX[get_byte(3, D)]; A += SBOX[get_byte(2, D) + 256];
354         B += SBOX[get_byte(1, D)]; C ^= SBOX[get_byte(0, D) + 256];
355         D = rotateRight(D, 24);
356     }
357 }
358 
359 /*
360 * MARS Reverse Mixing Operation
361 */
362 void reverse_mix(ref uint A, ref uint B, ref uint C, ref uint D) pure
363 {
364     foreach (size_t j; 0 .. 2)
365     {
366         B ^= SBOX[get_byte(3, A) + 256]; C -= SBOX[get_byte(0, A)];
367         D -= SBOX[get_byte(1, A) + 256]; D ^= SBOX[get_byte(2, A)];
368         A = rotateLeft(A, 24);
369         
370         C ^= SBOX[get_byte(3, B) + 256]; D -= SBOX[get_byte(0, B)];
371         A -= SBOX[get_byte(1, B) + 256]; A ^= SBOX[get_byte(2, B)];
372         C -= (B = rotateLeft(B, 24));
373         
374         D ^= SBOX[get_byte(3, C) + 256]; A -= SBOX[get_byte(0, C)];
375         B -= SBOX[get_byte(1, C) + 256]; B ^= SBOX[get_byte(2, C)];
376         C = rotateLeft(C, 24);
377         D -= A;
378         
379         A ^= SBOX[get_byte(3, D) + 256]; B -= SBOX[get_byte(0, D)];
380         C -= SBOX[get_byte(1, D) + 256]; C ^= SBOX[get_byte(2, D)];
381         D = rotateLeft(D, 24);
382     }
383 }
384 
385 /*
386 * Generate a mask for runs of bits
387 */
388 uint gen_mask(uint input) pure
389 {
390     uint mask = 0;
391     
392     for (uint j = 2; j != 31; ++j)
393     {
394         const uint region = (input >> (j-1)) & 0x07;
395         
396         if (region == 0x00 || region == 0x07)
397         {
398             const uint low = (j < 9) ? 0 : (j - 9);
399             const uint high = (j < 23) ? j : 23;
400             
401             for (uint k = low; k != high; ++k)
402             {
403                 const uint value = (input >> k) & 0x3FF;
404                 
405                 if (value == 0 || value == 0x3FF)
406                 {
407                     mask |= 1 << j;
408                     break;
409                 }
410             }
411         }
412     }
413     
414     return mask;
415 }