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 }