1 /** 2 * GOST 34.11 3 * 4 * Copyright: 5 * (C) 2009 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.gost_3411; 12 13 import botan.constants; 14 static if (BOTAN_HAS_GOST_34_11): 15 16 import botan.hash.hash; 17 import botan.block.gost_28147; 18 import botan.utils.loadstor; 19 import botan.utils.rotate; 20 import botan.utils.xor_buf; 21 import botan.utils.types; 22 import botan.utils.get_byte; 23 24 /** 25 * GOST 34.11 26 */ 27 class GOST3411 : HashFunction 28 { 29 public: 30 override @property string name() const { return "GOST-R-34.11-94" ; } 31 override @property size_t outputLength() const { return 32; } 32 override @property size_t hashBlockSize() const { return 32; } 33 override HashFunction clone() const { return new GOST3411; } 34 35 override void clear() 36 { 37 m_cipher.clear(); 38 zeroise(m_sum); 39 zeroise(m_hash); 40 m_count = 0; 41 m_position = 0; 42 } 43 44 /** 45 * GOST 34.11 Constructor 46 */ 47 this() 48 { 49 m_cipher = new GOST_28147_89(scoped!GOST_28147_89_Params("R3411_CryptoPro").Scoped_payload); 50 m_buffer = SecureVector!ubyte(32); 51 m_sum = SecureVector!ubyte(32); 52 m_hash = SecureVector!ubyte(32); 53 m_count = 0; 54 m_position = 0; 55 } 56 57 protected: 58 /** 59 * The GOST 34.11 compression function 60 */ 61 void compress_n(const(ubyte)* input, size_t blocks) 62 { 63 foreach (size_t i; 0 .. blocks) 64 { 65 for (ushort j = 0, carry = 0; j != 32; ++j) 66 { 67 ushort s = cast(ushort)(m_sum[j] + input[32*i+j] + carry); 68 carry = get_byte(0, s); 69 m_sum[j] = get_byte(1, s); 70 } 71 72 ubyte[32] S; 73 74 ulong[4] U, V; 75 loadBigEndian(U.ptr, m_hash.ptr, 4); 76 loadBigEndian(V.ptr, input + 32*i, 4); 77 78 foreach (size_t j; 0 .. 4) 79 { 80 ubyte[32] key; 81 82 // P transformation 83 foreach (size_t k; 0 .. 4) 84 foreach (size_t l; 0 .. 8) 85 key[4*l+k] = get_byte(l, U[k]) ^ get_byte(l, V[k]); 86 87 m_cipher.setKey(key.ptr, 32); 88 m_cipher.encrypt(&m_hash[8*j], S.ptr + 8*j); 89 90 if (j == 3) 91 break; 92 93 // A(x) 94 ulong A_U = U[0]; 95 U[0] = U[1]; 96 U[1] = U[2]; 97 U[2] = U[3]; 98 U[3] = U[0] ^ A_U; 99 100 if (j == 1) // C_3 101 { 102 U[0] ^= 0x00FF00FF00FF00FF; 103 U[1] ^= 0xFF00FF00FF00FF00; 104 U[2] ^= 0x00FFFF00FF0000FF; 105 U[3] ^= 0xFF000000FFFF00FF; 106 } 107 108 // A(A(x)) 109 ulong AA_V_1 = V[0] ^ V[1]; 110 ulong AA_V_2 = V[1] ^ V[2]; 111 V[0] = V[2]; 112 V[1] = V[3]; 113 V[2] = AA_V_1; 114 V[3] = AA_V_2; 115 } 116 117 ubyte[32] S2; 118 119 // 12 rounds of psi 120 S2[ 0] = S[24]; 121 S2[ 1] = S[25]; 122 S2[ 2] = S[26]; 123 S2[ 3] = S[27]; 124 S2[ 4] = S[28]; 125 S2[ 5] = S[29]; 126 S2[ 6] = S[30]; 127 S2[ 7] = S[31]; 128 S2[ 8] = S[ 0] ^ S[ 2] ^ S[ 4] ^ S[ 6] ^ S[24] ^ S[30]; 129 S2[ 9] = S[ 1] ^ S[ 3] ^ S[ 5] ^ S[ 7] ^ S[25] ^ S[31]; 130 S2[10] = S[ 0] ^ S[ 8] ^ S[24] ^ S[26] ^ S[30]; 131 S2[11] = S[ 1] ^ S[ 9] ^ S[25] ^ S[27] ^ S[31]; 132 S2[12] = S[ 0] ^ S[ 4] ^ S[ 6] ^ S[10] ^ S[24] ^ S[26] ^ S[28] ^ S[30]; 133 S2[13] = S[ 1] ^ S[ 5] ^ S[ 7] ^ S[11] ^ S[25] ^ S[27] ^ S[29] ^ S[31]; 134 S2[14] = S[ 0] ^ S[ 4] ^ S[ 8] ^ S[12] ^ S[24] ^ S[26] ^ S[28]; 135 S2[15] = S[ 1] ^ S[ 5] ^ S[ 9] ^ S[13] ^ S[25] ^ S[27] ^ S[29]; 136 S2[16] = S[ 2] ^ S[ 6] ^ S[10] ^ S[14] ^ S[26] ^ S[28] ^ S[30]; 137 S2[17] = S[ 3] ^ S[ 7] ^ S[11] ^ S[15] ^ S[27] ^ S[29] ^ S[31]; 138 S2[18] = S[ 0] ^ S[ 2] ^ S[ 6] ^ S[ 8] ^ S[12] ^ S[16] ^ S[24] ^ S[28]; 139 S2[19] = S[ 1] ^ S[ 3] ^ S[ 7] ^ S[ 9] ^ S[13] ^ S[17] ^ S[25] ^ S[29]; 140 S2[20] = S[ 2] ^ S[ 4] ^ S[ 8] ^ S[10] ^ S[14] ^ S[18] ^ S[26] ^ S[30]; 141 S2[21] = S[ 3] ^ S[ 5] ^ S[ 9] ^ S[11] ^ S[15] ^ S[19] ^ S[27] ^ S[31]; 142 S2[22] = S[ 0] ^ S[ 2] ^ S[10] ^ S[12] ^ S[16] ^ S[20] ^ S[24] ^ S[28] ^ S[30]; 143 S2[23] = S[ 1] ^ S[ 3] ^ S[11] ^ S[13] ^ S[17] ^ S[21] ^ S[25] ^ S[29] ^ S[31]; 144 S2[24] = S[ 0] ^ S[ 6] ^ S[12] ^ S[14] ^ S[18] ^ S[22] ^ S[24] ^ S[26]; 145 S2[25] = S[ 1] ^ S[ 7] ^ S[13] ^ S[15] ^ S[19] ^ S[23] ^ S[25] ^ S[27]; 146 S2[26] = S[ 2] ^ S[ 8] ^ S[14] ^ S[16] ^ S[20] ^ S[24] ^ S[26] ^ S[28]; 147 S2[27] = S[ 3] ^ S[ 9] ^ S[15] ^ S[17] ^ S[21] ^ S[25] ^ S[27] ^ S[29]; 148 S2[28] = S[ 4] ^ S[10] ^ S[16] ^ S[18] ^ S[22] ^ S[26] ^ S[28] ^ S[30]; 149 S2[29] = S[ 5] ^ S[11] ^ S[17] ^ S[19] ^ S[23] ^ S[27] ^ S[29] ^ S[31]; 150 S2[30] = S[ 0] ^ S[ 2] ^ S[ 4] ^ S[12] ^ S[18] ^ S[20] ^ S[28]; 151 S2[31] = S[ 1] ^ S[ 3] ^ S[ 5] ^ S[13] ^ S[19] ^ S[21] ^ S[29]; 152 153 xorBuf(S.ptr, S2.ptr, input + 32*i, 32); 154 155 S2[0] = S[0] ^ S[2] ^ S[4] ^ S[6] ^ S[24] ^ S[30]; 156 S2[1] = S[1] ^ S[3] ^ S[5] ^ S[7] ^ S[25] ^ S[31]; 157 158 copyMem(S.ptr, S.ptr+2, 30); 159 S[30] = S2[0]; 160 S[31] = S2[1]; 161 162 xorBuf(S.ptr, m_hash.ptr, 32); 163 164 // 61 rounds of psi 165 S2[ 0] = S[ 2] ^ S[ 6] ^ S[14] ^ S[20] ^ S[22] ^ S[26] ^ S[28] ^ S[30]; 166 S2[ 1] = S[ 3] ^ S[ 7] ^ S[15] ^ S[21] ^ S[23] ^ S[27] ^ S[29] ^ S[31]; 167 S2[ 2] = S[ 0] ^ S[ 2] ^ S[ 6] ^ S[ 8] ^ S[16] ^ S[22] ^ S[28]; 168 S2[ 3] = S[ 1] ^ S[ 3] ^ S[ 7] ^ S[ 9] ^ S[17] ^ S[23] ^ S[29]; 169 S2[ 4] = S[ 2] ^ S[ 4] ^ S[ 8] ^ S[10] ^ S[18] ^ S[24] ^ S[30]; 170 S2[ 5] = S[ 3] ^ S[ 5] ^ S[ 9] ^ S[11] ^ S[19] ^ S[25] ^ S[31]; 171 S2[ 6] = S[ 0] ^ S[ 2] ^ S[10] ^ S[12] ^ S[20] ^ S[24] ^ S[26] ^ S[30]; 172 S2[ 7] = S[ 1] ^ S[ 3] ^ S[11] ^ S[13] ^ S[21] ^ S[25] ^ S[27] ^ S[31]; 173 S2[ 8] = S[ 0] ^ S[ 6] ^ S[12] ^ S[14] ^ S[22] ^ S[24] ^ S[26] ^ S[28] ^ S[30]; 174 S2[ 9] = S[ 1] ^ S[ 7] ^ S[13] ^ S[15] ^ S[23] ^ S[25] ^ S[27] ^ S[29] ^ S[31]; 175 S2[10] = S[ 0] ^ S[ 4] ^ S[ 6] ^ S[ 8] ^ S[14] ^ S[16] ^ S[26] ^ S[28]; 176 S2[11] = S[ 1] ^ S[ 5] ^ S[ 7] ^ S[ 9] ^ S[15] ^ S[17] ^ S[27] ^ S[29]; 177 S2[12] = S[ 2] ^ S[ 6] ^ S[ 8] ^ S[10] ^ S[16] ^ S[18] ^ S[28] ^ S[30]; 178 S2[13] = S[ 3] ^ S[ 7] ^ S[ 9] ^ S[11] ^ S[17] ^ S[19] ^ S[29] ^ S[31]; 179 S2[14] = S[ 0] ^ S[ 2] ^ S[ 6] ^ S[ 8] ^ S[10] ^ S[12] ^ S[18] ^ S[20] ^ S[24]; 180 S2[15] = S[ 1] ^ S[ 3] ^ S[ 7] ^ S[ 9] ^ S[11] ^ S[13] ^ S[19] ^ S[21] ^ S[25]; 181 S2[16] = S[ 2] ^ S[ 4] ^ S[ 8] ^ S[10] ^ S[12] ^ S[14] ^ S[20] ^ S[22] ^ S[26]; 182 S2[17] = S[ 3] ^ S[ 5] ^ S[ 9] ^ S[11] ^ S[13] ^ S[15] ^ S[21] ^ S[23] ^ S[27]; 183 S2[18] = S[ 4] ^ S[ 6] ^ S[10] ^ S[12] ^ S[14] ^ S[16] ^ S[22] ^ S[24] ^ S[28]; 184 S2[19] = S[ 5] ^ S[ 7] ^ S[11] ^ S[13] ^ S[15] ^ S[17] ^ S[23] ^ S[25] ^ S[29]; 185 S2[20] = S[ 6] ^ S[ 8] ^ S[12] ^ S[14] ^ S[16] ^ S[18] ^ S[24] ^ S[26] ^ S[30]; 186 S2[21] = S[ 7] ^ S[ 9] ^ S[13] ^ S[15] ^ S[17] ^ S[19] ^ S[25] ^ S[27] ^ S[31]; 187 S2[22] = S[ 0] ^ S[ 2] ^ S[ 4] ^ S[ 6] ^ S[ 8] ^ S[10] ^ S[14] ^ S[16] ^ 188 S[18] ^ S[20] ^ S[24] ^ S[26] ^ S[28] ^ S[30]; 189 S2[23] = S[ 1] ^ S[ 3] ^ S[ 5] ^ S[ 7] ^ S[ 9] ^ S[11] ^ S[15] ^ S[17] ^ 190 S[19] ^ S[21] ^ S[25] ^ S[27] ^ S[29] ^ S[31]; 191 S2[24] = S[ 0] ^ S[ 8] ^ S[10] ^ S[12] ^ S[16] ^ S[18] ^ S[20] ^ S[22] ^ 192 S[24] ^ S[26] ^ S[28]; 193 S2[25] = S[ 1] ^ S[ 9] ^ S[11] ^ S[13] ^ S[17] ^ S[19] ^ S[21] ^ S[23] ^ 194 S[25] ^ S[27] ^ S[29]; 195 S2[26] = S[ 2] ^ S[10] ^ S[12] ^ S[14] ^ S[18] ^ S[20] ^ S[22] ^ S[24] ^ 196 S[26] ^ S[28] ^ S[30]; 197 S2[27] = S[ 3] ^ S[11] ^ S[13] ^ S[15] ^ S[19] ^ S[21] ^ S[23] ^ S[25] ^ 198 S[27] ^ S[29] ^ S[31]; 199 S2[28] = S[ 0] ^ S[ 2] ^ S[ 6] ^ S[12] ^ S[14] ^ S[16] ^ S[20] ^ S[22] ^ S[26] ^ S[28]; 200 S2[29] = S[ 1] ^ S[ 3] ^ S[ 7] ^ S[13] ^ S[15] ^ S[17] ^ S[21] ^ S[23] ^ S[27] ^ S[29]; 201 S2[30] = S[ 2] ^ S[ 4] ^ S[ 8] ^ S[14] ^ S[16] ^ S[18] ^ S[22] ^ S[24] ^ S[28] ^ S[30]; 202 S2[31] = S[ 3] ^ S[ 5] ^ S[ 9] ^ S[15] ^ S[17] ^ S[19] ^ S[23] ^ S[25] ^ S[29] ^ S[31]; 203 204 copyMem(m_hash.ptr, S2.ptr, 32); 205 } 206 } 207 208 /** 209 * Hash additional inputs 210 */ 211 override void addData(const(ubyte)* input, size_t length) 212 { 213 m_count += length; 214 215 if (m_position) 216 { 217 bufferInsert(m_buffer, m_position, input, length); 218 219 if (m_position + length >= hashBlockSize) 220 { 221 compress_n(m_buffer.ptr, 1); 222 input += (hashBlockSize - m_position); 223 length -= (hashBlockSize - m_position); 224 m_position = 0; 225 } 226 } 227 228 const size_t full_blocks = length / hashBlockSize; 229 const size_t remaining = length % hashBlockSize; 230 231 if (full_blocks) 232 compress_n(input, full_blocks); 233 234 bufferInsert(m_buffer, m_position, input + full_blocks * hashBlockSize, remaining); 235 m_position += remaining; 236 } 237 238 /** 239 * Produce the final GOST 34.11 output 240 */ 241 override void finalResult(ubyte* output) 242 { 243 if (m_position) 244 { 245 clearMem(m_buffer.ptr + m_position, m_buffer.length - m_position); 246 compress_n(m_buffer.ptr, 1); 247 } 248 249 SecureVector!ubyte length_buf = SecureVector!ubyte(32); 250 const ulong bit_count = m_count * 8; 251 storeLittleEndian(bit_count, length_buf.ptr); 252 253 SecureVector!ubyte sum_buf = m_sum.dup; 254 255 compress_n(length_buf.ptr, 1); 256 compress_n(sum_buf.ptr, 1); 257 258 copyMem(output, m_hash.ptr, 32); 259 clear(); 260 } 261 262 Unique!GOST_28147_89 m_cipher; 263 SecureVector!ubyte m_buffer, m_sum, m_hash; 264 size_t m_position; 265 ulong m_count; 266 }