mirror of
https://github.com/kevinbentley/Descent3.git
synced 2025-01-23 12:08:56 +00:00
375 lines
6.8 KiB
C++
375 lines
6.8 KiB
C++
|
/*
|
||
|
* $Logfile: /DescentIII/Main/dmfc/encryption.cpp $
|
||
|
* $Revision: 1.1.1.1 $
|
||
|
* $Date: 2003/08/26 03:57:21 $
|
||
|
* $Author: kevinb $
|
||
|
*
|
||
|
* header file for ICE encryption class
|
||
|
*
|
||
|
* $Log: encryption.cpp,v $
|
||
|
* Revision 1.1.1.1 2003/08/26 03:57:21 kevinb
|
||
|
* initial 1.5 import
|
||
|
*
|
||
|
*
|
||
|
* 2 7/08/99 2:37a Jeff
|
||
|
* created encryption class based off of ICE encryption
|
||
|
*
|
||
|
* $NoKeywords: $
|
||
|
*/
|
||
|
|
||
|
#include "encryption.h"
|
||
|
|
||
|
class IceSubkey
|
||
|
{
|
||
|
public:
|
||
|
unsigned long val[3];
|
||
|
};
|
||
|
|
||
|
// the S-boxes
|
||
|
static unsigned long ice_sbox[4][1024];
|
||
|
static int ice_sboxes_initialised = 0;
|
||
|
|
||
|
// modulo values for the S-boxes
|
||
|
static const int ice_smod[4][4] =
|
||
|
{
|
||
|
{333, 313, 505, 369},
|
||
|
{379, 375, 319, 391},
|
||
|
{361, 445, 451, 397},
|
||
|
{397, 425, 395, 505}
|
||
|
};
|
||
|
|
||
|
// XOR values for the S-boxes
|
||
|
static const int ice_sxor[4][4] =
|
||
|
{
|
||
|
{0x83, 0x85, 0x9b, 0xcd},
|
||
|
{0xcc, 0xa7, 0xad, 0x41},
|
||
|
{0x4b, 0x2e, 0xd4, 0x33},
|
||
|
{0xea, 0xcb, 0x2e, 0x04}
|
||
|
};
|
||
|
|
||
|
// Permutation values for the P-box
|
||
|
static const unsigned long ice_pbox[32] =
|
||
|
{
|
||
|
0x00000001, 0x00000080, 0x00000400, 0x00002000,
|
||
|
0x00080000, 0x00200000, 0x01000000, 0x40000000,
|
||
|
0x00000008, 0x00000020, 0x00000100, 0x00004000,
|
||
|
0x00010000, 0x00800000, 0x04000000, 0x20000000,
|
||
|
0x00000004, 0x00000010, 0x00000200, 0x00008000,
|
||
|
0x00020000, 0x00400000, 0x08000000, 0x10000000,
|
||
|
0x00000002, 0x00000040, 0x00000800, 0x00001000,
|
||
|
0x00040000, 0x00100000, 0x02000000, 0x80000000
|
||
|
};
|
||
|
|
||
|
// key rotation schedule
|
||
|
static const int ice_keyrot[16] =
|
||
|
{
|
||
|
0, 1, 2, 3, 2, 1, 3, 0,
|
||
|
1, 3, 2, 0, 3, 1, 0, 2
|
||
|
};
|
||
|
|
||
|
//
|
||
|
// 8-bit Galois Field multiplication of a by b, modulo m.
|
||
|
// Just like arithmetic multiplication, except that additions and
|
||
|
// subtractions are replaced by XOR.
|
||
|
//
|
||
|
static uint gf_mult(uint a,uint b,uint m)
|
||
|
{
|
||
|
uint res = 0;
|
||
|
|
||
|
while(b)
|
||
|
{
|
||
|
if(b&1)
|
||
|
res ^= a;
|
||
|
|
||
|
a <<= 1;
|
||
|
b >>= 1;
|
||
|
|
||
|
if(a>=256)
|
||
|
a ^= m;
|
||
|
}
|
||
|
|
||
|
return (res);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Galois Field exponentiation.
|
||
|
// Raise the base to the power of 7, modulo m.
|
||
|
//
|
||
|
static unsigned long gf_exp7(uint b, uint m)
|
||
|
{
|
||
|
uint x;
|
||
|
|
||
|
if(b==0)
|
||
|
return 0;
|
||
|
|
||
|
x = gf_mult (b, b, m);
|
||
|
x = gf_mult (b, x, m);
|
||
|
x = gf_mult (x, x, m);
|
||
|
|
||
|
return (gf_mult (b, x, m));
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Carry out the ICE 32-bit P-box permutation.
|
||
|
//
|
||
|
static unsigned long ice_perm32 (unsigned long x)
|
||
|
{
|
||
|
unsigned long res = 0;
|
||
|
const unsigned long *pbox = ice_pbox;
|
||
|
|
||
|
while(x)
|
||
|
{
|
||
|
if(x&1)
|
||
|
res |= *pbox;
|
||
|
pbox++;
|
||
|
x >>= 1;
|
||
|
}
|
||
|
|
||
|
return (res);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Initialise the ICE S-boxes.
|
||
|
// This only has to be done once.
|
||
|
//
|
||
|
static void ice_sboxes_init(void)
|
||
|
{
|
||
|
int i;
|
||
|
|
||
|
for(i=0;i<1024;i++)
|
||
|
{
|
||
|
int col=(i>>1)&0xff;
|
||
|
int row=(i&0x1)|((i&0x200)>>8);
|
||
|
unsigned long x;
|
||
|
|
||
|
x = gf_exp7(col^ice_sxor[0][row],ice_smod[0][row])<<24;
|
||
|
ice_sbox[0][i] = ice_perm32 (x);
|
||
|
|
||
|
x = gf_exp7(col^ice_sxor[1][row],ice_smod[1][row])<<16;
|
||
|
ice_sbox[1][i] = ice_perm32 (x);
|
||
|
|
||
|
x = gf_exp7(col^ice_sxor[2][row],ice_smod[2][row])<<8;
|
||
|
ice_sbox[2][i] = ice_perm32 (x);
|
||
|
|
||
|
x = gf_exp7(col^ice_sxor[3][row],ice_smod[3][row]);
|
||
|
ice_sbox[3][i] = ice_perm32 (x);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Create a new ICE key.
|
||
|
//
|
||
|
IceKey::IceKey(int n)
|
||
|
{
|
||
|
if(!ice_sboxes_initialised)
|
||
|
{
|
||
|
ice_sboxes_init();
|
||
|
ice_sboxes_initialised = 1;
|
||
|
}
|
||
|
|
||
|
if(n<1)
|
||
|
{
|
||
|
_size = 1;
|
||
|
_rounds = 8;
|
||
|
}else{
|
||
|
_size = n;
|
||
|
_rounds = n*16;
|
||
|
}
|
||
|
|
||
|
_keysched = new IceSubkey[_rounds];
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Destroy an ICE key.
|
||
|
//
|
||
|
IceKey::~IceKey ()
|
||
|
{
|
||
|
int i, j;
|
||
|
|
||
|
for(i=0;i<_rounds;i++)
|
||
|
{
|
||
|
for(j=0;j<3;j++)
|
||
|
{
|
||
|
_keysched[i].val[j] = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
_rounds = _size = 0;
|
||
|
|
||
|
delete[] _keysched;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// The single round ICE f function.
|
||
|
//
|
||
|
static unsigned long ice_f(unsigned long p,const IceSubkey *sk)
|
||
|
{
|
||
|
unsigned long tl, tr; /* Expanded 40-bit values */
|
||
|
unsigned long al, ar; /* Salted expanded 40-bit values */
|
||
|
|
||
|
// Left half expansion
|
||
|
tl = ((p >> 16) & 0x3ff) | (((p >> 14) | (p << 18)) & 0xffc00);
|
||
|
|
||
|
// Right half expansion
|
||
|
tr = (p & 0x3ff) | ((p << 2) & 0xffc00);
|
||
|
|
||
|
// Perform the salt permutation
|
||
|
al = sk->val[2] & (tl ^ tr);
|
||
|
ar = al ^ tr;
|
||
|
al ^= tl;
|
||
|
|
||
|
al ^= sk->val[0]; // XOR with the subkey
|
||
|
ar ^= sk->val[1];
|
||
|
|
||
|
// S-box lookup and permutation
|
||
|
return (ice_sbox[0][al>>10] | ice_sbox[1][al & 0x3ff] |
|
||
|
ice_sbox[2][ar>>10] | ice_sbox[3][ar & 0x3ff]);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Encrypt a block of 8 bytes of data with the given ICE key.
|
||
|
//
|
||
|
void IceKey::encrypt(const ubyte *ptext,ubyte *ctext) const
|
||
|
{
|
||
|
int i;
|
||
|
unsigned long l,r;
|
||
|
|
||
|
l = (((unsigned long) ptext[0]) << 24) |
|
||
|
(((unsigned long) ptext[1]) << 16) |
|
||
|
(((unsigned long) ptext[2]) << 8) | ptext[3];
|
||
|
|
||
|
r = (((unsigned long) ptext[4]) << 24) |
|
||
|
(((unsigned long) ptext[5]) << 16) |
|
||
|
(((unsigned long) ptext[6]) << 8) | ptext[7];
|
||
|
|
||
|
for(i=0;i<_rounds;i+=2)
|
||
|
{
|
||
|
l ^= ice_f(r,&_keysched[i]);
|
||
|
r ^= ice_f(l,&_keysched[i+1]);
|
||
|
}
|
||
|
|
||
|
for(i=0;i<4;i++)
|
||
|
{
|
||
|
ctext[3 - i] = (ubyte)r&0xff;
|
||
|
ctext[7 - i] = (ubyte)l&0xff;
|
||
|
|
||
|
r >>= 8;
|
||
|
l >>= 8;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Decrypt a block of 8 bytes of data with the given ICE key.
|
||
|
//
|
||
|
void IceKey::decrypt(const ubyte *ctext,ubyte *ptext) const
|
||
|
{
|
||
|
int i;
|
||
|
unsigned long l,r;
|
||
|
|
||
|
l = (((unsigned long) ctext[0]) << 24) |
|
||
|
(((unsigned long) ctext[1]) << 16) |
|
||
|
(((unsigned long) ctext[2]) << 8) | ctext[3];
|
||
|
r = (((unsigned long) ctext[4]) << 24) |
|
||
|
(((unsigned long) ctext[5]) << 16) |
|
||
|
(((unsigned long) ctext[6]) << 8) | ctext[7];
|
||
|
|
||
|
for(i=_rounds-1;i>0;i-=2)
|
||
|
{
|
||
|
l ^= ice_f(r,&_keysched[i]);
|
||
|
r ^= ice_f(l,&_keysched[i-1]);
|
||
|
}
|
||
|
|
||
|
for(i=0;i<4;i++)
|
||
|
{
|
||
|
ptext[3 - i] = (ubyte)r&0xff;
|
||
|
ptext[7 - i] = (ubyte)l&0xff;
|
||
|
|
||
|
r >>= 8;
|
||
|
l >>= 8;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Set 8 rounds [n, n+7] of the key schedule of an ICE key.
|
||
|
//
|
||
|
void IceKey::scheduleBuild(unsigned short *kb,int n,const int *keyrot)
|
||
|
{
|
||
|
int i;
|
||
|
|
||
|
for(i=0;i<8;i++)
|
||
|
{
|
||
|
int j;
|
||
|
int kr = keyrot[i];
|
||
|
IceSubkey *isk = &_keysched[n+i];
|
||
|
|
||
|
for(j=0;j<3;j++)
|
||
|
isk->val[j] = 0;
|
||
|
|
||
|
for(j=0;j<15;j++)
|
||
|
{
|
||
|
int k;
|
||
|
unsigned long *curr_sk = &isk->val[j%3];
|
||
|
|
||
|
for(k=0;k<4;k++)
|
||
|
{
|
||
|
ushort *curr_kb = &kb[(kr+k)&3];
|
||
|
int bit = *curr_kb&1;
|
||
|
|
||
|
*curr_sk = (*curr_sk<<1)|bit;
|
||
|
*curr_kb = (*curr_kb>>1)|((bit^1)<<15);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Set the key schedule of an ICE key.
|
||
|
//
|
||
|
void IceKey::set(const ubyte *key)
|
||
|
{
|
||
|
int i;
|
||
|
|
||
|
if(_rounds==8)
|
||
|
{
|
||
|
ushort kb[4];
|
||
|
|
||
|
for(i=0;i<4;i++)
|
||
|
{
|
||
|
kb[3-i] = (key[i*2]<<8)|key[i*2+1];
|
||
|
}
|
||
|
|
||
|
scheduleBuild(kb,0,ice_keyrot);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
for(i=0;i<_size;i++)
|
||
|
{
|
||
|
int j;
|
||
|
ushort kb[4];
|
||
|
|
||
|
for(j=0;j<4;j++)
|
||
|
{
|
||
|
kb[3-j] = (key[i*8+j*2]<<8)|key[i*8+j*2+1];
|
||
|
|
||
|
scheduleBuild(kb,i*8,ice_keyrot);
|
||
|
scheduleBuild(kb,_rounds-8-i*8,&ice_keyrot[8]);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Return the key size, in bytes.
|
||
|
//
|
||
|
int IceKey::keySize(void) const
|
||
|
{
|
||
|
return (_size*8);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Return the block size, in bytes.
|
||
|
//
|
||
|
int IceKey::blockSize(void) const
|
||
|
{
|
||
|
return 8;
|
||
|
}
|