/** * Implementation of hash function «ГОСТ Р 34.11—2012». * RFC: 6986 https://tools.ietf.org/html/rfc6986 * GOST: http://protect.gost.ru/document.aspx?control=7&id=180209 * * @param hash Output buffer for 256/512-bit hash. * @param msg Entire message. * @param length Message length in bits. * @param is_512 true for 512-bit hash, false for 256-bit hash. * @return 0 — on success, 1 — on error. */ int streebog(WORD *hash, const unsigned char *msg, uint64_t length, bool is_512) { WORD h[WORDS_IN_CHUNK]; WORD N[WORDS_IN_CHUNK]; WORD uint512[WORDS_IN_CHUNK]; /* 512-bit unsigned integer. Little endian. */ WORD Sigma[WORDS_IN_CHUNK]; WORD padding[WORDS_IN_CHUNK]; WORD zero[WORDS_IN_CHUNK]; WORD *m; uint64_t len = length; for(int i = 0; i < 12; ++i) init_chunk(C[i], C_STR[i]); chunk_set(N, 0); chunk_set(Sigma, 0); chunk_set(zero, 0); set_uint512(uint512, 512); m = (WORD *)msg; if(is_512) chunk_set(h, 0); else chunk_set(h, WADDING); /* stage 2 */ while(len >= CHUNK_BITS) { gN(h, m, N); add512(N, uint512); add512(Sigma, m); len -= CHUNK_BITS; m += WORDS_IN_CHUNK; } /* stage 3 */ /* 3.1. */ pad(padding, msg + length / CHUNK_BITS * CHUNK_SIZE, len); /* 3.2. */ gN(h, padding, N); /* 3.3. */ set_uint512(uint512, len); add512(N, uint512); /* 3.4. */ add512(Sigma, padding); /* 3.5. */ gN(h, N, zero); /* 3.6. */ gN(h, Sigma, zero); /* 3.7. */ chunk_cpy(hash, h, is_512); return 0; }
inline void pad(WORD *padding, const unsigned char *offcut, unsigned int len) { unsigned char i, shift, mask1 = 0xff, mask2 = 0x80; unsigned char *ptr = (unsigned char *)padding; chunk_set(padding, 0); i = len / 8; memcpy(padding, offcut, i + 1 - IS_MULT8(len)); shift = 8 - (len % 8); /* last bit index */ mask1 >>= shift; mask2 >>= (shift - 1); ptr[i] = (ptr[i] & mask1) | mask2; }
int main(int argc, char* argv[]) { int err, i; char key[10], value[10]; CHUNK* chunk; /* create database file */ err = chunk_create(FILENAME, HTABLE_SIZE); if (err) { printf("Error: cant create chunk file\n"); return -1; } /* open database file */ chunk = malloc(sizeof(CHUNK)); err = chunk_open(chunk, FILENAME, CACHE_SIZE); if (err) { free(chunk); printf("Error: problem with open chunk file\n"); return -2; } /* insert */ for(i=0; i<SIZE; i++) { sprintf(key, "%s%d", "key", i); sprintf(value, "%s%d", "value", i); chunk_set(chunk, key, value); } /* remove */ printf("chunk_remove key5 %d\n", chunk_remove(chunk, "key5")); printf("chunk_remove key7 %d\n", chunk_remove(chunk, "key7")); /* get */ for(i=0; i<SIZE; i++) { sprintf(key, "%s%d", "key", i); printf("chunk_get %s = %s\n",key, chunk_get(chunk, key)); } /* forEach */ chunk_for_each(chunk, display); /* close */ chunk_close(chunk); free(chunk); return 0; }
inline void L(WORD *chunk) { WORD *a_ptr; WORD i, j, k, l, word, test, ri; WORD result[WORDS_IN_CHUNK]; chunk_set(result, 0); for(i = 0; i < 8; ++i) /* base vectors */ { a_ptr = (WORD *)A; /* Test every bit in base vector and if set, do: step = A[] XOR previous_step */ for(j = WORDS_IN_VECTOR; j > 0; --j) { word = chunk[WORDS_IN_VECTOR * i + j - 1]; for(k = 0; k < ARCH_MODE; ++k) /* bits in word */ { test = word & (1ULL << (ARCH_MODE - 1 - k)); if(test) { for(l = 0; l < WORDS_IN_VECTOR; ++l) { ri = i * WORDS_IN_VECTOR + l; result[ri] ^= *a_ptr; ++a_ptr; } } else a_ptr += WORDS_IN_VECTOR; } } } chunk_cpy(chunk, result, true); }