VeraCrypt
aboutsummaryrefslogtreecommitdiff
path: root/src/Crypto
diff options
context:
space:
mode:
Diffstat (limited to 'src/Crypto')
-rw-r--r--src/Crypto/Crypto.vcxproj12
-rw-r--r--src/Crypto/Crypto.vcxproj.filters9
-rw-r--r--src/Crypto/GostCipher.c269
-rw-r--r--src/Crypto/GostCipher.h61
-rw-r--r--src/Crypto/Makefile.inc3
-rw-r--r--src/Crypto/Sources5
-rw-r--r--src/Crypto/gost89_x64.asm481
-rw-r--r--src/Crypto/gost89_x86.asm0
8 files changed, 839 insertions, 1 deletions
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
@@ -202,12 +202,23 @@
</Command>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(TargetDir)\%(Filename).obj;%(Outputs)</Outputs>
</CustomBuild>
+ <CustomBuild Include="Gost89_x64.asm">
+ <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">echo %(Filename)%(Extension) &amp; nasm.exe -Xvc -f win64 -Ox -o "$(TargetDir)\%(Filename).obj" -l "$(TargetDir)\%(Filename).lst" "%(FullPath)"
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(TargetDir)\%(Filename).obj;%(Outputs)</Outputs>
+ <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">echo %(Filename)%(Extension) &amp; nasm.exe -Xvc -f win64 -Ox -o "$(TargetDir)\%(Filename).obj" -l "$(TargetDir)\%(Filename).lst" "%(FullPath)"
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(TargetDir)\%(Filename).obj;%(Outputs)</Outputs>
+ </CustomBuild>
</ItemGroup>
<ItemGroup>
<ClCompile Include="Aeskey.c" />
<ClCompile Include="Aestab.c" />
<ClCompile Include="Camellia.c" />
<ClCompile Include="cpu.c" />
+ <ClCompile Include="GostCipher.c" />
<ClCompile Include="Rmd160.c" />
<ClCompile Include="Serpent.c" />
<ClCompile Include="Sha2.c" />
@@ -222,6 +233,7 @@
<ClInclude Include="Camellia.h" />
<ClInclude Include="config.h" />
<ClInclude Include="cpu.h" />
+ <ClInclude Include="GostCipher.h" />
<ClInclude Include="misc.h" />
<ClInclude Include="Rmd160.h" />
<ClInclude Include="Serpent.h" />
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 @@
<ClCompile Include="Whirlpool.c">
<Filter>Source Files</Filter>
</ClCompile>
+ <ClCompile Include="GostCipher.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="Aes.h">
@@ -83,6 +86,9 @@
<ClInclude Include="Whirlpool.h">
<Filter>Header Files</Filter>
</ClInclude>
+ <ClInclude Include="GostCipher.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
</ItemGroup>
<ItemGroup>
<CustomBuild Include="Aes_hw_cpu.asm">
@@ -94,5 +100,8 @@
<CustomBuild Include="Aes_x86.asm">
<Filter>Source Files</Filter>
</CustomBuild>
+ <CustomBuild Include="Gost89_x64.asm">
+ <Filter>Source Files</Filter>
+ </CustomBuild>
</ItemGroup>
</Project> \ 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
--- /dev/null
+++ b/src/Crypto/gost89_x86.asm