From 0b2c8b09c6eb3ddce22fa88c34a640881f8f2177 Mon Sep 17 00:00:00 2001 From: Mounir IDRASSI Date: Tue, 9 Aug 2016 09:54:00 +0200 Subject: Windows: Add Magma cipher (GOST-89) --- src/Crypto/GostCipher.c | 269 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 269 insertions(+) create mode 100644 src/Crypto/GostCipher.c (limited to 'src/Crypto/GostCipher.c') diff --git a/src/Crypto/GostCipher.c b/src/Crypto/GostCipher.c new file mode 100644 index 00000000..a745210f --- /dev/null +++ b/src/Crypto/GostCipher.c @@ -0,0 +1,269 @@ +/** @file +GOST89 implementation + +Copyright (c) 2016. Disk Cryptography Services for EFI (DCS), Alex Kolotnikov + +This program and the accompanying materials +are licensed and made available under the terms and conditions +of the Apache License, Version 2.0. The full text of the license may be found at +https://opensource.org/licenses/Apache-2.0 + +Dynamic SBOX idea is from GostCrypt project. Copyright (c) 2008-2011 TrueCrypt Developers Association +**/ + + + +#include "GostCipher.h" +#include "Streebog.h" +#include "common\Tcdefs.h" +#include "cpu.h" + +#if defined(CIPHER_GOST89) + +// Crypto Pro +byte S_CryptoPro[8][16] = { + {0x1,0x3,0xA,0x9,0x5,0xB,0x4,0xF,0x8,0x6,0x7,0xE,0xD,0x0,0x2,0xC}, + {0xD,0xE,0x4,0x1,0x7,0x0,0x5,0xA,0x3,0xC,0x8,0xF,0x6,0x2,0x9,0xB}, + {0x7,0x6,0x2,0x4,0xD,0x9,0xF,0x0,0xA,0x1,0x5,0xB,0x8,0xE,0xC,0x3}, + {0x7,0x6,0x4,0xB,0x9,0xC,0x2,0xA,0x1,0x8,0x0,0xE,0xF,0xD,0x3,0x5}, + {0x4,0xA,0x7,0xC,0x0,0xF,0x2,0x8,0xE,0x1,0x6,0x5,0xD,0xB,0x9,0x3}, + {0x7,0xF,0xC,0xE,0x9,0x4,0x1,0x0,0x3,0xB,0x5,0x2,0x6,0xA,0x8,0xD}, + {0x5,0xF,0x4,0x0,0x2,0xD,0xB,0x9,0x1,0x7,0x6,0x3,0xC,0xE,0xA,0x8}, + {0xA,0x4,0x5,0x6,0x8,0x1,0x3,0x7,0xD,0xC,0xE,0x0,0x9,0x2,0xB,0xF} + }; + +// TC26 +byte S_TC26[8][16] = +{ + { 0xc, 0x4, 0x6, 0x2, 0xa, 0x5, 0xb, 0x9, 0xe, 0x8, 0xd, 0x7, 0x0, 0x3, 0xf, 0x1 }, + { 0x6, 0x8, 0x2, 0x3, 0x9, 0xa, 0x5, 0xc, 0x1, 0xe, 0x4, 0x7, 0xb, 0xd, 0x0, 0xf }, + { 0xb, 0x3, 0x5, 0x8, 0x2, 0xf, 0xa, 0xd, 0xe, 0x1, 0x7, 0x4, 0xc, 0x9, 0x6, 0x0 }, + { 0xc, 0x8, 0x2, 0x1, 0xd, 0x4, 0xf, 0x6, 0x7, 0x0, 0xa, 0x5, 0x3, 0xe, 0x9, 0xb }, + { 0x7, 0xf, 0x5, 0xa, 0x8, 0x1, 0x6, 0xd, 0x0, 0x9, 0x3, 0xe, 0xb, 0x4, 0x2, 0xc }, + { 0x5, 0xd, 0xf, 0x6, 0x9, 0x2, 0xc, 0xa, 0xb, 0x7, 0x8, 0x1, 0x4, 0x3, 0xe, 0x0 }, + { 0x8, 0xe, 0x2, 0x5, 0x6, 0x9, 0x1, 0xc, 0xf, 0x4, 0xb, 0x0, 0xd, 0xa, 0x3, 0x7 }, + { 0x1, 0x7, 0xe, 0xd, 0x0, 0x5, 0x8, 0x3, 0x4, 0xf, 0xa, 0x6, 0x9, 0xc, 0xb, 0x2 }, +}; + +void gost_prepare_kds(gost_kds* kds) { + uint32 i; + // Build substitution tables. + for (i = 0; i < 256; ++i) { + uint32 p; + p = kds->sbox[7][i >> 4] << 4 | kds->sbox[6][i & 15]; + p = p << 24; p = p << 11 | p >> 21; + kds->sbox_cvt[i] = p; // S87 + + p = kds->sbox[5][i >> 4] << 4 | kds->sbox[4][i & 15]; + p = p << 16; p = p << 11 | p >> 21; + kds->sbox_cvt[256 + i] = p; // S65 + + p = kds->sbox[3][i >> 4] << 4 | kds->sbox[2][i & 15]; + p = p << 8; p = p << 11 | p >> 21; + kds->sbox_cvt[256 * 2 + i] = p; // S43 + + p = kds->sbox[1][i >> 4] << 4 | kds->sbox[0][i & 15]; + p = p << 11 | p >> 21; + kds->sbox_cvt[256 * 3 + i] = p; // S21 + } +} + + +#ifdef GOST_DYNAMIC_SBOXES +static void xor_s_box(byte s_box[8][16], byte *seed) +{ + int i; + for (i = 0; i < 16; i++) + { + s_box[1][i] ^= (seed[ (i * 4) + 0 ] ) & 0xF; + s_box[2][i] ^= (seed[ (i * 4) + 0 ]>>4) & 0xF; + s_box[3][i] ^= (seed[ (i * 4) + 1 ] ) & 0xF; + s_box[4][i] ^= (seed[ (i * 4) + 1 ]>>4) & 0xF; + s_box[5][i] ^= (seed[ (i * 4) + 2 ] ) & 0xF; + s_box[6][i] ^= (seed[ (i * 4) + 2 ]>>4) & 0xF; + s_box[7][i] ^= (seed[ (i * 4) + 3 ] ) & 0xF; + s_box[8][i] ^= (seed[ (i * 4) + 3 ]>>4) & 0xF; + } +} +#endif + +void gost_set_key(byte *key, gost_kds *ks) +{ +#ifdef GOST_DYNAMIC_SBOXES + STREEBOG_CTX sctx; + byte sbox_seed[64]; +#if defined (DEVICE_DRIVER) && !defined (_WIN64) + KFLOATING_SAVE floatingPointState; + NTSTATUS saveStatus = STATUS_SUCCESS; + if (HasSSE2() || HasSSE41()) + saveStatus = KeSaveFloatingPointState (&floatingPointState); +#endif +#endif + + memcpy(ks->key, key, GOST_KEYSIZE); + memcpy(ks->sbox, S_TC26, sizeof(ks->sbox)); + +#ifdef GOST_DYNAMIC_SBOXES + //Generate pseudorandom data based on the key + STREEBOG_init(&sctx); + STREEBOG_add(&sctx, key, 32); + STREEBOG_finalize(&sctx, sbox_seed); + +#if defined (DEVICE_DRIVER) && !defined (_WIN64) + if (NT_SUCCESS (saveStatus) && (HasSSE2() || HasSSE41())) + KeRestoreFloatingPointState (&floatingPointState); +#endif + + xor_s_box(ks->sbox, sbox_seed); +#endif + + gost_prepare_kds(ks); +} + +static uint32 f(uint32 v, uint32* sbox){ + byte* x =(byte*) &v; + /* Do substitutions */ + return sbox[x[3]] | sbox[256 + x[2]] | sbox[256*2 + x[1]] | sbox[256*3 + x[0]]; +} + +void gost_encrypt_block(uint64 in_, uint64* out_, gost_kds* kds) { + uint32* in = (uint32*)&in_; + uint32* out = (uint32*)out_; + uint32* key = (uint32*)kds->key; + uint32* sbox = kds->sbox_cvt; + + // As named in the GOST + uint32 n1 = in[0]; + uint32 n2 = in[1]; + + n2 ^= f(n1+key[0], sbox); + n1 ^= f(n2+key[1], sbox); + n2 ^= f(n1+key[2], sbox); + n1 ^= f(n2+key[3], sbox); + n2 ^= f(n1+key[4], sbox); + n1 ^= f(n2+key[5], sbox); + n2 ^= f(n1+key[6], sbox); + n1 ^= f(n2+key[7], sbox); + + n2 ^= f(n1+key[0], sbox); + n1 ^= f(n2+key[1], sbox); + n2 ^= f(n1+key[2], sbox); + n1 ^= f(n2+key[3], sbox); + n2 ^= f(n1+key[4], sbox); + n1 ^= f(n2+key[5], sbox); + n2 ^= f(n1+key[6], sbox); + n1 ^= f(n2+key[7], sbox); + + n2 ^= f(n1+key[0], sbox); + n1 ^= f(n2+key[1], sbox); + n2 ^= f(n1+key[2], sbox); + n1 ^= f(n2+key[3], sbox); + n2 ^= f(n1+key[4], sbox); + n1 ^= f(n2+key[5], sbox); + n2 ^= f(n1+key[6], sbox); + n1 ^= f(n2+key[7], sbox); + + n2 ^= f(n1+key[7], sbox); + n1 ^= f(n2+key[6], sbox); + n2 ^= f(n1+key[5], sbox); + n1 ^= f(n2+key[4], sbox); + n2 ^= f(n1+key[3], sbox); + n1 ^= f(n2+key[2], sbox); + n2 ^= f(n1+key[1], sbox); + n1 ^= f(n2+key[0], sbox); + + // There is no swap after the last round + out[0] = n2; + out[1] = n1; +} + +void gost_decrypt_block(uint64 in_, uint64* out_, gost_kds* kds) { + uint32* in = (uint32*)&in_; + uint32* out = (uint32*)out_; + uint32* key = (uint32*)kds->key; + uint32* sbox = kds->sbox_cvt; + + // As named in the GOST + uint32 n1 = in[0]; + uint32 n2 = in[1]; + + n2 ^= f(n1+key[0], sbox); + n1 ^= f(n2+key[1], sbox); + n2 ^= f(n1+key[2], sbox); + n1 ^= f(n2+key[3], sbox); + n2 ^= f(n1+key[4], sbox); + n1 ^= f(n2+key[5], sbox); + n2 ^= f(n1+key[6], sbox); + n1 ^= f(n2+key[7], sbox); + + n2 ^= f(n1+key[7], sbox); + n1 ^= f(n2+key[6], sbox); + n2 ^= f(n1+key[5], sbox); + n1 ^= f(n2+key[4], sbox); + n2 ^= f(n1+key[3], sbox); + n1 ^= f(n2+key[2], sbox); + n2 ^= f(n1+key[1], sbox); + n1 ^= f(n2+key[0], sbox); + + n2 ^= f(n1+key[7], sbox); + n1 ^= f(n2+key[6], sbox); + n2 ^= f(n1+key[5], sbox); + n1 ^= f(n2+key[4], sbox); + n2 ^= f(n1+key[3], sbox); + n1 ^= f(n2+key[2], sbox); + n2 ^= f(n1+key[1], sbox); + n1 ^= f(n2+key[0], sbox); + + n2 ^= f(n1+key[7], sbox); + n1 ^= f(n2+key[6], sbox); + n2 ^= f(n1+key[5], sbox); + n1 ^= f(n2+key[4], sbox); + n2 ^= f(n1+key[3], sbox); + n1 ^= f(n2+key[2], sbox); + n2 ^= f(n1+key[1], sbox); + n1 ^= f(n2+key[0], sbox); + + out[0] = n2; + out[1] = n1; +} + +#if defined(_M_AMD64) +void gost_encrypt_128_CBC_asm(byte *in, byte *out, gost_kds *ks, uint64 count); +void gost_decrypt_128_CBC_asm(byte *in, byte *out, gost_kds *ks, uint64 count); +#endif + +void gost_encrypt(byte *in, byte *out, gost_kds *ks, int count) { +#if defined(_M_AMD64) + gost_encrypt_128_CBC_asm(in, out, ks, (uint64)count); +#else + while (count > 0) { + // encrypt two blocks in CBC mode + gost_encrypt_block(*((uint64*)in), (uint64*)out, ks); + *((gst_udword*)(out + 8)) = *((gst_udword*)(in + 8)) ^ *((gst_udword*)(out)); + *((gst_udword*)(out + 12)) = *((gst_udword*)(in + 12)) ^ *((gst_udword*)(out + 4)); + gost_encrypt_block(*((uint64*)(out + 8)), (uint64*)(out + 8), ks); + count--; + in += 16; + out += 16; + } +#endif +} + +void gost_decrypt(byte *in, byte *out, gost_kds *ks, int count) { +#if defined(_M_AMD64) + gost_decrypt_128_CBC_asm(in, out, ks, (uint64)count); +#else + while (count > 0) { + // decrypt two blocks in CBC mode + gost_decrypt_block(*((uint64*)(in + 8)), (uint64*)(out + 8), ks); + *((gst_udword*)(out + 8)) ^= *((gst_udword*)(in));; + *((gst_udword*)(out + 12)) ^= *((gst_udword*)(in + 4));; + gost_decrypt_block(*((uint64*)(in)), (uint64*)(out), ks); + count--; + in += 16; + out += 16; + } +#endif +} + +#endif \ No newline at end of file -- cgit v1.2.3