Skip to content

Instantly share code, notes, and snippets.

@kik
Created May 24, 2012 15:19
Show Gist options
  • Save kik/2782177 to your computer and use it in GitHub Desktop.
Save kik/2782177 to your computer and use it in GitHub Desktop.
cipher0x
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
class Cipher0X
{
private:
static u32 load_be32(const u8 *p)
{
u32 v;
v = p[0] << 24;
v |= p[1] << 16;
v |= p[2] << 8;
v |= p[3] << 0;
return v;
}
static void store_be32(u8 *p, u32 v)
{
p[0] = v >> 24;
p[1] = v >> 16;
p[2] = v >> 8;
p[3] = v >> 0;
}
static u32 Fadd(u32 a, u32 b, u16 c)
{
u16 x = (a >> 16) + (b >> 16) + c;
u16 y = (a & 0xFFFF) + (b & 0xFFFF) + c;
return (x << 16) | y;
}
static u32 Fswap(u32 x)
{
return ((x & 0xF0F0F0F0) >> 4) | ((x & 0x0F0F0F0F) << 4);
}
static u32 Frot(u32 x)
{
return (x << 1) | (x >> 31);
}
static bool Fodd(u32 x)
{
x ^= x >> 16;
x ^= x >> 8;
x ^= x >> 4;
x ^= x >> 2;
x ^= x >> 1;
return x & 1;
}
static u32 Fbitperm(u32 x, bool flag)
{
if (flag) {
return
((x & 0x00AA0000) << 7) |
((x & 0x00005500) << 9) |
((x & 0x00000055) << 16) |
((x & 0xAA000000) >> 0) |
((x & 0x000000AA) >> 1) |
((x & 0x0055AA00) >> 8) |
((x & 0x55000000) >> 15);
} else {
return
((x & 0x00000055) << 1) |
((x & 0x0000AA00) << 7) |
((x & 0x00550000) << 9) |
((x & 0x000000AA) << 16) |
((x & 0x55000000) >> 0) |
((x & 0x00AA5500) >> 8) |
((x & 0xAA000000) >> 17);
}
}
static u32 F(u32 r, u32 sk, u16 cc, bool bitperm)
{
u32 X = Fadd(r, sk, cc);
u32 Y = Fswap(X);
u32 M = Frot(sk);
if (Fodd(Y & M)) {
Y ^= ~M;
}
u32 T = Fbitperm(Y, bitperm);
return T ^ ((T << 8) | (T >> 24)) ^ Frot(T);
}
static u32 F0(u32 r, u32 sk)
{
return F(r, sk, 0, false);
}
static u32 F1(u32 r, u32 sk)
{
return F(r, sk, 0, true);
}
static u32 F2(u32 r, u32 sk)
{
return F(r, sk, 0x5353, false);
}
static u32 F3(u32 r, u32 sk)
{
return F(r, sk, 0x5353, true);
}
u8 protocol;
u32 skey[4];
void Feistel0(u32& L, u32& R, int ski)
{
L ^= F0(R, skey[ski]);
swap(L, R);
}
void Feistel1(u32& L, u32& R, int ski)
{
L ^= F1(R, skey[ski]);
swap(L, R);
}
void Feistel2(u32& L, u32& R, int ski)
{
L ^= F2(R, skey[ski]);
swap(L, R);
}
void Feistel3(u32& L, u32& R, int ski)
{
L ^= F3(R, skey[ski]);
swap(L, R);
}
void enc_dec(u32 InL, u32 InR,
u32& OutL, u32& OutR,
bool dec)
{
u32 L, R;
L = InL;
R = InR;
if (dec) {
Feistel1(L, R, 3); Feistel0(L, R, 2); Feistel0(L, R, 1); Feistel1(L, R, 0);
Feistel2(L, R, 3); Feistel0(L, R, 2); Feistel3(L, R, 1); Feistel1(L, R, 0);
Feistel2(L, R, 3); Feistel0(L, R, 2); Feistel2(L, R, 1); Feistel2(L, R, 0);
Feistel2(L, R, 3); Feistel1(L, R, 2); Feistel0(L, R, 1); Feistel1(L, R, 0);
} else {
Feistel1(L, R, 0); Feistel0(L, R, 1); Feistel1(L, R, 2); Feistel2(L, R, 3);
Feistel2(L, R, 0); Feistel2(L, R, 1); Feistel0(L, R, 2); Feistel2(L, R, 3);
Feistel1(L, R, 0); Feistel3(L, R, 1); Feistel0(L, R, 2); Feistel2(L, R, 3);
Feistel1(L, R, 0); Feistel0(L, R, 1); Feistel0(L, R, 2); Feistel1(L, R, 3);
}
swap(L, R);
OutL = L;
OutR = R;
}
void encrypt(u32 InL, u32 InR, u32& OutL, u32& OutR)
{
enc_dec(InL, InR, OutL, OutR, false);
}
void decrypt(u32 InL, u32 InR, u32& OutL, u32& OutR)
{
enc_dec(InL, InR, OutL, OutR, true);
}
void schedule(u32 KeyL, u32 KeyR)
{
skey[0] = KeyL;
skey[1] = KeyR;
skey[2] = 0x08090A0B;
skey[3] = 0x0C0D0E0F;
u32 R;
if (protocol & 0x0c) {
R = 0x84E5C4E7;
} else {
R = 0x6AA32B6F;
}
for (int i = 0 ; i < 8 ; i++) {
R = skey[i % 4] = F0(skey[i % 4], R);
}
}
public:
void cbc_encdec(const u8 *Key,
const u8 *Input,
int Size,
u8 *Output,
const u8* IV,
bool dec)
{
u32 KeyL = load_be32(&Key[0]);
u32 KeyR = load_be32(&Key[4]);
schedule(KeyL, KeyR);
u32 fbL = load_be32(&IV[0]);
u32 fbR = load_be32(&IV[4]);
for (; Size >= 8; Size -= 8, Input += 8, Output += 8) {
if (dec) {
u32 CL = load_be32(&Input[0]);
u32 CR = load_be32(&Input[4]);
u32 PL, PR;
decrypt(CL, CR, PL, PR);
store_be32(&Output[0], PL ^ fbL);
store_be32(&Output[4], PR ^ fbR);
fbL = CL;
fbR = CR;
} else {
u32 PL = load_be32(&Input[0]);
u32 PR = load_be32(&Input[4]);
u32 CL, CR;
encrypt(PL ^ fbL, PR ^ fbR, CL, CR);
store_be32(&Output[0], CL);
store_be32(&Output[4], CR);
fbL = CL;
fbR = CR;
}
}
if (Size > 0) {
u32 CL, CR;
encrypt(fbL, fbR, CL, CR);
u8 tmp[8];
store_be32(&tmp[0], CL);
store_be32(&tmp[4], CR);
for (u32 i = 0 ; i < Size ; i++) {
Output[i] = Input[i] ^ tmp[i];
}
}
}
void cbc_decrypt(const u8 *Key,
const u8 *Input,
int Size,
u8 *Output,
const u8* IV)
{
cbc_encdec(Key, Input, Size, Output, IV, true);
}
void cbc_encrypt(const u8 *Key,
const u8 *Input,
int Size,
u8 *Output,
const u8* IV)
{
cbc_encdec(Key, Input, Size, Output, IV, false);
}
explicit Cipher0X(u8 protocol)
: protocol(protocol)
{
}
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment