diff options
-rw-r--r-- | cipher/Makefile.am | 1 | ||||
-rw-r--r-- | cipher/cipher.c | 4 | ||||
-rw-r--r-- | cipher/gost.h | 33 | ||||
-rw-r--r-- | cipher/gost28147.c | 220 | ||||
-rw-r--r-- | configure.ac | 8 | ||||
-rw-r--r-- | doc/gcrypt.texi | 5 | ||||
-rw-r--r-- | src/cipher.h | 1 | ||||
-rw-r--r-- | src/gcrypt.h.in | 3 | ||||
-rw-r--r-- | tests/basic.c | 3 |
9 files changed, 276 insertions, 2 deletions
diff --git a/cipher/Makefile.am b/cipher/Makefile.am index 3dd6f88f..f3bd71ca 100644 --- a/cipher/Makefile.am +++ b/cipher/Makefile.am @@ -62,6 +62,7 @@ dsa.c \ elgamal.c \ ecc.c ecc-curves.c ecc-misc.c ecc-common.h \ idea.c \ +gost28147.c gost.h \ md4.c \ md5.c \ rijndael.c rijndael-tables.h rijndael-amd64.S rijndael-armv6.S \ diff --git a/cipher/cipher.c b/cipher/cipher.c index 6ddd58be..a17ca9b2 100644 --- a/cipher/cipher.c +++ b/cipher/cipher.c @@ -110,6 +110,10 @@ static struct cipher_table_entry { &_gcry_cipher_spec_salsa20r12, &_gcry_cipher_extraspec_salsa20, GCRY_CIPHER_SALSA20R12 }, #endif +#if USE_GOST28147 + { &_gcry_cipher_spec_gost28147, + &dummy_extra_spec, GCRY_CIPHER_GOST28147 }, +#endif { NULL } }; diff --git a/cipher/gost.h b/cipher/gost.h new file mode 100644 index 00000000..e1cf033e --- /dev/null +++ b/cipher/gost.h @@ -0,0 +1,33 @@ +/* gost.h - GOST 28147-89 implementation + * 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 <http://www.gnu.org/licenses/>. + */ + +#ifndef _GCRY_GOST_H +#define _GCRY_GOST_H + +typedef struct { + u32 subst[4][256]; + u32 key[8]; + int subst_set; +} GOST28147_context; + +/* This is a simple interface that will be used by GOST R 34.11-94 */ +extern void _gcry_gost_enc_one (GOST28147_context *c, const byte *key, + byte *out, byte *in); + +#endif diff --git a/cipher/gost28147.c b/cipher/gost28147.c new file mode 100644 index 00000000..5d6d1e73 --- /dev/null +++ b/cipher/gost28147.c @@ -0,0 +1,220 @@ +/* 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 <http://www.gnu.org/licenses/>. + */ + +/* 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 <config.h> +#include "types.h" +#include "g10lib.h" +#include "cipher.h" + + +/* 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 void +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; +} + +void _gcry_gost_enc_one (GOST28147_context *c, const byte *key, + byte *out, byte *in) +{ + gost_setkey (c, key, 32); + gost_encrypt_block (c, out, in); +} + +static void +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; +} + +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/configure.ac b/configure.ac index 8deb4481..a1f7dfa9 100644 --- a/configure.ac +++ b/configure.ac @@ -184,7 +184,7 @@ LIBGCRYPT_CONFIG_HOST="$host" # Definitions for symmetric ciphers. available_ciphers="arcfour blowfish cast5 des aes twofish serpent rfc2268 seed" -available_ciphers="$available_ciphers camellia idea salsa20" +available_ciphers="$available_ciphers camellia idea salsa20 gost28147" enabled_ciphers="" # Definitions for public-key ciphers. @@ -1501,6 +1501,12 @@ if test "$found" = "1" ; then AC_DEFINE(USE_SALSA20, 1, [Defined if this module should be included]) fi +LIST_MEMBER(gost28147, $enabled_ciphers) +if test "$found" = "1" ; then + GCRYPT_CIPHERS="$GCRYPT_CIPHERS gost28147.lo" + AC_DEFINE(USE_GOST28147, 1, [Defined if this module should be included]) +fi + LIST_MEMBER(dsa, $enabled_pubkey_ciphers) if test "$found" = "1" ; then GCRYPT_PUBKEY_CIPHERS="$GCRYPT_PUBKEY_CIPHERS dsa.lo" diff --git a/doc/gcrypt.texi b/doc/gcrypt.texi index 63fd5963..580ddf80 100644 --- a/doc/gcrypt.texi +++ b/doc/gcrypt.texi @@ -1583,6 +1583,11 @@ This is the Salsa20 stream cipher. @cindex Salsa20/12 This is the Salsa20/12 - reduced round version of Salsa20 stream cipher. +@item GCRY_CIPHER_GOST28147 +@cindex GOST 28147-89 +The GOST 28147-89 cipher, defined in the respective GOST standard. +Translation of this GOST into English is provided in the RFC-5830. + @end table @node Available cipher modes diff --git a/src/cipher.h b/src/cipher.h index 7791083b..34fc2e8a 100644 --- a/src/cipher.h +++ b/src/cipher.h @@ -200,6 +200,7 @@ extern gcry_cipher_spec_t _gcry_cipher_spec_camellia256; extern gcry_cipher_spec_t _gcry_cipher_spec_idea; extern gcry_cipher_spec_t _gcry_cipher_spec_salsa20; extern gcry_cipher_spec_t _gcry_cipher_spec_salsa20r12; +extern gcry_cipher_spec_t _gcry_cipher_spec_gost28147; extern cipher_extra_spec_t _gcry_cipher_extraspec_tripledes; extern cipher_extra_spec_t _gcry_cipher_extraspec_aes; diff --git a/src/gcrypt.h.in b/src/gcrypt.h.in index 71ea0730..b87dd0e0 100644 --- a/src/gcrypt.h.in +++ b/src/gcrypt.h.in @@ -845,7 +845,8 @@ enum gcry_cipher_algos GCRY_CIPHER_CAMELLIA192 = 311, GCRY_CIPHER_CAMELLIA256 = 312, GCRY_CIPHER_SALSA20 = 313, - GCRY_CIPHER_SALSA20R12 = 314 + GCRY_CIPHER_SALSA20R12 = 314, + GCRY_CIPHER_GOST28147 = 315 }; /* The Rijndael algorithm is basically AES, so provide some macros. */ diff --git a/tests/basic.c b/tests/basic.c index 26c85caf..527c8ae9 100644 --- a/tests/basic.c +++ b/tests/basic.c @@ -2379,6 +2379,9 @@ check_ciphers (void) #if USE_IDEA GCRY_CIPHER_IDEA, #endif +#if USE_GOST28147 + GCRY_CIPHER_GOST28147, +#endif 0 }; static int algos2[] = { |