|
/*
|
|
Copyright (c) 2003, Dominik Reichl <dominik.reichl@t-online.de>
|
|
All rights reserved.
|
|
|
|
LICENSE TERMS
|
|
|
|
Redistribution and use in source and binary forms, with or without
|
|
modification, are permitted provided that the following conditions are met:
|
|
|
|
* Redistributions of source code must retain the above copyright notice, this
|
|
list of conditions and the following disclaimer.
|
|
* Redistributions in binary form must reproduce the above copyright notice,
|
|
this list of conditions and the following disclaimer in the documentation
|
|
and/or other materials provided with the distribution.
|
|
* Neither the name of ReichlSoft nor the names of its contributors may be used
|
|
to endorse or promote products derived from this software without specific
|
|
prior written permission.
|
|
|
|
DISCLAIMER
|
|
|
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
|
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#include "gosthash.h"
|
|
|
|
static bool g_bTablesInitialized = false;
|
|
|
|
static UWORD32 g_pSBox1[256];
|
|
static UWORD32 g_pSBox2[256];
|
|
static UWORD32 g_pSBox3[256];
|
|
static UWORD32 g_pSBox4[256];
|
|
|
|
#define GOST_ENCRYPT_ROUND(k1, k2) \
|
|
t = (k1) + r; \
|
|
l ^= g_pSBox1[t & 0xFF] ^ g_pSBox2[(t >> 8) & 0xFF] ^ \
|
|
g_pSBox3[(t >> 16) & 0xFF] ^ g_pSBox4[t >> 24]; \
|
|
t = (k2) + l; \
|
|
r ^= g_pSBox1[t & 0xFF] ^ g_pSBox2[(t >> 8) & 0xFF] ^ \
|
|
g_pSBox3[(t >> 16) & 0xFF] ^ g_pSBox4[t >> 24];
|
|
|
|
#define GOST_ENCRYPT(k0) \
|
|
GOST_ENCRYPT_ROUND(k0[0], k0[1]) \
|
|
GOST_ENCRYPT_ROUND(k0[2], k0[3]) \
|
|
GOST_ENCRYPT_ROUND(k0[4], k0[5]) \
|
|
GOST_ENCRYPT_ROUND(k0[6], k0[7]) \
|
|
GOST_ENCRYPT_ROUND(k0[0], k0[1]) \
|
|
GOST_ENCRYPT_ROUND(k0[2], k0[3]) \
|
|
GOST_ENCRYPT_ROUND(k0[4], k0[5]) \
|
|
GOST_ENCRYPT_ROUND(k0[6], k0[7]) \
|
|
GOST_ENCRYPT_ROUND(k0[0], k0[1]) \
|
|
GOST_ENCRYPT_ROUND(k0[2], k0[3]) \
|
|
GOST_ENCRYPT_ROUND(k0[4], k0[5]) \
|
|
GOST_ENCRYPT_ROUND(k0[6], k0[7]) \
|
|
GOST_ENCRYPT_ROUND(k0[7], k0[6]) \
|
|
GOST_ENCRYPT_ROUND(k0[5], k0[4]) \
|
|
GOST_ENCRYPT_ROUND(k0[3], k0[2]) \
|
|
GOST_ENCRYPT_ROUND(k0[1], k0[0]) \
|
|
t = r; \
|
|
r = l; \
|
|
l = t;
|
|
|
|
void _gostMakeTables()
|
|
{
|
|
INTPREF a, b, i;
|
|
UWORD32 ax, bx, cx, dx;
|
|
|
|
const UWORD32 uStdSBox[8][16] = // 4-bit SBox
|
|
{
|
|
{ 4, 10, 9, 2, 13, 8, 0, 14, 6, 11, 1, 12, 7, 15, 5, 3 },
|
|
{ 14, 11, 4, 12, 6, 13, 15, 10, 2, 3, 8, 1, 0, 7, 5, 9 },
|
|
{ 5, 8, 1, 13, 10, 3, 4, 2, 14, 15, 12, 7, 6, 0, 9, 11 },
|
|
{ 7, 13, 10, 1, 0, 8, 9, 15, 14, 4, 6, 12, 11, 2, 5, 3 },
|
|
{ 6, 12, 7, 1, 5, 15, 13, 8, 4, 10, 9, 14, 0, 3, 11, 2 },
|
|
{ 4, 11, 10, 0, 7, 2, 1, 13, 3, 6, 8, 5, 9, 12, 15, 14 },
|
|
{ 13, 11, 4, 1, 3, 15, 5, 9, 0, 10, 14, 7, 6, 8, 2, 12 },
|
|
{ 1, 15, 13, 0, 5, 7, 10, 4, 9, 2, 3, 14, 6, 11, 8, 12 }
|
|
};
|
|
|
|
i = 0;
|
|
for(a = 0; a < 16; a++)
|
|
{
|
|
ax = uStdSBox[1][a] << 15;
|
|
bx = uStdSBox[3][a] << 23;
|
|
cx = uStdSBox[5][a];
|
|
cx = (cx >> 1) | (cx << 31);
|
|
dx = uStdSBox[7][a] << 7;
|
|
|
|
for(b = 0; b < 16; b++)
|
|
{
|
|
g_pSBox1[i ] = ax | (uStdSBox[0][b] << 11);
|
|
g_pSBox2[i ] = bx | (uStdSBox[2][b] << 19);
|
|
g_pSBox3[i ] = cx | (uStdSBox[4][b] << 27);
|
|
g_pSBox4[i++] = dx | (uStdSBox[6][b] << 3);
|
|
}
|
|
}
|
|
}
|
|
|
|
CGOSTHash::CGOSTHash()
|
|
{
|
|
}
|
|
|
|
CGOSTHash::~CGOSTHash()
|
|
{
|
|
}
|
|
|
|
void CGOSTHash::Init(RH_DATA_INFO *pInfo)
|
|
{
|
|
if(g_bTablesInitialized == false)
|
|
{
|
|
_gostMakeTables();
|
|
g_bTablesInitialized = true;
|
|
}
|
|
|
|
memset(m_sum, 0, 32);
|
|
memset(m_hash, 0, 32);
|
|
memset(m_len, 0, 32);
|
|
memset(m_partial, 0, 32);
|
|
m_partial_bytes = 0;
|
|
}
|
|
|
|
void CGOSTHash::_Compress(UWORD32 *h, UWORD32 *m)
|
|
{
|
|
INTPREF i;
|
|
UWORD32 l, r, t, k0[8], u[8], v[8], w[8], s[8];
|
|
|
|
memcpy(u, h, 32);
|
|
memcpy(v, m, 32);
|
|
|
|
for(i = 0; i < 8; i += 2)
|
|
{
|
|
w[0] = u[0] ^ v[0]; // w = u XOR v
|
|
w[1] = u[1] ^ v[1];
|
|
w[2] = u[2] ^ v[2];
|
|
w[3] = u[3] ^ v[3];
|
|
w[4] = u[4] ^ v[4];
|
|
w[5] = u[5] ^ v[5];
|
|
w[6] = u[6] ^ v[6];
|
|
w[7] = u[7] ^ v[7];
|
|
|
|
// P transformation
|
|
|
|
k0[0] = (w[0] & 0x000000FF) | ((w[2] & 0x000000FF) << 8) |
|
|
((w[4] & 0x000000FF) << 16) | ((w[6] & 0x000000FF) << 24);
|
|
k0[1] = ((w[0] & 0x0000FF00) >> 8) | (w[2] & 0x0000FF00) |
|
|
((w[4] & 0x0000FF00) << 8) | ((w[6] & 0x0000FF00) << 16);
|
|
k0[2] = ((w[0] & 0x00FF0000) >> 16) | ((w[2] & 0x00FF0000) >> 8) |
|
|
(w[4] & 0x00FF0000) | ((w[6] & 0x00FF0000) << 8);
|
|
k0[3] = ((w[0] & 0xFF000000) >> 24) | ((w[2] & 0xFF000000) >> 16) |
|
|
((w[4] & 0xFF000000) >> 8) | (w[6] & 0xFF000000);
|
|
k0[4] = (w[1] & 0x000000FF) | ((w[3] & 0x000000FF) << 8) |
|
|
((w[5] & 0x000000FF) << 16) | ((w[7] & 0x000000FF) << 24);
|
|
k0[5] = ((w[1] & 0x0000FF00) >> 8) | (w[3] & 0x0000FF00) |
|
|
((w[5] & 0x0000FF00) << 8) | ((w[7] & 0x0000FF00) << 16);
|
|
k0[6] = ((w[1] & 0x00FF0000) >> 16) | ((w[3] & 0x00FF0000) >> 8) |
|
|
(w[5] & 0x00FF0000) | ((w[7] & 0x00FF0000) << 8);
|
|
k0[7] = ((w[1] & 0xFF000000) >> 24) | ((w[3] & 0xFF000000) >> 16) |
|
|
((w[5] & 0xFF000000) >> 8) | (w[7] & 0xFF000000);
|
|
|
|
r = h[i];
|
|
l = h[i + 1];
|
|
GOST_ENCRYPT(k0);
|
|
|
|
s[i] = r;
|
|
s[i + 1] = l;
|
|
|
|
if(i == 6) break;
|
|
|
|
l = u[0] ^ u[2]; // U = A(U)
|
|
r = u[1] ^ u[3];
|
|
u[0] = u[2];
|
|
u[1] = u[3];
|
|
u[2] = u[4];
|
|
u[3] = u[5];
|
|
u[4] = u[6];
|
|
u[5] = u[7];
|
|
u[6] = l;
|
|
u[7] = r;
|
|
|
|
if(i == 2) // Constant C_3
|
|
{
|
|
u[0] ^= 0xFF00FF00;
|
|
u[1] ^= 0xFF00FF00;
|
|
u[2] ^= 0x00FF00FF;
|
|
u[3] ^= 0x00FF00FF;
|
|
u[4] ^= 0x00FFFF00;
|
|
u[5] ^= 0xFF0000FF;
|
|
u[6] ^= 0x000000FF;
|
|
u[7] ^= 0xFF00FFFF;
|
|
}
|
|
|
|
l = v[0]; // V = A(A(V))
|
|
r = v[2];
|
|
v[0] = v[4];
|
|
v[2] = v[6];
|
|
v[4] = l ^ r;
|
|
v[6] = v[0] ^ r;
|
|
l = v[1];
|
|
r = v[3];
|
|
v[1] = v[5];
|
|
v[3] = v[7];
|
|
v[5] = l ^ r;
|
|
v[7] = v[1] ^ r;
|
|
}
|
|
|
|
// 12 rounds of the LFSR (computed from a product matrix) and XOR in M
|
|
u[0] = m[0] ^ s[6];
|
|
u[1] = m[1] ^ s[7];
|
|
u[2] = m[2] ^ (s[0] << 16) ^ (s[0] >> 16) ^ (s[0] & 0xFFFF) ^
|
|
(s[1] & 0xFFFF) ^ (s[1] >> 16) ^ (s[2] << 16) ^ s[6] ^ (s[6] << 16) ^
|
|
(s[7] & 0xFFFF0000) ^ (s[7] >> 16);
|
|
u[3] = m[3] ^ (s[0] & 0xFFFF) ^ (s[0] << 16) ^ (s[1] & 0xFFFF) ^
|
|
(s[1] << 16) ^ (s[1] >> 16) ^ (s[2] << 16) ^ (s[2] >> 16) ^
|
|
(s[3] << 16) ^ s[6] ^ (s[6] << 16) ^ (s[6] >> 16) ^ (s[7] & 0xFFFF) ^
|
|
(s[7] << 16) ^ (s[7] >> 16);
|
|
u[4] = m[4] ^
|
|
(s[0] & 0xFFFF0000) ^ (s[0] << 16) ^ (s[0] >> 16) ^
|
|
(s[1] & 0xFFFF0000) ^ (s[1] >> 16) ^ (s[2] << 16) ^ (s[2] >> 16) ^
|
|
(s[3] << 16) ^ (s[3] >> 16) ^ (s[4] << 16) ^ (s[6] << 16) ^
|
|
(s[6] >> 16) ^(s[7] & 0xFFFF) ^ (s[7] << 16) ^ (s[7] >> 16);
|
|
u[5] = m[5] ^ (s[0] << 16) ^ (s[0] >> 16) ^ (s[0] & 0xFFFF0000) ^
|
|
(s[1] & 0xFFFF) ^ s[2] ^ (s[2] >> 16) ^ (s[3] << 16) ^ (s[3] >> 16) ^
|
|
(s[4] << 16) ^ (s[4] >> 16) ^ (s[5] << 16) ^ (s[6] << 16) ^
|
|
(s[6] >> 16) ^ (s[7] & 0xFFFF0000) ^ (s[7] << 16) ^ (s[7] >> 16);
|
|
u[6] = m[6] ^ s[0] ^ (s[1] >> 16) ^ (s[2] << 16) ^ s[3] ^ (s[3] >> 16) ^
|
|
(s[4] << 16) ^ (s[4] >> 16) ^ (s[5] << 16) ^ (s[5] >> 16) ^ s[6] ^
|
|
(s[6] << 16) ^ (s[6] >> 16) ^ (s[7] << 16);
|
|
u[7] = m[7] ^ (s[0] & 0xFFFF0000) ^ (s[0] << 16) ^ (s[1] & 0xFFFF) ^
|
|
(s[1] << 16) ^ (s[2] >> 16) ^ (s[3] << 16) ^ s[4] ^ (s[4] >> 16) ^
|
|
(s[5] << 16) ^ (s[5] >> 16) ^ (s[6] >> 16) ^ (s[7] & 0xFFFF) ^
|
|
(s[7] << 16) ^ (s[7] >> 16);
|
|
|
|
// 16 * 1 round of the LFSR and XOR in H
|
|
v[0] = h[0] ^ (u[1] << 16) ^ (u[0] >> 16);
|
|
v[1] = h[1] ^ (u[2] << 16) ^ (u[1] >> 16);
|
|
v[2] = h[2] ^ (u[3] << 16) ^ (u[2] >> 16);
|
|
v[3] = h[3] ^ (u[4] << 16) ^ (u[3] >> 16);
|
|
v[4] = h[4] ^ (u[5] << 16) ^ (u[4] >> 16);
|
|
v[5] = h[5] ^ (u[6] << 16) ^ (u[5] >> 16);
|
|
v[6] = h[6] ^ (u[7] << 16) ^ (u[6] >> 16);
|
|
v[7] = h[7] ^ (u[0] & 0xFFFF0000) ^ (u[0] << 16) ^ (u[7] >> 16) ^
|
|
(u[1] & 0xFFFF0000) ^ (u[1] << 16) ^ (u[6] << 16) ^ (u[7] & 0xFFFF0000);
|
|
|
|
// 61 rounds of LFSR, mixing up h (computed from a product matrix)
|
|
h[0] = (v[0] & 0xFFFF0000) ^ (v[0] << 16) ^ (v[0] >> 16) ^ (v[1] >> 16) ^
|
|
(v[1] & 0xFFFF0000) ^ (v[2] << 16) ^ (v[3] >> 16) ^ (v[4] << 16) ^
|
|
(v[5] >> 16) ^ v[5] ^ (v[6] >> 16) ^ (v[7] << 16) ^ (v[7] >> 16) ^
|
|
(v[7] & 0xFFFF);
|
|
h[1] = (v[0] << 16) ^ (v[0] >> 16) ^ (v[0] & 0xFFFF0000) ^ (v[1] & 0xFFFF) ^
|
|
v[2] ^ (v[2] >> 16) ^ (v[3] << 16) ^ (v[4] >> 16) ^ (v[5] << 16) ^
|
|
(v[6] << 16) ^ v[6] ^ (v[7] & 0xFFFF0000) ^ (v[7] >> 16);
|
|
h[2] = (v[0] & 0xFFFF) ^ (v[0] << 16) ^ (v[1] << 16) ^ (v[1] >> 16) ^
|
|
(v[1] & 0xFFFF0000) ^ (v[2] << 16) ^ (v[3] >> 16) ^ v[3] ^ (v[4] << 16) ^
|
|
(v[5] >> 16) ^ v[6] ^ (v[6] >> 16) ^ (v[7] & 0xFFFF) ^ (v[7] << 16) ^
|
|
(v[7] >> 16);
|
|
h[3] = (v[0] << 16) ^ (v[0] >> 16) ^ (v[0] & 0xFFFF0000) ^
|
|
(v[1] & 0xFFFF0000) ^ (v[1] >> 16) ^ (v[2] << 16) ^ (v[2] >> 16) ^ v[2] ^
|
|
(v[3] << 16) ^ (v[4] >> 16) ^ v[4] ^ (v[5] << 16) ^ (v[6] << 16) ^
|
|
(v[7] & 0xFFFF) ^ (v[7] >> 16);
|
|
h[4] = (v[0] >> 16) ^ (v[1] << 16) ^ v[1] ^ (v[2] >> 16) ^ v[2] ^
|
|
(v[3] << 16) ^ (v[3] >> 16) ^ v[3] ^ (v[4] << 16) ^ (v[5] >> 16) ^
|
|
v[5] ^ (v[6] << 16) ^ (v[6] >> 16) ^ (v[7] << 16);
|
|
h[5] = (v[0] << 16) ^ (v[0] & 0xFFFF0000) ^ (v[1] << 16) ^ (v[1] >> 16) ^
|
|
(v[1] & 0xFFFF0000) ^ (v[2] << 16) ^ v[2] ^ (v[3] >> 16) ^ v[3] ^
|
|
(v[4] << 16) ^ (v[4] >> 16) ^ v[4] ^ (v[5] << 16) ^ (v[6] << 16) ^
|
|
(v[6] >> 16) ^ v[6] ^ (v[7] << 16) ^ (v[7] >> 16) ^ (v[7] & 0xFFFF0000);
|
|
h[6] = v[0] ^ v[2] ^ (v[2] >> 16) ^ v[3] ^ (v[3] << 16) ^ v[4] ^
|
|
(v[4] >> 16) ^ (v[5] << 16) ^ (v[5] >> 16) ^ v[5] ^ (v[6] << 16) ^
|
|
(v[6] >> 16) ^ v[6] ^ (v[7] << 16) ^ v[7];
|
|
h[7] = v[0] ^ (v[0] >> 16) ^ (v[1] << 16) ^ (v[1] >> 16) ^ (v[2] << 16) ^
|
|
(v[3] >> 16) ^ v[3] ^ (v[4] << 16) ^ v[4] ^ (v[5] >> 16) ^ v[5] ^
|
|
(v[6] << 16) ^ (v[6] >> 16) ^ (v[7] << 16) ^ v[7];
|
|
}
|
|
|
|
void CGOSTHash::_Bytes(const UWORD8 *pBuf, UWORD32 uBits)
|
|
{
|
|
INTPREF i, j = 0;
|
|
UWORD32 a, c = 0, m[8];
|
|
|
|
// Convert bytes to 32-bit words and compute the sum
|
|
for(i = 0; i < 8; i++)
|
|
{
|
|
a = ((UWORD32)pBuf[j]) |
|
|
(((UWORD32)pBuf[j + 1]) << 8) |
|
|
(((UWORD32)pBuf[j + 2]) << 16) |
|
|
(((UWORD32)pBuf[j + 3]) << 24);
|
|
|
|
j += 4;
|
|
m[i] = a;
|
|
|
|
// Bugfix July 23, 2002 mjos@iki.fi. Thanks to Kaluzhinsky Anatoly.
|
|
if(c)
|
|
{
|
|
c = a + m_sum[i] + 1;
|
|
m_sum[i] = c;
|
|
c = c <= a;
|
|
}
|
|
else
|
|
{
|
|
c = a + m_sum[i];
|
|
m_sum[i] = c;
|
|
c = c < a;
|
|
}
|
|
}
|
|
|
|
_Compress(m_hash, m);
|
|
|
|
// A 64-bit counter should be sufficient
|
|
m_len[0] += uBits;
|
|
if(m_len[0] < uBits) // Overflowed
|
|
m_len[1]++;
|
|
}
|
|
|
|
void CGOSTHash::Update(const UWORD8 *pBuf, UINTPREF uLen)
|
|
{
|
|
UINTPREF i, j = 0;
|
|
|
|
i = m_partial_bytes;
|
|
|
|
while((i < 32) && (j < uLen))
|
|
m_partial[i++] = pBuf[j++];
|
|
|
|
if(i < 32)
|
|
{
|
|
m_partial_bytes = i;
|
|
return;
|
|
}
|
|
_Bytes(m_partial, 256);
|
|
|
|
while((j + 32) < uLen)
|
|
{
|
|
_Bytes(&pBuf[j], 256);
|
|
j += 32;
|
|
}
|
|
|
|
i = 0;
|
|
while(j < uLen)
|
|
m_partial[i++] = pBuf[j++];
|
|
|
|
m_partial_bytes = i;
|
|
}
|
|
|
|
void CGOSTHash::Final()
|
|
{
|
|
INTPREF i, j = 0;
|
|
UWORD32 a;
|
|
|
|
if(m_partial_bytes > 0)
|
|
{
|
|
memset(&m_partial[m_partial_bytes], 0, 32 - m_partial_bytes);
|
|
_Bytes(m_partial, m_partial_bytes << 3);
|
|
}
|
|
|
|
_Compress(m_hash, m_len);
|
|
_Compress(m_hash, m_sum);
|
|
|
|
for(i = 0; i < 8; i++)
|
|
{
|
|
a = m_hash[i];
|
|
m_digest[j] = (UWORD8) a;
|
|
m_digest[j + 1] = (UWORD8)(a >> 8);
|
|
m_digest[j + 2] = (UWORD8)(a >> 16);
|
|
m_digest[j + 3] = (UWORD8)(a >> 24);
|
|
j += 4;
|
|
}
|
|
}
|