mirror of
https://github.com/veracrypt/VeraCrypt
synced 2024-11-14 23:23:30 +01:00
266 lines
7.7 KiB
C
266 lines
7.7 KiB
C
/** @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 "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
|
|
}
|
|
}
|
|
|
|
|
|
static void xor_s_box(byte s_box[8][16], byte *seed)
|
|
{
|
|
int i;
|
|
for (i = 0; i < 16; i++)
|
|
{
|
|
s_box[0][i] ^= (seed[ (i * 4) + 0 ] ) & 0xF;
|
|
s_box[1][i] ^= (seed[ (i * 4) + 0 ]>>4) & 0xF;
|
|
s_box[2][i] ^= (seed[ (i * 4) + 1 ] ) & 0xF;
|
|
s_box[3][i] ^= (seed[ (i * 4) + 1 ]>>4) & 0xF;
|
|
s_box[4][i] ^= (seed[ (i * 4) + 2 ] ) & 0xF;
|
|
s_box[5][i] ^= (seed[ (i * 4) + 2 ]>>4) & 0xF;
|
|
s_box[6][i] ^= (seed[ (i * 4) + 3 ] ) & 0xF;
|
|
s_box[7][i] ^= (seed[ (i * 4) + 3 ]>>4) & 0xF;
|
|
}
|
|
}
|
|
|
|
void gost_set_key(const byte *key, gost_kds *ks, int useDynamicSbox)
|
|
{
|
|
memcpy(ks->key, key, GOST_KEYSIZE);
|
|
memcpy(ks->sbox, S_TC26, sizeof(ks->sbox));
|
|
|
|
if (useDynamicSbox)
|
|
{
|
|
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
|
|
//Generate pseudorandom data based on the key
|
|
STREEBOG_init(&sctx);
|
|
STREEBOG_add(&sctx, ks->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);
|
|
}
|
|
|
|
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(const byte *in, byte *out, gost_kds *ks, uint64 count);
|
|
void gost_decrypt_128_CBC_asm(const byte *in, byte *out, gost_kds *ks, uint64 count);
|
|
#endif
|
|
|
|
void gost_encrypt(const 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(const 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
|