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/Common/Crypto.c | 36 ++- src/Common/Crypto.h | 8 +- src/Common/Tests.c | 13 +- src/Crypto/Crypto.vcxproj | 12 + src/Crypto/Crypto.vcxproj.filters | 9 + src/Crypto/GostCipher.c | 269 +++++++++++++++++++++ src/Crypto/GostCipher.h | 61 +++++ src/Crypto/Makefile.inc | 3 + src/Crypto/Sources | 5 +- src/Crypto/gost89_x64.asm | 481 ++++++++++++++++++++++++++++++++++++++ src/Crypto/gost89_x86.asm | 0 11 files changed, 889 insertions(+), 8 deletions(-) create mode 100644 src/Crypto/GostCipher.c create mode 100644 src/Crypto/GostCipher.h create mode 100644 src/Crypto/gost89_x64.asm create mode 100644 src/Crypto/gost89_x86.asm diff --git a/src/Common/Crypto.c b/src/Common/Crypto.c index dea4ff02..16115bf6 100644 --- a/src/Common/Crypto.c +++ b/src/Common/Crypto.c @@ -23,6 +23,7 @@ #include "Volumes.h" #include "cpu.h" +#pragma warning (disable:4706) // assignment within conditional expression /* Update the following when adding a new cipher or EA: Crypto.h: @@ -54,6 +55,9 @@ static Cipher Ciphers[] = { SERPENT, L"Serpent", 16, 32, 140*4 }, { TWOFISH, L"Twofish", 16, 32, TWOFISH_KS }, { CAMELLIA, L"Camellia", 16, 32, CAMELLIA_KS }, +#if defined(CIPHER_GOST89) + { GOST89, L"GOST89", 16, 32, GOST_KS }, +#endif // defined(CIPHER_GOST89) #endif { 0, 0, 0, 0, 0 } }; @@ -71,6 +75,9 @@ static EncryptionAlgorithm EncryptionAlgorithms[] = { { SERPENT, 0 }, { XTS, 0 }, 1 }, { { TWOFISH, 0 }, { XTS, 0 }, 1 }, { { CAMELLIA, 0 }, { XTS, 0 }, 1 }, +#if defined(CIPHER_GOST89) + { { GOST89, 0 }, { XTS, 0 }, 1 }, +#endif // defined(CIPHER_GOST89) { { TWOFISH, AES, 0 }, { XTS, 0 }, 1 }, { { SERPENT, TWOFISH, AES, 0 }, { XTS, 0 }, 1 }, { { AES, SERPENT, 0 }, { XTS, 0 }, 1 }, @@ -143,6 +150,14 @@ int CipherInit (int cipher, unsigned char *key, unsigned __int8 *ks) break; #endif +#if !defined(TC_WINDOWS_BOOT) +#if defined(CIPHER_GOST89) + case GOST89: + gost_set_key(key, (gost_kds*)ks); + break; +#endif // && defined(CIPHER_GOST89) +#endif // !defined(TC_WINDOWS_BOOT) + default: // Unknown/wrong cipher ID return ERR_CIPHER_INIT_FAILURE; @@ -170,6 +185,11 @@ void EncipherBlock(int cipher, void *data, void *ks) #if !defined (TC_WINDOWS_BOOT) || defined (TC_WINDOWS_BOOT_CAMELLIA) case CAMELLIA: camellia_encrypt (data, data, ks); break; #endif +#if !defined(TC_WINDOWS_BOOT) +#if defined(CIPHER_GOST89) + case GOST89: gost_encrypt(data, data, ks, 1); break; +#endif // defined(CIPHER_GOST89) +#endif // !defined(TC_WINDOWS_BOOT) default: TC_THROW_FATAL_EXCEPTION; // Unknown/wrong ID } } @@ -203,6 +223,9 @@ void EncipherBlocks (int cipher, void *dataPtr, void *ks, size_t blockCount) KeRestoreFloatingPointState (&floatingPointState); #endif } + else if (cipher == GOST89) { + gost_encrypt(data, data, ks, (int)blockCount); + } else { size_t blockSize = CipherGetBlockSize (cipher); @@ -225,6 +248,13 @@ void DecipherBlock(int cipher, void *data, void *ks) #if !defined (TC_WINDOWS_BOOT) || defined (TC_WINDOWS_BOOT_CAMELLIA) case CAMELLIA: camellia_decrypt (data, data, ks); break; #endif +#if !defined(TC_WINDOWS_BOOT) +#if defined(CIPHER_GOST89) + case GOST89: gost_decrypt(data, data, ks, 1); break; +#endif // defined(CIPHER_GOST89) +#endif // !defined(TC_WINDOWS_BOOT) + + #ifndef TC_WINDOWS_BOOT case AES: @@ -272,6 +302,9 @@ void DecipherBlocks (int cipher, void *dataPtr, void *ks, size_t blockCount) KeRestoreFloatingPointState (&floatingPointState); #endif } + else if (cipher == GOST89) { + gost_decrypt(data, data, ks, (int)blockCount); + } else { size_t blockSize = CipherGetBlockSize (cipher); @@ -340,7 +373,8 @@ int CipherGetKeyScheduleSize (int cipherId) BOOL CipherSupportsIntraDataUnitParallelization (int cipher) { - return cipher == AES && IsAesHwCpuSupported(); + return cipher == AES && IsAesHwCpuSupported() || + cipher == GOST89; } #endif diff --git a/src/Common/Crypto.h b/src/Common/Crypto.h index 28b5f8c4..9b5fbace 100644 --- a/src/Common/Crypto.h +++ b/src/Common/Crypto.h @@ -107,7 +107,8 @@ enum AES, SERPENT, TWOFISH, - CAMELLIA + CAMELLIA, + GOST89 }; typedef struct @@ -189,9 +190,10 @@ typedef struct #ifndef TC_WINDOWS_BOOT # include "Sha2.h" # include "Whirlpool.h" -# include "Camellia.h" +# include "GostCipher.h" +# include "Camellia.h" #else -# include "CamelliaSmall.h" +# include "CamelliaSmall.h" #endif #include "GfMul.h" diff --git a/src/Common/Tests.c b/src/Common/Tests.c index 81ba4161..02f893c7 100644 --- a/src/Common/Tests.c +++ b/src/Common/Tests.c @@ -497,7 +497,11 @@ void CipherInit2(int cipher, void* key, void* ks, int key_len) case CAMELLIA: CipherInit(cipher,key,ks); break; - +#if defined(CIPHER_GOST89) + case GOST89: + CipherInit(cipher,key,ks); + break; +#endif // defined(CIPHER_GOST89) default: /* Unknown/wrong ID */ TC_THROW_FATAL_EXCEPTION; @@ -925,8 +929,11 @@ BOOL TestSectorBufEncryption (PCRYPTO_INFO ci) nTestsPerformed++; } - - return (nTestsPerformed == 90); +#if defined(CIPHER_GOST89) + return (nTestsPerformed == 100); +#else + return (nTestsPerformed == 95); +#endif } static BOOL DoAutoTestAlgorithms (void) diff --git a/src/Crypto/Crypto.vcxproj b/src/Crypto/Crypto.vcxproj index 8810adf1..f502458f 100644 --- a/src/Crypto/Crypto.vcxproj +++ b/src/Crypto/Crypto.vcxproj @@ -199,6 +199,16 @@ $(TargetDir)\%(Filename).obj;%(Outputs) true echo %(Filename)%(Extension) & nasm.exe -Xvc -f win32 -Ox --prefix _ -o "$(TargetDir)\%(Filename).obj" -l "$(TargetDir)\%(Filename).lst" "%(FullPath)" + + $(TargetDir)\%(Filename).obj;%(Outputs) + + + true + echo %(Filename)%(Extension) & nasm.exe -Xvc -f win64 -Ox -o "$(TargetDir)\%(Filename).obj" -l "$(TargetDir)\%(Filename).lst" "%(FullPath)" + + $(TargetDir)\%(Filename).obj;%(Outputs) + true + echo %(Filename)%(Extension) & nasm.exe -Xvc -f win64 -Ox -o "$(TargetDir)\%(Filename).obj" -l "$(TargetDir)\%(Filename).lst" "%(FullPath)" $(TargetDir)\%(Filename).obj;%(Outputs) @@ -208,6 +218,7 @@ + @@ -222,6 +233,7 @@ + diff --git a/src/Crypto/Crypto.vcxproj.filters b/src/Crypto/Crypto.vcxproj.filters index 41b640f3..c05e7fc7 100644 --- a/src/Crypto/Crypto.vcxproj.filters +++ b/src/Crypto/Crypto.vcxproj.filters @@ -42,6 +42,9 @@ Source Files + + Source Files + @@ -83,6 +86,9 @@ Header Files + + Header Files + @@ -94,5 +100,8 @@ Source Files + + Source Files + \ No newline at end of file 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 diff --git a/src/Crypto/GostCipher.h b/src/Crypto/GostCipher.h new file mode 100644 index 00000000..9b9e18b4 --- /dev/null +++ b/src/Crypto/GostCipher.h @@ -0,0 +1,61 @@ + +/* + Copyright (c) 2008-2011 TrueCrypt Developers Association. All rights reserved. + + Governed by the TrueCrypt License 3.0 the full text of which is contained in + the file License.txt included in TrueCrypt binary and source code distribution + packages. +*/ + + + +#ifndef GOST_CIPHER_H +#define GOST_CIPHER_H + +//In unsigned chars +#define GOST_KEYSIZE 32 +#define GOST_BLOCKSIZE 8 +#define GOST_SBOX_SIZE 16 + +//Production setting, but can be turned off to compare the algorithm with other implementations +#define CIPHER_GOST89 +#define GOST_DYNAMIC_SBOXES + +#if defined(CIPHER_GOST89) + +#ifndef rotl32 +#define rotl32(b, shift) ((b << shift) | (b >> (32 - shift))) +#endif + +typedef unsigned char byte; +#ifdef GST_WINDOWS_BOOT +typedef int gst_word; +typedef long gst_dword; +typedef unsigned int gst_uword; +typedef unsigned long gst_udword; +#else +typedef short gst_word; +typedef int gst_dword; +typedef unsigned short gst_uword; +typedef unsigned int gst_udword; +#endif + +typedef struct gost_kds +{ + byte key[32]; + gst_udword sbox_cvt[256 * 4]; + byte sbox[8][16]; +} gost_kds; + +#define GOST_KS (sizeof(gost_kds)) + +void gost_encrypt(byte *in, byte *out, gost_kds *ks, int count); +void gost_decrypt(byte *in, byte *out, gost_kds *ks, int count); +void gost_set_key(byte *key, gost_kds *ks); + +#else +#define GOST_KS (0) +#endif + + +#endif diff --git a/src/Crypto/Makefile.inc b/src/Crypto/Makefile.inc index 955f2a76..bd5b80d9 100644 --- a/src/Crypto/Makefile.inc +++ b/src/Crypto/Makefile.inc @@ -8,6 +8,9 @@ TC_ASFLAGS = $(TC_ASFLAGS) -f win64 TC_ASM_ERR_LOG = ..\Driver\build_errors_asm.log +"$(OBJ_PATH)\$(O)\gost89_$(TC_ARCH).obj": gost89_$(TC_ARCH).asm + nasm.exe $(TC_ASFLAGS) -o "$@" -l "$(OBJ_PATH)\$(O)\gost89_$(TC_ARCH).lst" gost89_$(TC_ARCH).asm 2>$(TC_ASM_ERR_LOG) + "$(OBJ_PATH)\$(O)\Aes_$(TC_ARCH).obj": Aes_$(TC_ARCH).asm nasm.exe $(TC_ASFLAGS) -o "$@" -l "$(OBJ_PATH)\$(O)\Aes_$(TC_ARCH).lst" Aes_$(TC_ARCH).asm 2>$(TC_ASM_ERR_LOG) diff --git a/src/Crypto/Sources b/src/Crypto/Sources index ae16662c..af6479f4 100644 --- a/src/Crypto/Sources +++ b/src/Crypto/Sources @@ -5,10 +5,12 @@ INCLUDES = .. NTTARGETFILES = \ "$(OBJ_PATH)\$(O)\Aes_$(TC_ARCH).obj" \ - "$(OBJ_PATH)\$(O)\Aes_hw_cpu.obj" + "$(OBJ_PATH)\$(O)\Aes_hw_cpu.obj" \ + "$(OBJ_PATH)\$(O)\gost89_$(TC_ARCH).obj" SOURCES = \ Aes_$(TC_ARCH).asm \ + gost89_$(TC_ARCH).asm \ Aes_hw_cpu.asm \ Aeskey.c \ Aestab.c \ @@ -17,5 +19,6 @@ SOURCES = \ Serpent.c \ Sha2.c \ Twofish.c \ + GostCipher.c \ Whirlpool.c \ Camellia.c diff --git a/src/Crypto/gost89_x64.asm b/src/Crypto/gost89_x64.asm new file mode 100644 index 00000000..f2e49cb7 --- /dev/null +++ b/src/Crypto/gost89_x64.asm @@ -0,0 +1,481 @@ +; +; GOST89 implementation x64 +; +; 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 +; +; Some ideas from article https://xakep.ru/2013/10/19/shifrovanie-gost-28147-89/ +; + +[section .bss align=16] + +;/////////////////////////////////////////////////////////////////// +;// Win64 registers to save +;/////////////////////////////////////////////////////////////////// +%macro SaveRegs 0 + sub rsp,8*8+10*16 + mov [rsp], rbx + mov [rsp+8], rbp + mov [rsp+8*2], rdi + mov [rsp+8*3], rsi + mov [rsp+8*4], r12 + mov [rsp+8*5], r13 + mov [rsp+8*6], r14 + mov [rsp+8*7], r15 +%endmacro + +%macro RestoreRegs 0 + mov rbx, [rsp] + mov rbp, [rsp+8] + mov rdi, [rsp+8*2] + mov rsi, [rsp+8*3] + mov r12, [rsp+8*4] + mov r13, [rsp+8*5] + mov r14, [rsp+8*6] + mov r15, [rsp+8*7] + add rsp,8*8+10*16 +%endmacro + +[section .text align=16] +;/////////////////////////////////////////////////////////////////// +;// Crypting 2 blocks +;/////////////////////////////////////////////////////////////////// +%macro gost_round2 2 ; 1 - pos1, 2 - pos2 + ; 1st + ; 1-2 byte + add ecx, r13d ; add key + movzx edi, cl + movzx esi, ch + xor r14d, dword [r8 + 32 + 256*3*4 + rdi*4] + xor r14d, dword [r8 + 32 + 256*2*4 + rsi*4] + shr ecx, 16 + ; 3-4 байт + movzx edi, cl + xor r14d, dword [r8 + 32 + 256*4 + rdi*4] + movzx esi, ch + xor r14d, dword [r8 + 32 + rsi*4] + mov edx, [r8 + %1*4] ; read key for second step + + ; 2nd + ; 1-2 byte + add eax, r10d ; read key + movzx r15d, al + movzx ebp, ah + xor r11d, dword [r8 + 32 + 256*3*4 + r15*4] + xor r11d, dword [r8 + 32 + 256*2*4 + rbp*4] + shr eax, 16 + ; 3-4 байт + movzx r15d, al + xor r11d, dword [r8 + 32 + 256*4 + r15*4] + movzx ebp, ah + xor r11d, dword [r8 + 32 + rbp*4] + mov ebx, [r8 + %1*4] ; read key for second step + + ; second step + ; 1st + ; 1-2 byte + add edx, r14d ; add key + movzx edi, dl + movzx esi, dh + xor r13d, dword [r8 + 32 + 256*3*4 + rdi*4] + xor r13d, dword [r8 + 32 + 256*2*4 + rsi*4] + shr edx, 16 + ; 3-4 байт + movzx edi, dl + xor r13d, dword [r8 + 32 + 256*4 + rdi*4] + movzx esi, dh + xor r13d, dword [r8 + 32 + rsi*4] + mov ecx, [r8 + %2*4] ; read key + + ; 2nd + ; 1-2 byte + add ebx, r11d; ; add key + movzx r15d, bl; + movzx ebp, bh; + xor r10d, dword [r8 + 32 + 256*3*4 + r15*4] + xor r10d, dword [r8 + 32 + 256*2*4 + rbp*4] + shr ebx, 16 + ; 3-4 байт + movzx r15d, bl + xor r10d, dword [r8 + 32 + 256*4 + r15*4] + movzx ebp, bh + xor r10d, dword [r8 + 32 + rbp*4] + mov eax, [r8 + %2*4] ; read key +%endmacro + +; input: r8 - &key, rdx - &IN +; returns: (r13) & (r10) +GostEncrypt2x64: + ; 1st + mov r13d, [rdx] + mov r14, [rdx] + shr r14, 32 + + ; 2nd + mov r10d, [rdx + 16] + mov r11, [rdx + 16] + shr r11, 32 + + mov ecx, [r8] + mov eax, ecx + + gost_round2 1, 2 + gost_round2 3, 4 + gost_round2 5, 6 + gost_round2 7, 0 + + gost_round2 1, 2 + gost_round2 3, 4 + gost_round2 5, 6 + gost_round2 7, 0 + + gost_round2 1, 2 + gost_round2 3, 4 + gost_round2 5, 6 + gost_round2 7, 7 + + gost_round2 6, 5 + gost_round2 4, 3 + gost_round2 2, 1 + gost_round2 0, 0 + + shl r13, 32 ; combine + or r13, r14 + + shl r10, 32 ; combine + or r10, r11 + ret + +; input: r8 - &key, rdx - &IN +; returns: (r13) & (r10) +GostDecrypt2x64: + ; 1st + mov r13d, [rdx] + mov r14, [rdx] + shr r14, 32 + + ; 2nd + mov r10d, [rdx + 16] + mov r11, [rdx + 16] + shr r11, 32 + + mov ecx, [r8] + mov eax, ecx + + gost_round2 1, 2 + gost_round2 3, 4 + gost_round2 5, 6 + gost_round2 7, 7 + + gost_round2 6, 5 + gost_round2 4, 3 + gost_round2 2, 1 + gost_round2 0, 7 + + gost_round2 6, 5 + gost_round2 4, 3 + gost_round2 2, 1 + gost_round2 0, 7 + + gost_round2 6, 5 + gost_round2 4, 3 + gost_round2 2, 1 + gost_round2 0, 0 + + shl r13, 32 ; combine + or r13, r14 + + shl r10, 32 ; combine + or r10, r11 +ret + +;/////////////////////////////////////////////////////////////////// +;// Crypting 1 block +;/////////////////////////////////////////////////////////////////// +%macro gost_round1 2 ; 1 - pos1, 2 - pos2 + ; 1-2 byte + add ecx, r13d ; add key + movzx edi, cl + movzx esi, ch + xor r14d, dword [r8 + 32 + 256*3*4 + rdi*4] + xor r14d, dword [r8 + 32 + 256*2*4 + rsi*4] + shr ecx, 16 + ; 3-4 байт + movzx edi, cl + xor r14d, dword [r8 + 32 + 256*4 + rdi*4] + movzx esi, ch + xor r14d, dword [r8 + 32 + rsi*4] + mov edx, [r8 + %1*4] ; read key for second step + + ; second step + ; 1-2 byte + add edx, r14d ; add key + movzx edi, dl + movzx esi, dh + xor r13d, dword [r8 + 32 + 256*3*4 + rdi*4] + xor r13d, dword [r8 + 32 + 256*2*4 + rsi*4] + shr edx, 16 + ; 3-4 байт + movzx edi, dl + xor r13d, dword [r8 + 32 + 256*4 + rdi*4] + movzx esi, dh + xor r13d, dword [r8 + 32 + rsi*4] + mov ecx, [r8 + %2*4] ; read key +%endmacro + +; input: r8 - &gost_kds rdx - &IN +; returns: r13 +GostEncrypt1x64: + mov r13d, [rdx] + mov r14, [rdx] + shr r14, 32 + mov ecx, [r8] + + gost_round1 1, 2 + gost_round1 3, 4 + gost_round1 5, 6 + gost_round1 7, 0 + + gost_round1 1, 2 + gost_round1 3, 4 + gost_round1 5, 6 + gost_round1 7, 0 + + gost_round1 1, 2 + gost_round1 3, 4 + gost_round1 5, 6 + gost_round1 7, 7 + + gost_round1 6, 5 + gost_round1 4, 3 + gost_round1 2, 1 + gost_round1 0, 0 + + shl r13, 32 ; combine + or r13, r14 +ret + +; input: r8 - &gost_kds rdx - IN +; returns: r13 +GostDecrypt1x64: + mov r13d, [rdx] + mov r14, [rdx] + shr r14, 32 + mov ecx, [r8] + + gost_round1 1, 2 + gost_round1 3, 4 + gost_round1 5, 6 + gost_round1 7, 7 + + gost_round1 6, 5 + gost_round1 4, 3 + gost_round1 2, 1 + gost_round1 0, 7 + + gost_round1 6, 5 + gost_round1 4, 3 + gost_round1 2, 1 + gost_round1 0, 7 + + gost_round1 6, 5 + gost_round1 4, 3 + gost_round1 2, 1 + gost_round1 0, 0 + + shl r13, 32 ; combine + or r13, r14 +ret + +global gost_encrypt_128_CBC_asm ; gost_encrypt_128_CBC_asm(uint64* out, uint64* in, gost_kds* kds, uint64 count); +; rcx - &out +; rdx - &in +; r8 - &gost_kds +; r9 - count +gost_encrypt_128_CBC_asm: + SaveRegs ; Saving + + sub rsp, 32 + mov [rsp], rcx ; Save out addr + mov [rsp + 8], rdx ; Save in addr + mov [rsp + 16], r8 ; key addr + +.do: + mov [rsp + 24], r9 ; Save count + cmp r9, 2 + jge .blk2 + cmp r9, 1 + jge .blk1 + jmp .end + +; One 128 block encryption +.blk1: + mov rdx, [rsp + 8] ; set in addr + call GostEncrypt1x64 + + mov rcx, [rsp] ; Restore out + mov rdx, [rsp + 8] ; restore in + + mov [rcx], r13 + mov rax, [rdx + 8] + xor rax, r13 ; CBC + + add rcx, 8 ;next 8 bytes + mov [rcx], rax + + mov rdx, rcx + call GostEncrypt1x64 + + mov rcx, [rsp] ; Restore out addr + mov rdx, [rsp+8] ; Restore in addr + + mov [rcx + 8], r13 + + add rcx,16 + mov [rsp], rcx + + add rdx, 16 + mov [rsp+8], rdx + + mov r9, [rsp + 24] + dec r9 + + jmp .do + +.blk2: + mov rdx, [rsp + 8] ; set in addr + call GostEncrypt2x64 + + mov rcx, [rsp] ; Restore out + mov rdx, [rsp + 8] ; restore in + + mov [rcx], r13 + + mov rax, [rdx + 8] + xor rax, r13 ; CBC + + mov [rcx + 16], r10 + + mov rbx, [rdx + 24] + xor rbx, r10 ; CBC + + mov [rcx + 8], rax + mov [rcx + 24], rbx + + add rcx, 8 ;next 8 bytes + + mov rdx, rcx + call GostEncrypt2x64 + + mov rcx, [rsp] ; Restore out addr + mov rdx, [rsp+8] ; Restore in addr + + mov [rcx + 8], r13 + mov [rcx + 24], r10 + + add rcx,32 + mov [rsp], rcx + + add rdx, 32 + mov [rsp+8], rdx + + mov r9, [rsp + 24] + sub r9, 2 + + jmp .do + +.end: + add rsp, 32 ; Load out addr + RestoreRegs ; Load +ret + +global gost_decrypt_128_CBC_asm ; gost_decrypt_128_CBC_asm(uint64* out, uint64* in, const gost_kds* kds, uint64 count); +; rcx - &out +; rdx - &in +; r8 - &gost_kds +; r9 - count +gost_decrypt_128_CBC_asm: + SaveRegs ; Saving + + sub rsp, 32 + mov [rsp], rdx ; Save out addr + mov [rsp+8], rcx ; Save in addr + mov [rsp+16], r8 ; key addr + +.do: + mov [rsp + 24], r9 ; Save count + cmp r9, 2 + jge .blk2 + cmp r9, 1 + jge .blk1 + jmp .end + +; One 128 block decryption +.blk1: + add rdx, 8 + call GostDecrypt1x64 + mov rcx, [rsp] ; Restore out + mov rdx, [rsp + 8] ; Restore in + mov rax, [rdx] + xor rax, r13 ; CBC + mov [rcx + 8], rax + + call GostDecrypt1x64 + + mov rcx, [rsp] ; Restore out addr + mov rdx, [rsp+8] ; Restore in addr + + mov [rcx], r13 + + add rcx,16 + mov [rsp], rcx + + add rdx, 16 + mov [rsp+8], rdx + + mov r9, [rsp + 24] + dec r9 + + jmp .do + +.blk2: + add rdx, 8 + call GostDecrypt2x64 + mov rcx, [rsp] ; Restore out + mov rdx, [rsp + 8] ; Restore in + + mov rax, [rdx] + xor rax, r13 ; CBC + mov [rcx + 8], rax + + mov rbx, [rdx+16] + xor rbx, r10 ; CBC + mov [rcx + 24], rbx + + call GostDecrypt2x64 + + mov rcx, [rsp] ; Restore out addr + mov rdx, [rsp+8] ; Restore in addr + + mov [rcx], r13 + mov [rcx+16], r10 + + add rcx,32 + mov [rsp], rcx + + add rdx,32 + mov [rsp+8], rdx + + mov r9, [rsp + 24] + sub r9, 2 + + jmp .do + +.end: + add rsp, 32 ; Load out addr + RestoreRegs ; Load +ret diff --git a/src/Crypto/gost89_x86.asm b/src/Crypto/gost89_x86.asm new file mode 100644 index 00000000..e69de29b -- cgit v1.2.3