1 /**
2 * Keccak
3 * 
4 * Copyright:
5 * (C) 2010 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.hash.keccak;
12 
13 import botan.constants;
14 static if (BOTAN_HAS_KECCAK):
15 
16 import botan.hash.hash;
17 import memutils.vector;
18 import botan.utils.loadstor;
19 import botan.utils.parsing;
20 import botan.utils.exceptn;
21 import botan.utils.rotate;
22 import botan.utils.xor_buf;
23 import botan.utils.get_byte;
24 import botan.utils.types;
25 import std.conv : to;
26 import std.algorithm : min, max;
27 
28 /**
29 * Keccak[1600], a SHA-3 candidate
30 */
31 final class Keccak1600 : HashFunction
32 {
33 public:
34 
35     /**
36     * Params:
37     *  output_bits = the size of the hash output; must be one of
38     *                          224, 256, 384, or 512
39     */
40     this(size_t output_bits = 512) 
41     {
42         m_output_bits = output_bits;
43         m_bitrate = 1600 - 2*output_bits;
44         m_S = 25;
45         m_S_pos = 0;
46         
47         // We only support the parameters for the SHA-3 proposal
48         
49         if (output_bits != 224 && output_bits != 256 &&
50             output_bits != 384 && output_bits != 512)
51             throw new InvalidArgument("Keccak_1600: Invalid output length " ~ to!string(output_bits));
52     }
53 
54     override @property size_t hashBlockSize() const { return m_bitrate / 8; }
55     override @property size_t outputLength() const { return m_output_bits / 8; }
56 
57     override HashFunction clone() const
58     {
59         return new Keccak1600(m_output_bits);
60     }
61 
62     override @property string name() const
63     {
64         return "Keccak-1600(" ~ to!string(m_output_bits) ~ ")";
65     }
66 
67     override void clear()
68     {
69         zeroise(m_S);
70         m_S_pos = 0;
71     }
72 
73 protected:
74     override void addData(const(ubyte)* input, size_t length)
75     {
76         if (length == 0)
77             return;
78         
79         while (length)
80         {
81             size_t to_take = min(length, m_bitrate / 8 - m_S_pos);
82             
83             length -= to_take;
84             
85             while (to_take && m_S_pos % 8)
86             {
87                 m_S[m_S_pos / 8] ^= cast(ulong)(input[0]) << (8 * (m_S_pos % 8));
88                 
89                 ++m_S_pos;
90                 ++input;
91                 --to_take;
92             }
93             
94             while (to_take && to_take % 8 == 0)
95             {
96                 m_S[m_S_pos / 8] ^= loadLittleEndian!ulong(input, 0);
97                 m_S_pos += 8;
98                 input += 8;
99                 to_take -= 8;
100             }
101             
102             while (to_take)
103             {
104                 m_S[m_S_pos / 8] ^= cast(ulong)(input[0]) << (8 * (m_S_pos % 8));
105                 
106                 ++m_S_pos;
107                 ++input;
108                 --to_take;
109             }
110             
111             if (m_S_pos == m_bitrate / 8)
112             {
113                 keccak_f_1600(*cast(ulong[25]*) m_S.ptr);
114                 m_S_pos = 0;
115             }
116         }
117     }
118 
119     override void finalResult(ubyte* output)
120     {
121         Vector!ubyte padding = Vector!ubyte(m_bitrate / 8 - m_S_pos);
122         
123         padding[0] = 0x01;
124         padding[padding.length-1] |= 0x80;
125         
126         addData(padding.ptr, padding.length);
127         
128         /*
129         * We never have to run the permutation again because we only support
130         * limited output lengths
131         */
132         foreach (size_t i; 0 .. m_output_bits/8)
133             output[i] = get_byte(7 - (i % 8), m_S[i/8]);
134         
135         clear();
136     }
137 
138     size_t m_output_bits, m_bitrate;
139     SecureVector!ulong m_S;
140     size_t m_S_pos;
141 }
142 
143 
144 
145 
146 void keccak_f_1600(ref ulong[25] A) pure
147 {
148     __gshared immutable ulong[24] RC = [
149         0x0000000000000001, 0x0000000000008082, 0x800000000000808A,
150         0x8000000080008000, 0x000000000000808B, 0x0000000080000001,
151         0x8000000080008081, 0x8000000000008009, 0x000000000000008A,
152         0x0000000000000088, 0x0000000080008009, 0x000000008000000A,
153         0x000000008000808B, 0x800000000000008B, 0x8000000000008089,
154         0x8000000000008003, 0x8000000000008002, 0x8000000000000080,
155         0x000000000000800A, 0x800000008000000A, 0x8000000080008081,
156         0x8000000000008080, 0x0000000080000001, 0x8000000080008008
157     ];
158     
159     foreach (size_t i; 0 .. 24)
160     {
161         const ulong C0 = A[0] ^ A[5] ^ A[10] ^ A[15] ^ A[20];
162         const ulong C1 = A[1] ^ A[6] ^ A[11] ^ A[16] ^ A[21];
163         const ulong C2 = A[2] ^ A[7] ^ A[12] ^ A[17] ^ A[22];
164         const ulong C3 = A[3] ^ A[8] ^ A[13] ^ A[18] ^ A[23];
165         const ulong C4 = A[4] ^ A[9] ^ A[14] ^ A[19] ^ A[24];
166         
167         const ulong D0 = rotateLeft(C0, 1) ^ C3;
168         const ulong D1 = rotateLeft(C1, 1) ^ C4;
169         const ulong D2 = rotateLeft(C2, 1) ^ C0;
170         const ulong D3 = rotateLeft(C3, 1) ^ C1;
171         const ulong D4 = rotateLeft(C4, 1) ^ C2;
172         
173         const ulong B00 = A[ 0] ^ D1;
174         const ulong B01 = rotateLeft(A[ 6] ^ D2, 44);
175         const ulong B02 = rotateLeft(A[12] ^ D3, 43);
176         const ulong B03 = rotateLeft(A[18] ^ D4, 21);
177         const ulong B04 = rotateLeft(A[24] ^ D0, 14);
178         const ulong B05 = rotateLeft(A[ 3] ^ D4, 28);
179         const ulong B06 = rotateLeft(A[ 9] ^ D0, 20);
180         const ulong B07 = rotateLeft(A[10] ^ D1, 3);
181         const ulong B08 = rotateLeft(A[16] ^ D2, 45);
182         const ulong B09 = rotateLeft(A[22] ^ D3, 61);
183         const ulong B10 = rotateLeft(A[ 1] ^ D2, 1);
184         const ulong B11 = rotateLeft(A[ 7] ^ D3, 6);
185         const ulong B12 = rotateLeft(A[13] ^ D4, 25);
186         const ulong B13 = rotateLeft(A[19] ^ D0, 8);
187         const ulong B14 = rotateLeft(A[20] ^ D1, 18);
188         const ulong B15 = rotateLeft(A[ 4] ^ D0, 27);
189         const ulong B16 = rotateLeft(A[ 5] ^ D1, 36);
190         const ulong B17 = rotateLeft(A[11] ^ D2, 10);
191         const ulong B18 = rotateLeft(A[17] ^ D3, 15);
192         const ulong B19 = rotateLeft(A[23] ^ D4, 56);
193         const ulong B20 = rotateLeft(A[ 2] ^ D3, 62);
194         const ulong B21 = rotateLeft(A[ 8] ^ D4, 55);
195         const ulong B22 = rotateLeft(A[14] ^ D0, 39);
196         const ulong B23 = rotateLeft(A[15] ^ D1, 41);
197         const ulong B24 = rotateLeft(A[21] ^ D2, 2);
198         
199         A[ 0] = B00 ^ (~B01 & B02);
200         A[ 1] = B01 ^ (~B02 & B03);
201         A[ 2] = B02 ^ (~B03 & B04);
202         A[ 3] = B03 ^ (~B04 & B00);
203         A[ 4] = B04 ^ (~B00 & B01);
204         A[ 5] = B05 ^ (~B06 & B07);
205         A[ 6] = B06 ^ (~B07 & B08);
206         A[ 7] = B07 ^ (~B08 & B09);
207         A[ 8] = B08 ^ (~B09 & B05);
208         A[ 9] = B09 ^ (~B05 & B06);
209         A[10] = B10 ^ (~B11 & B12);
210         A[11] = B11 ^ (~B12 & B13);
211         A[12] = B12 ^ (~B13 & B14);
212         A[13] = B13 ^ (~B14 & B10);
213         A[14] = B14 ^ (~B10 & B11);
214         A[15] = B15 ^ (~B16 & B17);
215         A[16] = B16 ^ (~B17 & B18);
216         A[17] = B17 ^ (~B18 & B19);
217         A[18] = B18 ^ (~B19 & B15);
218         A[19] = B19 ^ (~B15 & B16);
219         A[20] = B20 ^ (~B21 & B22);
220         A[21] = B21 ^ (~B22 & B23);
221         A[22] = B22 ^ (~B23 & B24);
222         A[23] = B23 ^ (~B24 & B20);
223         A[24] = B24 ^ (~B20 & B21);
224         
225         A[0] ^= RC[i];
226     }
227 }