1
0
mirror of https://github.com/veracrypt/VeraCrypt.git synced 2025-11-13 03:48:26 -06:00

Windows: Add Magma cipher (GOST-89)

This commit is contained in:
Mounir IDRASSI
2016-08-09 09:54:00 +02:00
parent 460f552a41
commit 0b2c8b09c6
11 changed files with 889 additions and 8 deletions

269
src/Crypto/GostCipher.c Normal file
View File

@@ -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