forked from metin2/server
235 lines
6.9 KiB
C++
235 lines
6.9 KiB
C++
#include "stdafx.h"
|
|
/*
|
|
static unsigned char const k8[16] = { 14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7 };
|
|
static unsigned char const k7[16] = { 15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10 };
|
|
static unsigned char const k6[16] = { 10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8 };
|
|
static unsigned char const k5[16] = { 7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15 };
|
|
static unsigned char const k4[16] = { 2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9 };
|
|
static unsigned char const k3[16] = { 12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11 };
|
|
static unsigned char const k2[16] = { 4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1 };
|
|
static unsigned char const k1[16] = { 13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7 };
|
|
*/
|
|
static unsigned char const k8[16] = { 15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13 };
|
|
static unsigned char const k7[16] = { 3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5 };
|
|
static unsigned char const k6[16] = { 10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8 };
|
|
static unsigned char const k5[16] = { 13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9 };
|
|
static unsigned char const k4[16] = { 11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3 };
|
|
static unsigned char const k3[16] = { 4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13 };
|
|
static unsigned char const k2[16] = { 4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1 };
|
|
static unsigned char const k1[16] = { 7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8 };
|
|
|
|
/* Byte-at-a-time substitution boxes */
|
|
static unsigned char k87[256];
|
|
static unsigned char k65[256];
|
|
static unsigned char k43[256];
|
|
static unsigned char k21[256];
|
|
|
|
void GOST_Init()
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < 256; i++)
|
|
{
|
|
k87[i] = k8[i >> 4] << 4 | k7[i & 15];
|
|
k65[i] = k6[i >> 4] << 4 | k5[i & 15];
|
|
k43[i] = k4[i >> 4] << 4 | k3[i & 15];
|
|
k21[i] = k2[i >> 4] << 4 | k1[i & 15];
|
|
}
|
|
}
|
|
|
|
INLINE static DWORD f(DWORD x)
|
|
{
|
|
x = k87[x >> 24 & 255] << 24 | k65[x >> 16 & 255] << 16 | k43[x >> 8 & 255] << 8 | k21[x & 255];
|
|
return x << 11 | x >> (32 - 11);
|
|
}
|
|
/*
|
|
static void GOST_ECB_Encrypt(DWORD * N1, DWORD * N2, const DWORD * KeyAddress)
|
|
{
|
|
register DWORD n1, n2; // As named in the GOST
|
|
|
|
n1 = *N1;
|
|
n2 = *N2;
|
|
|
|
// Instead of swapping halves, swap names each round
|
|
n2 ^= f(n1+KeyAddress[0]);
|
|
n1 ^= f(n2+KeyAddress[1]);
|
|
n2 ^= f(n1+KeyAddress[2]);
|
|
n1 ^= f(n2+KeyAddress[3]);
|
|
n2 ^= f(n1+KeyAddress[4]);
|
|
n1 ^= f(n2+KeyAddress[5]);
|
|
n2 ^= f(n1+KeyAddress[6]);
|
|
n1 ^= f(n2+KeyAddress[7]);
|
|
|
|
n2 ^= f(n1+KeyAddress[0]);
|
|
n1 ^= f(n2+KeyAddress[1]);
|
|
n2 ^= f(n1+KeyAddress[2]);
|
|
n1 ^= f(n2+KeyAddress[3]);
|
|
n2 ^= f(n1+KeyAddress[4]);
|
|
n1 ^= f(n2+KeyAddress[5]);
|
|
n2 ^= f(n1+KeyAddress[6]);
|
|
n1 ^= f(n2+KeyAddress[7]);
|
|
|
|
n2 ^= f(n1+KeyAddress[0]);
|
|
n1 ^= f(n2+KeyAddress[1]);
|
|
n2 ^= f(n1+KeyAddress[2]);
|
|
n1 ^= f(n2+KeyAddress[3]);
|
|
n2 ^= f(n1+KeyAddress[4]);
|
|
n1 ^= f(n2+KeyAddress[5]);
|
|
n2 ^= f(n1+KeyAddress[6]);
|
|
n1 ^= f(n2+KeyAddress[7]);
|
|
|
|
n2 ^= f(n1+KeyAddress[7]);
|
|
n1 ^= f(n2+KeyAddress[6]);
|
|
n2 ^= f(n1+KeyAddress[5]);
|
|
n1 ^= f(n2+KeyAddress[4]);
|
|
n2 ^= f(n1+KeyAddress[3]);
|
|
n1 ^= f(n2+KeyAddress[2]);
|
|
n2 ^= f(n1+KeyAddress[1]);
|
|
n1 ^= f(n2+KeyAddress[0]);
|
|
|
|
// There is no swap after the last round
|
|
*N1 = n2;
|
|
*N2 = n1;
|
|
}
|
|
*/
|
|
int GOST_Encrypt(DWORD * DstBuffer, const DWORD * SrcBuffer, const DWORD * KeyAddress, DWORD Length, DWORD *IVector)
|
|
{
|
|
DWORD i;
|
|
DWORD N1,N2;
|
|
|
|
N1 = IVector[0];
|
|
N2 = IVector[1];
|
|
|
|
for (i = 0; i < (Length >> 2); i = i+2)
|
|
{
|
|
register DWORD n1, n2; // As named in the GOST
|
|
|
|
n1 = N1;
|
|
n2 = N2;
|
|
|
|
// Instead of swapping halves, swap names each round
|
|
n2 ^= f(n1+KeyAddress[0]);
|
|
n1 ^= f(n2+KeyAddress[1]);
|
|
n2 ^= f(n1+KeyAddress[2]);
|
|
n1 ^= f(n2+KeyAddress[3]);
|
|
n2 ^= f(n1+KeyAddress[4]);
|
|
n1 ^= f(n2+KeyAddress[5]);
|
|
n2 ^= f(n1+KeyAddress[6]);
|
|
n1 ^= f(n2+KeyAddress[7]);
|
|
|
|
n2 ^= f(n1+KeyAddress[0]);
|
|
n1 ^= f(n2+KeyAddress[1]);
|
|
n2 ^= f(n1+KeyAddress[2]);
|
|
n1 ^= f(n2+KeyAddress[3]);
|
|
n2 ^= f(n1+KeyAddress[4]);
|
|
n1 ^= f(n2+KeyAddress[5]);
|
|
n2 ^= f(n1+KeyAddress[6]);
|
|
n1 ^= f(n2+KeyAddress[7]);
|
|
|
|
n2 ^= f(n1+KeyAddress[0]);
|
|
n1 ^= f(n2+KeyAddress[1]);
|
|
n2 ^= f(n1+KeyAddress[2]);
|
|
n1 ^= f(n2+KeyAddress[3]);
|
|
n2 ^= f(n1+KeyAddress[4]);
|
|
n1 ^= f(n2+KeyAddress[5]);
|
|
n2 ^= f(n1+KeyAddress[6]);
|
|
n1 ^= f(n2+KeyAddress[7]);
|
|
|
|
n2 ^= f(n1+KeyAddress[7]);
|
|
n1 ^= f(n2+KeyAddress[6]);
|
|
n2 ^= f(n1+KeyAddress[5]);
|
|
n1 ^= f(n2+KeyAddress[4]);
|
|
n2 ^= f(n1+KeyAddress[3]);
|
|
n1 ^= f(n2+KeyAddress[2]);
|
|
n2 ^= f(n1+KeyAddress[1]);
|
|
n1 ^= f(n2+KeyAddress[0]);
|
|
|
|
N1 = n2;
|
|
N2 = n1;
|
|
//GOST_ECB_Encrypt(&N1, &N2, KeyAddress);
|
|
// XOR plaintext with initial vector,
|
|
// move rezult to ciphertext and to initial vector
|
|
DstBuffer[i] = SrcBuffer[i] ^ N1;
|
|
N1 = DstBuffer[i];
|
|
|
|
DstBuffer[i+1] = SrcBuffer[i+1] ^ N2;
|
|
N2 = DstBuffer[i+1];
|
|
}
|
|
|
|
return Length;
|
|
}
|
|
|
|
|
|
// ************ GOST CBC decryption **************
|
|
int GOST_Decrypt(DWORD * DstBuffer, const DWORD * SrcBuffer, const DWORD * KeyAddress, DWORD Length, DWORD *IVector)
|
|
{
|
|
DWORD i;
|
|
DWORD N1, N2, dwTmp;
|
|
|
|
N1 = IVector[0];
|
|
N2 = IVector[1];
|
|
|
|
for (i = 0; i < (Length >> 2); i = i + 2)
|
|
{
|
|
register DWORD n1, n2; // As named in the GOST
|
|
|
|
n1 = N1;
|
|
n2 = N2;
|
|
|
|
// Instead of swapping halves, swap names each round
|
|
n2 ^= f(n1+KeyAddress[0]);
|
|
n1 ^= f(n2+KeyAddress[1]);
|
|
n2 ^= f(n1+KeyAddress[2]);
|
|
n1 ^= f(n2+KeyAddress[3]);
|
|
n2 ^= f(n1+KeyAddress[4]);
|
|
n1 ^= f(n2+KeyAddress[5]);
|
|
n2 ^= f(n1+KeyAddress[6]);
|
|
n1 ^= f(n2+KeyAddress[7]);
|
|
|
|
n2 ^= f(n1+KeyAddress[0]);
|
|
n1 ^= f(n2+KeyAddress[1]);
|
|
n2 ^= f(n1+KeyAddress[2]);
|
|
n1 ^= f(n2+KeyAddress[3]);
|
|
n2 ^= f(n1+KeyAddress[4]);
|
|
n1 ^= f(n2+KeyAddress[5]);
|
|
n2 ^= f(n1+KeyAddress[6]);
|
|
n1 ^= f(n2+KeyAddress[7]);
|
|
|
|
n2 ^= f(n1+KeyAddress[0]);
|
|
n1 ^= f(n2+KeyAddress[1]);
|
|
n2 ^= f(n1+KeyAddress[2]);
|
|
n1 ^= f(n2+KeyAddress[3]);
|
|
n2 ^= f(n1+KeyAddress[4]);
|
|
n1 ^= f(n2+KeyAddress[5]);
|
|
n2 ^= f(n1+KeyAddress[6]);
|
|
n1 ^= f(n2+KeyAddress[7]);
|
|
|
|
n2 ^= f(n1+KeyAddress[7]);
|
|
n1 ^= f(n2+KeyAddress[6]);
|
|
n2 ^= f(n1+KeyAddress[5]);
|
|
n1 ^= f(n2+KeyAddress[4]);
|
|
n2 ^= f(n1+KeyAddress[3]);
|
|
n1 ^= f(n2+KeyAddress[2]);
|
|
n2 ^= f(n1+KeyAddress[1]);
|
|
n1 ^= f(n2+KeyAddress[0]);
|
|
|
|
// There is no swap after the last round
|
|
N1 = n2;
|
|
N2 = n1;
|
|
//GOST_ECB_Encrypt(&N1, &N2, KeyAddress);
|
|
// XOR encrypted text with encrypted initial vector (we get rezult - decrypted text),
|
|
// move encrypted text to new initial vector.
|
|
// We need dwTmp because SrcBuffer may be the same as DstBuffer
|
|
dwTmp = SrcBuffer[i] ^ N1;
|
|
N1 = SrcBuffer[i];
|
|
DstBuffer[i] = dwTmp;
|
|
|
|
dwTmp = SrcBuffer[i+1] ^ N2;
|
|
N2 = SrcBuffer[i+1];
|
|
DstBuffer[i+1] = dwTmp;
|
|
}
|
|
|
|
return Length;
|
|
}
|
|
|