diff options
Diffstat (limited to '3rdparty/plibsys/src/pcryptohash-gost3411.c')
-rw-r--r-- | 3rdparty/plibsys/src/pcryptohash-gost3411.c | 484 |
1 files changed, 484 insertions, 0 deletions
diff --git a/3rdparty/plibsys/src/pcryptohash-gost3411.c b/3rdparty/plibsys/src/pcryptohash-gost3411.c new file mode 100644 index 0000000..9430453 --- /dev/null +++ b/3rdparty/plibsys/src/pcryptohash-gost3411.c @@ -0,0 +1,484 @@ +/* + * The MIT License + * + * Copyright (C) 2010-2017 Alexander Saprykin <saprykin.spb@gmail.com> + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * 'Software'), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "pmem.h" +#include "pcryptohash-gost3411.h" + +#include <string.h> +#include <stdlib.h> + +struct PHashGOST3411_ { + puint32 buf[8]; /* Buffer to handle incoming data. */ + puint32 hash[8]; /* State of calculated hash. */ + puint32 len[8]; /* Length of hashed data, in bits. */ + puint32 sum[8]; /* 256-bit sum of hashed data. */ +}; + +static void pp_crypto_hash_gost3411_swap_bytes (puint32 *data, puint words); +static void pp_crypto_hash_gost3411_sum_256 (puint32 a[8], const puint32 b[8]); +static void pp_crypto_hash_gost3411_process (PHashGOST3411 *ctx, const puint32 data[8]); + +/* K block data from RFC4357 for GOST 28147-89 */ +/* static const puchar pp_crypto_hash_gost3411_K_block[8][16] = { + {0x9, 0x6, 0x3, 0x2, 0x8, 0xB, 0x1, 0x7, 0xA, 0x4, 0xE, 0xF, 0xC, 0x0, 0xD, 0x5}, + {0x3, 0x7, 0xE, 0x9, 0x8, 0xA, 0xF, 0x0, 0x5, 0x2, 0x6, 0xC, 0xB, 0x4, 0xD, 0x1}, + {0xE, 0x4, 0x6, 0x2, 0xB, 0x3, 0xD, 0x8, 0xC, 0xF, 0x5, 0xA, 0x0, 0x7, 0x1, 0x9}, + {0xE, 0x7, 0xA, 0xC, 0xD, 0x1, 0x3, 0x9, 0x0, 0x2, 0xB, 0x4, 0xF, 0x8, 0x5, 0x6}, + {0xB, 0x5, 0x1, 0x9, 0x8, 0xD, 0xF, 0x0, 0xE, 0x4, 0x2, 0x3, 0xC, 0x7, 0xA, 0x6}, + {0x3, 0xA, 0xD, 0xC, 0x1, 0x2, 0x0, 0xB, 0x7, 0x5, 0x9, 0x4, 0x8, 0xF, 0xE, 0x6}, + {0x1, 0xD, 0x2, 0x9, 0x7, 0xA, 0x6, 0x0, 0x8, 0xC, 0x4, 0x5, 0xF, 0x3, 0xB, 0xE}, + {0xB, 0xA, 0xF, 0x5, 0x0, 0xC, 0xE, 0x8, 0x6, 0x2, 0x3, 0x9, 0x1, 0x7, 0xD, 0x4} +}; */ + +/* K block data used by Russian Central Bank (see RFC 4357, sec. 11.2) */ +/* static const puchar pp_crypto_hash_gost3411_K_block[8][16] = { + {0x4, 0xA, 0x9, 0x2, 0xD, 0x8, 0x0, 0xE, 0x6, 0xB, 0x1, 0xC, 0x7, 0xF, 0x5, 0x3}, + {0xE, 0xB, 0x4, 0xC, 0x6, 0xD, 0xF, 0xA, 0x2, 0x3, 0x8, 0x1, 0x0, 0x7, 0x5, 0x9}, + {0x5, 0x8, 0x1, 0xD, 0xA, 0x3, 0x4, 0x2, 0xE, 0xF, 0xC, 0x7, 0x6, 0x0, 0x9, 0xB}, + {0x7, 0xD, 0xA, 0x1, 0x0, 0x8, 0x9, 0xF, 0xE, 0x4, 0x6, 0xC, 0xB, 0x2, 0x5, 0x3}, + {0x6, 0xC, 0x7, 0x1, 0x5, 0xF, 0xD, 0x8, 0x4, 0xA, 0x9, 0xE, 0x0, 0x3, 0xB, 0x2}, + {0x4, 0xB, 0xA, 0x0, 0x7, 0x2, 0x1, 0xD, 0x3, 0x6, 0x8, 0x5, 0x9, 0xC, 0xF, 0xE}, + {0xD, 0xB, 0x4, 0x1, 0x3, 0xF, 0x5, 0x9, 0x0, 0xA, 0xE, 0x7, 0x6, 0x8, 0x2, 0xC}, + {0x1, 0xF, 0xD, 0x0, 0x5, 0x7, 0xA, 0x4, 0x9, 0x2, 0x3, 0xE, 0x6, 0xB, 0x8, 0xC} +}; */ + + /* K block data id-GostR3411-94-CryptoProParamSet (see RFC 4357, sec. 11.2) */ + static const puchar pp_crypto_hash_gost3411_K_block[8][16] = { + {0xA, 0x4, 0x5, 0x6, 0x8, 0x1, 0x3, 0x7, 0xD, 0xC, 0xE, 0x0, 0x9, 0x2, 0xB, 0xF}, + {0x5, 0xF, 0x4, 0x0, 0x2, 0xD, 0xB, 0x9, 0x1, 0x7, 0x6, 0x3, 0xC, 0xE, 0xA, 0x8}, + {0x7, 0xF, 0xC, 0xE, 0x9, 0x4, 0x1, 0x0, 0x3, 0xB, 0x5, 0x2, 0x6, 0xA, 0x8, 0xD}, + {0x4, 0xA, 0x7, 0xC, 0x0, 0xF, 0x2, 0x8, 0xE, 0x1, 0x6, 0x5, 0xD, 0xB, 0x9, 0x3}, + {0x7, 0x6, 0x4, 0xB, 0x9, 0xC, 0x2, 0xA, 0x1, 0x8, 0x0, 0xE, 0xF, 0xD, 0x3, 0x5}, + {0x7, 0x6, 0x2, 0x4, 0xD, 0x9, 0xF, 0x0, 0xA, 0x1, 0x5, 0xB, 0x8, 0xE, 0xC, 0x3}, + {0xD, 0xE, 0x4, 0x1, 0x7, 0x0, 0x5, 0xA, 0x3, 0xC, 0x8, 0xF, 0x6, 0x2, 0x9, 0xB}, + {0x1, 0x3, 0xA, 0x9, 0x5, 0xB, 0x4, 0xF, 0x8, 0x6, 0x7, 0xE, 0xD, 0x0, 0x2, 0xC} + }; + +/* GOST 28147-89 transformation to generate keys */ +#define P_GOST_28147_ROUND(N, key) \ +{ \ + puint32 CM1; \ + \ + CM1 = (N)[0] + (key); \ + \ + CM1 = ((puint32) pp_crypto_hash_gost3411_K_block [0][CM1 & 0xF] \ + | (puint32) pp_crypto_hash_gost3411_K_block [1][(CM1 >> 4) & 0xF] << 4 \ + | (puint32) pp_crypto_hash_gost3411_K_block [2][(CM1 >> 8) & 0xF] << 8 \ + | (puint32) pp_crypto_hash_gost3411_K_block [3][(CM1 >> 12) & 0xF] << 12 \ + | (puint32) pp_crypto_hash_gost3411_K_block [4][(CM1 >> 16) & 0xF] << 16 \ + | (puint32) pp_crypto_hash_gost3411_K_block [5][(CM1 >> 20) & 0xF] << 20 \ + | (puint32) pp_crypto_hash_gost3411_K_block [6][(CM1 >> 24) & 0xF] << 24 \ + | (puint32) pp_crypto_hash_gost3411_K_block [7][(CM1 >> 28) & 0xF] << 28); \ + \ + CM1 = ((CM1 << 11) | (CM1 >> 21)) ^ (N)[1]; \ + (N)[1] = (N)[0]; \ + (N)[0] = CM1; \ +} + +/* Core GOST 28147-89 transformation */ +#define P_GOST_28147_E(data, key, out) \ +{ \ + puint32 N[2]; \ + \ + memcpy (N, data, 8); \ + \ + P_GOST_28147_ROUND (N, (key)[0]); \ + P_GOST_28147_ROUND (N, (key)[1]); \ + P_GOST_28147_ROUND (N, (key)[2]); \ + P_GOST_28147_ROUND (N, (key)[3]); \ + P_GOST_28147_ROUND (N, (key)[4]); \ + P_GOST_28147_ROUND (N, (key)[5]); \ + P_GOST_28147_ROUND (N, (key)[6]); \ + P_GOST_28147_ROUND (N, (key)[7]); \ + \ + P_GOST_28147_ROUND (N, (key)[0]); \ + P_GOST_28147_ROUND (N, (key)[1]); \ + P_GOST_28147_ROUND (N, (key)[2]); \ + P_GOST_28147_ROUND (N, (key)[3]); \ + P_GOST_28147_ROUND (N, (key)[4]); \ + P_GOST_28147_ROUND (N, (key)[5]); \ + P_GOST_28147_ROUND (N, (key)[6]); \ + P_GOST_28147_ROUND (N, (key)[7]); \ + \ + P_GOST_28147_ROUND (N, (key)[0]); \ + P_GOST_28147_ROUND (N, (key)[1]); \ + P_GOST_28147_ROUND (N, (key)[2]); \ + P_GOST_28147_ROUND (N, (key)[3]); \ + P_GOST_28147_ROUND (N, (key)[4]); \ + P_GOST_28147_ROUND (N, (key)[5]); \ + P_GOST_28147_ROUND (N, (key)[6]); \ + P_GOST_28147_ROUND (N, (key)[7]); \ + \ + P_GOST_28147_ROUND (N, (key)[7]); \ + P_GOST_28147_ROUND (N, (key)[6]); \ + P_GOST_28147_ROUND (N, (key)[5]); \ + P_GOST_28147_ROUND (N, (key)[4]); \ + P_GOST_28147_ROUND (N, (key)[3]); \ + P_GOST_28147_ROUND (N, (key)[2]); \ + P_GOST_28147_ROUND (N, (key)[1]); \ + P_GOST_28147_ROUND (N, (key)[0]); \ + \ + (out)[0] = N[1]; \ + (out)[1] = N[0]; \ +} + +/* P transformation from GOST R 34.11-94 */ +#define P_GOST_3411_P(data, out) \ +{ \ + (out)[0] = ((data) [0] & 0x000000FF) \ + | (((data)[2] << 8) & 0x0000FF00) \ + | (((data)[4] << 16) & 0x00FF0000) \ + | (((data)[6] << 24) & 0xFF000000); \ + (out)[1] = (((data)[0] >> 8) & 0x000000FF) \ + | ((data) [2] & 0x0000FF00) \ + | (((data)[4] << 8) & 0x00FF0000) \ + | (((data)[6] << 16) & 0xFF000000); \ + (out)[2] = (((data)[0] >> 16) & 0x000000FF) \ + | (((data)[2] >> 8) & 0x0000FF00) \ + | ((data) [4] & 0x00FF0000) \ + | (((data)[6] << 8) & 0xFF000000); \ + (out)[3] = (((data)[0] >> 24) & 0x000000FF) \ + | (((data)[2] >> 16) & 0x0000FF00) \ + | (((data)[4] >> 8) & 0x00FF0000) \ + | ((data) [6] & 0xFF000000); \ + (out)[4] = ((data) [1] & 0x000000FF) \ + | (((data)[3] << 8) & 0x0000FF00) \ + | (((data)[5] << 16) & 0x00FF0000) \ + | (((data)[7] << 24) & 0xFF000000); \ + (out)[5] = (((data)[1] >> 8) & 0x000000FF) \ + | ((data) [3] & 0x0000FF00) \ + | (((data)[5] << 8) & 0x00FF0000) \ + | (((data)[7] << 16) & 0xFF000000); \ + (out)[6] = (((data)[1] >> 16) & 0x000000FF) \ + | (((data)[3] >> 8) & 0x0000FF00) \ + | ((data) [5] & 0x00FF0000) \ + | (((data)[7] << 8) & 0xFF000000); \ + (out)[7] = (((data)[1] >> 24) & 0x000000FF) \ + | (((data)[3] >> 16) & 0x0000FF00) \ + | (((data)[5] >> 8) & 0x00FF0000) \ + | ((data) [7] & 0xFF000000); \ +} + +static void +pp_crypto_hash_gost3411_swap_bytes (puint32 *data, + puint words) +{ +#ifndef PLIBSYS_IS_BIGENDIAN + P_UNUSED (data); + P_UNUSED (words); +#else + while (words-- > 0) { + *data = PUINT32_TO_LE (*data); + ++data; + } +#endif +} + +/* 256-bit sum */ +static void +pp_crypto_hash_gost3411_sum_256 (puint32 a[8], + const puint32 b[8]) +{ + puint i; + puint32 old; + pboolean carry; + + carry = FALSE; + for (i = 0; i < 8; ++i) { + old = a[i]; + a[i] = a[i] + b[i] + (carry ? 1 : 0); + carry = (a[i] < old || a[i] < b[i]) ? TRUE : FALSE; + } +} + +/* Core GOST R 34.11-94 transformation */ +static void pp_crypto_hash_gost3411_process (PHashGOST3411 *ctx, + const puint32 data[8]) +{ + puint32 U[8], V[8], W[8], S[8], K[4][8]; + + memcpy (U, ctx->hash, 32); + memcpy (V, data, 32); + + /* Generate first key: P (U xor V) */ + W[0] = U[0] ^ V[0]; + 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_GOST_3411_P (W, K[0]); + + /* Generate second key: P (A (U) xor A^2 (V)) */ + W[0] = U[2] ^ V[4]; + W[1] = U[3] ^ V[5]; + W[2] = U[4] ^ V[6]; + W[3] = U[5] ^ V[7]; + W[4] = U[6] ^ (V[0] ^= V[2]); + W[5] = U[7] ^ (V[1] ^= V[3]); + W[6] = (U[0] ^= U[2]) ^ (V[2] ^= V[4]); + W[7] = (U[1] ^= U[3]) ^ (V[3] ^= V[5]); + + P_GOST_3411_P (W, K[1]); + + /* Generate third key: P ((A^2 (U) + C3) xor A^4 (V)) */ + /* C3 = FF00FFFF 000000FF FF0000FF 00FFFF00 00FF00FF 00FF00FF FF00FF00 FF00FF00 */ + U[2] ^= U[4] ^ 0x000000FF; + U[3] ^= U[5] ^ 0xFF00FFFF; + U[4] ^= 0xFF00FF00; + U[5] ^= 0xFF00FF00; + U[6] ^= 0x00FF00FF; + U[7] ^= 0x00FF00FF; + U[0] ^= 0x00FFFF00; + U[1] ^= 0xFF0000FF; + + W[0] = U[4] ^ V[0]; + W[2] = U[6] ^ V[2]; + W[4] = U[0] ^ (V[4] ^= V[6]); + W[6] = U[2] ^ (V[6] ^= V[0]); + W[1] = U[5] ^ V[1]; + W[3] = U[7] ^ V[3]; + W[5] = U[1] ^ (V[5] ^= V[7]); + W[7] = U[3] ^ (V[7] ^= V[1]); + + P_GOST_3411_P (W, K[2]); + + /* Generate forth key: P (A (A^2 (U) xor C3) xor A^6 (V)) */ + W[0] = U[6] ^ V[4]; + W[1] = U[7] ^ V[5]; + W[2] = U[0] ^ V[6]; + W[3] = U[1] ^ V[7]; + W[4] = U[2] ^ (V[0] ^= V[2]); + W[5] = U[3] ^ (V[1] ^= V[3]); + W[6] = (U[4] ^= U[6]) ^ (V[2] ^= V[4]); + W[7] = (U[5] ^= U[7]) ^ (V[3] ^= V[5]); + + P_GOST_3411_P (W, K[3]); + + /* Perform GOST 28147-89 encryption */ + P_GOST_28147_E (ctx->hash, K[0], S); + P_GOST_28147_E (ctx->hash + 2, K[1], S + 2); + P_GOST_28147_E (ctx->hash + 4, K[2], S + 4); + P_GOST_28147_E (ctx->hash + 6, K[3], S + 6); + + /* Step hash function: H (M, Hprev) = PSI^61 (Hprev xor PSI (M xor PSI^12 (S))) */ + + /* (12 rounds of LFSR) xor M */ + U[0] = data[0] ^ S[6]; + + U[1] = data[1] ^ S[7]; + + U[2] = data[2] ^ (S[0] & 0x0000FFFF) ^ (S[0] >> 16) ^ (S[0] << 16) + ^ (S[1] & 0x0000FFFF) ^ (S[1] >> 16) ^ (S[2] << 16) + ^ (S[7] & 0xFFFF0000) ^ (S[6] << 16) ^ (S[7] >> 16) + ^ S[6]; + + U[3] = data[3] ^ (S[0] & 0x0000FFFF) ^ (S[0] << 16) ^ (S[2] << 16) + ^ (S[1] & 0x0000FFFF) ^ (S[1] << 16) ^ (S[1] >> 16) + ^ (S[7] & 0x0000FFFF) ^ (S[2] >> 16) ^ (S[3] << 16) + ^ (S[6] << 16) ^ (S[6] >> 16) ^ (S[7] << 16) + ^ (S[7] >> 16) ^ S[6]; + + U[4] = data[4] ^ (S[0] & 0xFFFF0000) ^ (S[0] << 16) ^ (S[0] >> 16) + ^ (S[1] & 0xFFFF0000) ^ (S[1] >> 16) ^ (S[2] << 16) + ^ (S[7] & 0x0000FFFF) ^ (S[3] << 16) ^ (S[3] >> 16) + ^ (S[4] << 16) ^ (S[6] << 16) ^ (S[6] >> 16) + ^ (S[2] >> 16) ^ (S[7] << 16) ^ (S[7] >> 16); + + U[5] = data[5] ^ (S[0] & 0xFFFF0000) ^ (S[0] >> 16) ^ (S[0] << 16) + ^ (S[1] & 0x0000FFFF) ^ (S[7] >> 16) ^ (S[2] >> 16) + ^ (S[7] & 0xFFFF0000) ^ (S[3] >> 16) ^ (S[4] << 16) + ^ (S[4] >> 16) ^ (S[5] << 16) ^ (S[6] << 16) + ^ (S[6] >> 16) ^ (S[3] << 16) ^ (S[7] << 16) + ^ S[2]; + + U[6] = data[6] ^ (S[4] >> 16) ^ (S[1] >> 16) ^ (S[2] << 16) + ^ (S[7] << 16) ^ (S[3] >> 16) ^ (S[4] << 16) + ^ (S[5] << 16) ^ (S[5] >> 16) ^ (S[6] << 16) + ^ (S[6] >> 16) ^ S[6] ^ S[0] + ^ S[3]; + + U[7] = data[7] ^ (S[0] & 0xFFFF0000) ^ (S[0] << 16) ^ (S[1] << 16) + ^ (S[1] & 0x0000FFFF) ^ (S[2] >> 16) ^ (S[3] << 16) + ^ (S[7] & 0x0000FFFF) ^ (S[4] >> 16) ^ (S[5] << 16) + ^ (S[5] >> 16) ^ (S[6] >> 16) ^ (S[7] << 16) + ^ (S[7] >> 16) ^ S[4]; + + /* (1 round of LFSR) xor Hprev */ + V[0] = ctx->hash[0] ^ (U[1] << 16) ^ (U[0] >> 16); + V[1] = ctx->hash[1] ^ (U[2] << 16) ^ (U[1] >> 16); + V[2] = ctx->hash[2] ^ (U[3] << 16) ^ (U[2] >> 16); + V[3] = ctx->hash[3] ^ (U[4] << 16) ^ (U[3] >> 16); + V[4] = ctx->hash[4] ^ (U[5] << 16) ^ (U[4] >> 16); + V[5] = ctx->hash[5] ^ (U[6] << 16) ^ (U[5] >> 16); + V[6] = ctx->hash[6] ^ (U[7] << 16) ^ (U[6] >> 16); + V[7] = ctx->hash[7] ^ (U[7] >> 16) + ^ (U[0] << 16) ^ (U[1] & 0xFFFF0000) + ^ (U[1] << 16) ^ (U[7] & 0xFFFF0000) + ^ (U[6] << 16) ^ (U[0] & 0xFFFF0000); + + /* Final 61 rounds of LFSR */ + ctx->hash[0] = (V[0] & 0xFFFF0000) ^ (V[0] << 16) ^ (V[0] >> 16) + ^ (V[1] & 0xFFFF0000) ^ (V[1] >> 16) ^ (V[2] << 16) + ^ (V[7] & 0x0000FFFF) ^ (V[3] >> 16) ^ (V[4] << 16) + ^ (V[5] >> 16) ^ (V[6] >> 16) ^ (V[7] << 16) + ^ (V[7] >> 16) ^ V[5]; + ctx->hash[1] = (V[0] & 0xFFFF0000) ^ (V[0] << 16) ^ (V[0] >> 16) + ^ (V[1] & 0x0000FFFF) ^ (V[2] >> 16) ^ (V[3] << 16) + ^ (V[7] & 0xFFFF0000) ^ (V[4] >> 16) ^ (V[5] << 16) + ^ (V[6] << 16) ^ (V[7] >> 16) ^ V[6] + ^ V[2] ; + ctx->hash[2] = (V[0] & 0x0000FFFF) ^ (V[0] << 16) ^ (V[1] << 16) + ^ (V[7] & 0x0000FFFF) ^ (V[1] >> 16) ^ (V[2] << 16) + ^ (V[1] & 0xFFFF0000) ^ (V[3] >> 16) ^ (V[4] << 16) + ^ (V[5] >> 16) ^ (V[6] >> 16) ^ (V[7] << 16) + ^ (V[7] >> 16) ^ V[3] ^ V[6]; + ctx->hash[3] = (V[0] & 0xFFFF0000) ^ (V[0] << 16) ^ (V[0] >> 16) + ^ (V[1] & 0xFFFF0000) ^ (V[1] >> 16) ^ (V[2] << 16) + ^ (V[7] & 0x0000FFFF) ^ (V[2] >> 16) ^ (V[3] << 16) + ^ (V[4] >> 16) ^ (V[5] << 16) ^ (V[6] << 16) + ^ (V[7] >> 16) ^ V[2] ^ V[4]; + ctx->hash[4] = (V[0] >> 16) ^ (V[1] << 16) ^ (V[2] >> 16) + ^ (V[3] << 16) ^ (V[3] >> 16) ^ (V[4] << 16) + ^ (V[5] >> 16) ^ (V[6] << 16) ^ (V[6] >> 16) + ^ (V[7] << 16) ^ V[1] ^ V[2] + ^ V[3] ^ V[5]; + ctx->hash[5] = (V[0] & 0xFFFF0000) ^ (V[0] << 16) ^ (V[1] << 16) + ^ (V[1] & 0xFFFF0000) ^ (V[1] >> 16) ^ (V[2] << 16) + ^ (V[7] & 0xFFFF0000) ^ (V[3] >> 16) ^ (V[4] << 16) + ^ (V[4] >> 16) ^ (V[5] << 16) ^ (V[6] << 16) + ^ (V[6] >> 16) ^ (V[7] << 16) ^ (V[7] >> 16) + ^ V[2] ^ V[3] ^ V[4] + ^ V[6]; + ctx->hash[6] = (V[2] >> 16) ^ (V[3] << 16) ^ (V[4] >> 16) + ^ (V[5] << 16) ^ (V[5] >> 16) ^ (V[6] << 16) + ^ (V[6] >> 16) ^ (V[7] << 16) ^ V[7] + ^ V[0] ^ V[2] ^ V[3] + ^ V[4] ^ V[5] ^ V[6]; + ctx->hash[7] = (V[0] >> 16) ^ (V[1] << 16) ^ (V[1] >> 16) + ^ (V[2] << 16) ^ (V[3] >> 16) ^ (V[4] << 16) + ^ (V[5] >> 16) ^ (V[6] << 16) ^ (V[6] >> 16) + ^ (V[7] << 16) ^ V[7] ^ V[0] + ^ V[3] ^ V[4] ^ V[5]; +} + +PHashGOST3411 * +p_crypto_hash_gost3411_new (void) +{ + PHashGOST3411 *ret; + + if (P_UNLIKELY ((ret = p_malloc0 (sizeof (PHashGOST3411))) == NULL)) + return NULL; + + p_crypto_hash_gost3411_reset (ret); + + return ret; +} + +void +p_crypto_hash_gost3411_update (PHashGOST3411 *ctx, + const puchar *data, + psize len) +{ + puint32 left, to_fill, len256[8]; + + left = (ctx->len[0] & 0xFF) >> 3; + to_fill = 32 - left; + + memset (len256, 0, 32); + len256[0] = (puint32) (len << 3); + len256[1] = (puint32) (len >> 29); + + pp_crypto_hash_gost3411_sum_256 (ctx->len, len256); + + if (left && (puint32) len >= to_fill) { + memcpy ((pchar *) ctx->buf + left, data, to_fill); + pp_crypto_hash_gost3411_swap_bytes (ctx->buf, 8); + pp_crypto_hash_gost3411_process (ctx, ctx->buf); + pp_crypto_hash_gost3411_sum_256 (ctx->sum, ctx->buf); + + data += to_fill; + len -= to_fill; + left = 0; + } + + while (len >= 32) { + memcpy (ctx->buf, data, 32); + pp_crypto_hash_gost3411_swap_bytes (ctx->buf, 8); + pp_crypto_hash_gost3411_process (ctx, ctx->buf); + pp_crypto_hash_gost3411_sum_256 (ctx->sum, ctx->buf); + + data += 32; + len -= 32; + } + + if (len > 0) + memcpy ((pchar *) ctx->buf + left, data, len); +} + +void +p_crypto_hash_gost3411_finish (PHashGOST3411 *ctx) +{ + puint32 left, last; + + left = ctx->len[0] & 0xFF; + last = 32 - (left >> 3); + + if (last % 32 != 0) { + memset ((pchar *) ctx->buf + (left >> 3), 0, last); + pp_crypto_hash_gost3411_swap_bytes (ctx->buf, 8); + pp_crypto_hash_gost3411_process (ctx, ctx->buf); + pp_crypto_hash_gost3411_sum_256 (ctx->sum, ctx->buf); + } + + pp_crypto_hash_gost3411_process (ctx, ctx->len); + pp_crypto_hash_gost3411_process (ctx, ctx->sum); + + pp_crypto_hash_gost3411_swap_bytes (ctx->hash, 8); +} + +const puchar * +p_crypto_hash_gost3411_digest (PHashGOST3411 *ctx) +{ + return (const puchar *) ctx->hash; +} + +void +p_crypto_hash_gost3411_reset (PHashGOST3411 *ctx) +{ + memset (ctx->buf, 0, 32); + memset (ctx->hash, 0, 32); + memset (ctx->len, 0, 32); + memset (ctx->sum, 0, 32); +} + +void +p_crypto_hash_gost3411_free (PHashGOST3411 *ctx) +{ + p_free (ctx); +} |