diff --git a/cipher/gost28147.c b/cipher/gost28147.c index 862e7d66..c669148d 100644 --- a/cipher/gost28147.c +++ b/cipher/gost28147.c @@ -1,235 +1,235 @@ /* gost28147.c - GOST 28147-89 implementation for Libgcrypt * Copyright (C) 2012 Free Software Foundation, Inc. * * This file is part of Libgcrypt. * * Libgcrypt is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * Libgcrypt is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this program; if not, see . */ /* GOST 28147-89 defines several modes of encryption: * - ECB which should be used only for key transfer * - CFB mode * - OFB-like mode with additional transformation on keystream * RFC 5830 names this 'counter encryption' mode * Original GOST text uses the term 'gammirovanie' * - MAC mode * * This implementation handles ECB and CFB modes via usual libgcrypt handling. * OFB-like and MAC modes are unsupported. */ #include #include "types.h" #include "g10lib.h" #include "cipher.h" #define max(a, b) (((a) > (b)) ? (a) : (b)) /* This is an s-box from RFC4357, named GostR3411-94-TestParamSet * For now it is the only s-box supported, as libgcrypt lacks mechanism * for passing parameters to cipher in a usefull way. */ unsigned char test_sbox[16 * 8] = { 0x4, 0xE, 0x5, 0x7, 0x6, 0x4, 0xD, 0x1, 0xA, 0xB, 0x8, 0xD, 0xC, 0xB, 0xB, 0xF, 0x9, 0x4, 0x1, 0xA, 0x7, 0xA, 0x4, 0xD, 0x2, 0xC, 0xD, 0x1, 0x1, 0x0, 0x1, 0x0, 0xD, 0x6, 0xA, 0x0, 0x5, 0x7, 0x3, 0x5, 0x8, 0xD, 0x3, 0x8, 0xF, 0x2, 0xF, 0x7, 0x0, 0xF, 0x4, 0x9, 0xD, 0x1, 0x5, 0xA, 0xE, 0xA, 0x2, 0xF, 0x8, 0xD, 0x9, 0x4, 0x6, 0x2, 0xE, 0xE, 0x4, 0x3, 0x0, 0x9, 0xB, 0x3, 0xF, 0x4, 0xA, 0x6, 0xA, 0x2, 0x1, 0x8, 0xC, 0x6, 0x9, 0x8, 0xE, 0x3, 0xC, 0x1, 0x7, 0xC, 0xE, 0x5, 0x7, 0xE, 0x7, 0x0, 0x6, 0xB, 0x0, 0x9, 0x6, 0x6, 0xF, 0x7, 0x0, 0x2, 0x3, 0xC, 0x8, 0xB, 0x5, 0x5, 0x9, 0x5, 0xB, 0xF, 0x2, 0x8, 0x3, 0x9, 0xB, 0x3, 0x2, 0xE, 0xC, 0xC, }; #include "gost.h" static gcry_err_code_t gost_setkey (void *c, const byte *key, unsigned keylen) { int i; GOST28147_context *ctx = c; if (keylen != 256 / 8) return GPG_ERR_INV_KEYLEN; for (i = 0; i < 8; i++) { ctx->key[i] = (key[4 * i + 3] << 24) | (key[4 * i + 2] << 16) | (key[4 * i + 1] << 8) | (key[4 * i + 0] << 0); } return GPG_ERR_NO_ERROR; } static void gost_set_subst (GOST28147_context *ctx, unsigned char *sbox) { unsigned i, j; for (i = 0; i < 4; i++) { for (j = 0; j < 256; j++) { ctx->subst[i][j] = sbox[ (j & 0xf) * 8 + 2 * i + 0] | (sbox[ (j >> 4) * 8 + 2 * i + 1] << 4); } } ctx->subst_set = 1; } static u32 gost_val (GOST28147_context *ctx, u32 cm1, int subkey) { cm1 += ctx->key[subkey]; cm1 = (ctx->subst[0][ (cm1 >> 0) & 0xff] << 0) | (ctx->subst[1][ (cm1 >> 8) & 0xff] << 8) | (ctx->subst[2][ (cm1 >> 16) & 0xff] << 16) | (ctx->subst[3][ (cm1 >> 24) & 0xff] << 24); return (cm1 << 11) | (cm1 >> 21); } static unsigned int gost_encrypt_block (void *c, byte *outbuf, const byte *inbuf) { GOST28147_context *ctx = c; u32 n1, n2; if (!ctx->subst_set) gost_set_subst (ctx, test_sbox); n1 = (inbuf[0] << 0) | (inbuf[1] << 8) | (inbuf[2] << 16) | (inbuf[3] << 24); n2 = (inbuf[4] << 0) | (inbuf[5] << 8) | (inbuf[6] << 16) | (inbuf[7] << 24); n2 ^= gost_val (ctx, n1, 0); n1 ^= gost_val (ctx, n2, 1); n2 ^= gost_val (ctx, n1, 2); n1 ^= gost_val (ctx, n2, 3); n2 ^= gost_val (ctx, n1, 4); n1 ^= gost_val (ctx, n2, 5); n2 ^= gost_val (ctx, n1, 6); n1 ^= gost_val (ctx, n2, 7); n2 ^= gost_val (ctx, n1, 0); n1 ^= gost_val (ctx, n2, 1); n2 ^= gost_val (ctx, n1, 2); n1 ^= gost_val (ctx, n2, 3); n2 ^= gost_val (ctx, n1, 4); n1 ^= gost_val (ctx, n2, 5); n2 ^= gost_val (ctx, n1, 6); n1 ^= gost_val (ctx, n2, 7); n2 ^= gost_val (ctx, n1, 0); n1 ^= gost_val (ctx, n2, 1); n2 ^= gost_val (ctx, n1, 2); n1 ^= gost_val (ctx, n2, 3); n2 ^= gost_val (ctx, n1, 4); n1 ^= gost_val (ctx, n2, 5); n2 ^= gost_val (ctx, n1, 6); n1 ^= gost_val (ctx, n2, 7); n2 ^= gost_val (ctx, n1, 7); n1 ^= gost_val (ctx, n2, 6); n2 ^= gost_val (ctx, n1, 5); n1 ^= gost_val (ctx, n2, 4); n2 ^= gost_val (ctx, n1, 3); n1 ^= gost_val (ctx, n2, 2); n2 ^= gost_val (ctx, n1, 1); n1 ^= gost_val (ctx, n2, 0); outbuf[0 + 0] = (n2 >> (0 * 8)) & 0xff; outbuf[1 + 0] = (n2 >> (1 * 8)) & 0xff; outbuf[2 + 0] = (n2 >> (2 * 8)) & 0xff; outbuf[3 + 0] = (n2 >> (3 * 8)) & 0xff; outbuf[0 + 4] = (n1 >> (0 * 8)) & 0xff; outbuf[1 + 4] = (n1 >> (1 * 8)) & 0xff; outbuf[2 + 4] = (n1 >> (2 * 8)) & 0xff; outbuf[3 + 4] = (n1 >> (3 * 8)) & 0xff; return /* burn_stack */ 4*sizeof(void*) /* func call */ + 3*sizeof(void*) /* stack */ + max( 4*sizeof(void*) /* gost_val call */, 3*sizeof(void*) /* gost_set_subst call */ + 2*sizeof(void*) /* gost_set subst stack*/ ); } unsigned int _gcry_gost_enc_one (GOST28147_context *c, const byte *key, byte *out, byte *in) { gost_setkey (c, key, 32); - return gost_encrypt_block (c, out, in); + return gost_encrypt_block (c, out, in) + 5 * sizeof(void *); } static unsigned int gost_decrypt_block (void *c, byte *outbuf, const byte *inbuf) { GOST28147_context *ctx = c; u32 n1, n2; if (!ctx->subst_set) gost_set_subst (ctx, test_sbox); n1 = (inbuf[0] << 0) | (inbuf[1] << 8) | (inbuf[2] << 16) | (inbuf[3] << 24); n2 = (inbuf[4] << 0) | (inbuf[5] << 8) | (inbuf[6] << 16) | (inbuf[7] << 24); n2 ^= gost_val (ctx, n1, 0); n1 ^= gost_val (ctx, n2, 1); n2 ^= gost_val (ctx, n1, 2); n1 ^= gost_val (ctx, n2, 3); n2 ^= gost_val (ctx, n1, 4); n1 ^= gost_val (ctx, n2, 5); n2 ^= gost_val (ctx, n1, 6); n1 ^= gost_val (ctx, n2, 7); n2 ^= gost_val (ctx, n1, 7); n1 ^= gost_val (ctx, n2, 6); n2 ^= gost_val (ctx, n1, 5); n1 ^= gost_val (ctx, n2, 4); n2 ^= gost_val (ctx, n1, 3); n1 ^= gost_val (ctx, n2, 2); n2 ^= gost_val (ctx, n1, 1); n1 ^= gost_val (ctx, n2, 0); n2 ^= gost_val (ctx, n1, 7); n1 ^= gost_val (ctx, n2, 6); n2 ^= gost_val (ctx, n1, 5); n1 ^= gost_val (ctx, n2, 4); n2 ^= gost_val (ctx, n1, 3); n1 ^= gost_val (ctx, n2, 2); n2 ^= gost_val (ctx, n1, 1); n1 ^= gost_val (ctx, n2, 0); n2 ^= gost_val (ctx, n1, 7); n1 ^= gost_val (ctx, n2, 6); n2 ^= gost_val (ctx, n1, 5); n1 ^= gost_val (ctx, n2, 4); n2 ^= gost_val (ctx, n1, 3); n1 ^= gost_val (ctx, n2, 2); n2 ^= gost_val (ctx, n1, 1); n1 ^= gost_val (ctx, n2, 0); outbuf[0 + 0] = (n2 >> (0 * 8)) & 0xff; outbuf[1 + 0] = (n2 >> (1 * 8)) & 0xff; outbuf[2 + 0] = (n2 >> (2 * 8)) & 0xff; outbuf[3 + 0] = (n2 >> (3 * 8)) & 0xff; outbuf[0 + 4] = (n1 >> (0 * 8)) & 0xff; outbuf[1 + 4] = (n1 >> (1 * 8)) & 0xff; outbuf[2 + 4] = (n1 >> (2 * 8)) & 0xff; outbuf[3 + 4] = (n1 >> (3 * 8)) & 0xff; return /* burn_stack */ 4*sizeof(void*) /* func call */ + 3*sizeof(void*) /* stack */ + max( 4*sizeof(void*) /* gost_val call */, 3*sizeof(void*) /* gost_set_subst call */ + 2*sizeof(void*) /* gost_set subst stack*/ ); } gcry_cipher_spec_t _gcry_cipher_spec_gost28147 = { "GOST28147", NULL, NULL, 8, 256, sizeof (GOST28147_context), gost_setkey, gost_encrypt_block, gost_decrypt_block, }; diff --git a/cipher/gostr3411-94.c b/cipher/gostr3411-94.c index bfd52bd8..368fc015 100644 --- a/cipher/gostr3411-94.c +++ b/cipher/gostr3411-94.c @@ -1,274 +1,283 @@ /* gostr3411-94.c - GOST R 34.11-94 hash function * Copyright (C) 2012 Free Software Foundation, Inc. * * This file is part of Libgcrypt. * * Libgcrypt is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * Libgcrypt is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this program; if not, see . */ #include #include #include #include #include "g10lib.h" #include "bithelp.h" #include "cipher.h" #include "hash-common.h" #include "gost.h" +#define max(a, b) (((a) > (b)) ? (a) : (b)) + typedef struct { gcry_md_block_ctx_t bctx; GOST28147_context hd; byte h[32]; byte sigma[32]; u32 len; } GOSTR3411_CONTEXT; static unsigned int transform (void *c, const unsigned char *data); static void gost3411_init (void *context) { GOSTR3411_CONTEXT *hd = context; memset (&hd->hd, 0, sizeof(hd->hd)); memset (hd->h, 0, 32); memset (hd->sigma, 0, 32); hd->bctx.nblocks = 0; hd->bctx.count = 0; hd->bctx.blocksize = 32; hd->bctx.bwrite = transform; } static void do_p (unsigned char *p, unsigned char *u, unsigned char *v) { int i, k; for (k = 0; k < 8; k++) { for (i = 0; i < 4; i++) { p[i + 4 * k] = u[8 * i + k] ^ v[8 * i + k]; } } } static void do_a (unsigned char *u) { unsigned char temp[8]; int i; memcpy (temp, u, 8); memmove (u, u+8, 24); for (i = 0; i < 8; i++) { u[24 + i] = u[i] ^ temp[i]; } } /* apply do_a twice: 1 2 3 4 -> 3 4 1^2 2^3 */ static void do_a2 (unsigned char *u) { unsigned char temp[16]; int i; memcpy (temp, u, 16); memcpy (u, u + 16, 16); for (i = 0; i < 8; i++) { u[16 + i] = temp[i] ^ temp[8 + i]; u[24 + i] = u[i] ^ temp[8 + i]; } } static void do_apply_c2 (unsigned char *u) { u[ 1] ^= 0xff; u[ 3] ^= 0xff; u[ 5] ^= 0xff; u[ 7] ^= 0xff; u[ 8] ^= 0xff; u[10] ^= 0xff; u[12] ^= 0xff; u[14] ^= 0xff; u[17] ^= 0xff; u[18] ^= 0xff; u[20] ^= 0xff; u[23] ^= 0xff; u[24] ^= 0xff; u[28] ^= 0xff; u[29] ^= 0xff; u[31] ^= 0xff; } #define do_phi_step(e, i) \ e[(0 + 2*i) % 32] ^= e[(2 + 2*i) % 32] ^ e[(4 + 2*i) % 32] ^ e[(6 + 2*i) % 32] ^ e[(24 + 2*i) % 32] ^ e[(30 + 2*i) % 32]; \ e[(1 + 2*i) % 32] ^= e[(3 + 2*i) % 32] ^ e[(5 + 2*i) % 32] ^ e[(7 + 2*i) % 32] ^ e[(25 + 2*i) % 32] ^ e[(31 + 2*i) % 32]; static void do_phi_submix (unsigned char *e, unsigned char *x, int round) { int i; round *= 2; for (i = 0; i < 32; i++) { e[(i + round) % 32] ^= x[i]; } } static void do_add (unsigned char *s, unsigned char *a) { unsigned temp = 0; int i; for (i = 0; i < 32; i++) { temp = s[i] + a[i] + (temp >> 8); s[i] = temp & 0xff; } } -static void +static unsigned int do_hash_step (GOST28147_context *hd, unsigned char *h, unsigned char *m) { unsigned char u[32], v[32], s[32]; unsigned char k[32]; + unsigned int burn; int i; memcpy (u, h, 32); memcpy (v, m, 32); for (i = 0; i < 4; i++) { do_p (k, u, v); - _gcry_gost_enc_one (hd, k, s + i*8, h + i*8); + burn = _gcry_gost_enc_one (hd, k, s + i*8, h + i*8); do_a (u); if (i == 1) do_apply_c2 (u); do_a2 (v); } for (i = 0; i < 5; i++) { do_phi_step (s, 0); do_phi_step (s, 1); do_phi_step (s, 2); do_phi_step (s, 3); do_phi_step (s, 4); do_phi_step (s, 5); do_phi_step (s, 6); do_phi_step (s, 7); do_phi_step (s, 8); do_phi_step (s, 9); /* That is in total 12 + 1 + 61 = 74 = 16 * 4 + 10 rounds */ if (i == 4) break; do_phi_step (s, 10); do_phi_step (s, 11); if (i == 0) do_phi_submix(s, m, 12); do_phi_step (s, 12); if (i == 0) do_phi_submix(s, h, 13); do_phi_step (s, 13); do_phi_step (s, 14); do_phi_step (s, 15); } memcpy (h, s+20, 12); memcpy (h+12, s, 20); + + return /* burn_stack */ 4 * sizeof(void*) /* func call (ret addr + args) */ + + 4 * 32 + 2 * sizeof(int) /* stack */ + + max(burn /* _gcry_gost_enc_one */, + sizeof(void*) * 2 /* do_a2 call */ + + 16 + sizeof(int) /* do_a2 stack */ ); } static unsigned int transform (void *ctx, const unsigned char *data) { GOSTR3411_CONTEXT *hd = ctx; byte m[32]; + unsigned int burn; memcpy (m, data, 32); - do_hash_step (&hd->hd, hd->h, m); + burn = do_hash_step (&hd->hd, hd->h, m); do_add (hd->sigma, m); -/* FIXME: Fix this arbitrary value for the stack_burn size. -wk */ - return /* stack_burn */ 200; + return /* burn_stack */ burn + 3 * sizeof(void*) + 32 + 2 * sizeof(void*); } /* The routine finally terminates the computation and returns the digest. The handle is prepared for a new cycle, but adding bytes to the handle will the destroy the returned buffer. Returns: 32 bytes with the message the digest. */ static void gost3411_final (void *context) { GOSTR3411_CONTEXT *hd = context; size_t padlen = 0; byte l[32]; int i; u32 nblocks; if (hd->bctx.count > 0) { padlen = 32 - hd->bctx.count; memset (hd->bctx.buf + hd->bctx.count, 0, padlen); hd->bctx.count += padlen; _gcry_md_block_write (hd, NULL, 0); /* flush */; } if (hd->bctx.count != 0) return; /* Something went wrong */ memset (l, 0, 32); nblocks = hd->bctx.nblocks; if (padlen) { nblocks --; l[0] = 256 - padlen * 8; } for (i = 1; i < 32 && nblocks != 0; i++) { l[i] = nblocks % 256; nblocks /= 256; } do_hash_step (&hd->hd, hd->h, l); do_hash_step (&hd->hd, hd->h, hd->sigma); } static byte * gost3411_read (void *context) { GOSTR3411_CONTEXT *hd = context; return hd->h; } gcry_md_spec_t _gcry_digest_spec_gost3411_94 = { "GOSTR3411_94", NULL, 0, NULL, 32, gost3411_init, _gcry_md_block_write, gost3411_final, gost3411_read, sizeof (GOSTR3411_CONTEXT) };