Skip to content

Commit

Permalink
twofish
Browse files Browse the repository at this point in the history
  • Loading branch information
SymmetricChaos committed Oct 19, 2024
1 parent 95835d5 commit 7529418
Show file tree
Hide file tree
Showing 3 changed files with 193 additions and 82 deletions.
126 changes: 126 additions & 0 deletions ciphers/src/digital/block_ciphers/twofish/functions.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
// 4-bit SBOX for q0 function
const Q0: [[u8; 16]; 4] = [
[
0x8, 0x1, 0x7, 0xD, 0x6, 0xF, 0x3, 0x2, 0x0, 0xB, 0x5, 0x9, 0xE, 0xC, 0xA, 0x4,
],
[
0xE, 0xC, 0xB, 0x8, 0x1, 0x2, 0x3, 0x5, 0xF, 0x4, 0xA, 0x6, 0x7, 0x0, 0x9, 0xD,
],
[
0xB, 0xA, 0x5, 0xE, 0x6, 0xD, 0x9, 0x0, 0xC, 0x8, 0xF, 0x3, 0x2, 0x4, 0x7, 0x1,
],
[
0xD, 0x7, 0xF, 0x4, 0x1, 0x2, 0x6, 0xE, 0x9, 0xB, 0x3, 0x0, 0x8, 0x5, 0xC, 0xA,
],
];

// 4-bit SBOX for q1 function
const Q1: [[u8; 16]; 4] = [
[
0x2, 0x8, 0xB, 0xD, 0xF, 0x7, 0x6, 0xE, 0x3, 0x1, 0x9, 0x4, 0x0, 0xA, 0xC, 0x5,
],
[
0x1, 0xE, 0x2, 0xB, 0x4, 0xC, 0x3, 0x7, 0x6, 0xD, 0xA, 0x5, 0xF, 0x9, 0x0, 0x8,
],
[
0x4, 0xC, 0x7, 0x5, 0x1, 0x6, 0x9, 0xA, 0x0, 0xE, 0xD, 0x8, 0x2, 0xB, 0x3, 0xF,
],
[
0xB, 0x9, 0x5, 0x1, 0xC, 0x3, 0xD, 0xE, 0x6, 0x4, 0x7, 0xF, 0x2, 0x0, 0x8, 0xA,
],
];

pub const QORD: [[usize; 5]; 4] = [
[1, 1, 0, 0, 1],
[0, 1, 1, 0, 0],
[0, 0, 0, 1, 1],
[1, 0, 1, 1, 0],
];

pub(super) fn q0(n: u8) -> u8 {
let a0 = (n >> 4) & 15;
let b0 = n & 15;
let a1 = a0 ^ b0;
let b1 = a0 ^ ((b0 << 3) | (b0 >> 1)) ^ ((a0 << 3) & 15); // Because the upper 4 bits will be empty the rotation of the lower 4 bits of b0 is always correct
let a2 = Q0[0][a1 as usize];
let b2 = Q0[1][b1 as usize];
let a3 = a2 ^ b2;
let b3 = a2 ^ ((b2 << 3) | (b2 >> 1)) ^ ((a2 << 3) & 15); // As for b0
let a4 = Q0[2][a3 as usize];
let b4 = Q0[3][b3 as usize];
(b4 << 4) | a4
}

pub(super) fn q1(n: u8) -> u8 {
let a0 = (n >> 4) & 15;
let b0 = n & 15;
let a1 = a0 ^ b0;
let b1 = a0 ^ ((b0 << 3) | (b0 >> 1)) ^ ((8 * a0) & 15);
let a2 = Q1[0][a1 as usize];
let b2 = Q1[1][b1 as usize];
let a3 = a2 ^ b2;
let b3 = a2 ^ ((b2 << 3) | (b2 >> 1)) ^ ((8 * a2) & 15);
let a4 = Q1[2][a3 as usize];
let b4 = Q1[3][b3 as usize];
(b4 << 4) | a4
}

// Maximum Distance Separable Operations
pub(super) fn gf_mult(mut a: u8, mut b: u8, p: u8) -> u8 {
let mut result = 0;
while a > 0 {
if a & 1 == 1 {
result ^= b;
}
a >>= 1;
if b & 0x80 == 0x80 {
b = (b << 1) ^ p;
} else {
b <<= 1;
}
}
result
}

pub(super) fn mds_column_mult(x: u8, column: usize) -> u32 {
let x5b = gf_mult(x, 0x5b, 0x69);
let xef = gf_mult(x, 0xef, 0x69);

let v = match column {
0 => [x, x5b, xef, xef],
1 => [xef, xef, x5b, x],
2 => [x5b, xef, x, xef],
3 => [x5b, x, xef, x5b],
_ => unreachable!(),
};
u32::from_le_bytes(v)
}

pub(super) fn mds_mult(y: [u8; 4]) -> u32 {
let mut z = 0;
for i in 0..4 {
z ^= mds_column_mult(y[i], i);
}
z
}

const RS: [[u8; 8]; 4] = [
[0x01, 0xa4, 0x55, 0x87, 0x5a, 0x58, 0xdb, 0x9e],
[0xa4, 0x56, 0x82, 0xf3, 0x1e, 0xc6, 0x68, 0xe5],
[0x02, 0xa1, 0xfc, 0xc1, 0x47, 0xae, 0x3d, 0x19],
[0xa4, 0x55, 0x87, 0x5a, 0x58, 0xdb, 0x9e, 0x03],
];

pub(super) fn rs_mult(m: &[u8], out: &mut [u8]) {
for i in 0..4 {
out[i] = 0;
for j in 0..8 {
out[i] ^= gf_mult(m[j], RS[i][j], 0x4d);
}
}
}

// Pseudo-Hadamard Transform
pub(super) fn pht(a: u32, b: u32) -> (u32, u32) {
(a.wrapping_add(b), a.wrapping_add(b << 1))
}
2 changes: 2 additions & 0 deletions ciphers/src/digital/block_ciphers/twofish/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
pub mod functions;
pub mod twofish;
Original file line number Diff line number Diff line change
@@ -1,76 +1,45 @@
use itertools::Itertools;
use utils::byte_formatting::{fill_u32s_le, u32s_to_bytes_le, ByteFormat};

use super::block_cipher::{BCMode, BCPadding, BlockCipher};

// 4-bit SBOX for q0 function
const Q0: [[u8; 16]; 4] = [
[
0x8, 0x1, 0x7, 0xD, 0x6, 0xF, 0x3, 0x2, 0x0, 0xB, 0x5, 0x9, 0xE, 0xC, 0xA, 0x4,
],
[
0xE, 0xC, 0xB, 0x8, 0x1, 0x2, 0x3, 0x5, 0xF, 0x4, 0xA, 0x6, 0x7, 0x0, 0x9, 0xD,
],
[
0xB, 0xA, 0x5, 0xE, 0x6, 0xD, 0x9, 0x0, 0xC, 0x8, 0xF, 0x3, 0x2, 0x4, 0x7, 0x1,
],
[
0xD, 0x7, 0xF, 0x4, 0x1, 0x2, 0x6, 0xE, 0x9, 0xB, 0x3, 0x0, 0x8, 0x5, 0xC, 0xA,
],
];

// 4-bit SBOX for q1 function
const Q1: [[u8; 16]; 4] = [
[
0x2, 0x8, 0xB, 0xD, 0xF, 0x7, 0x6, 0xE, 0x3, 0x1, 0x9, 0x4, 0x0, 0xA, 0xC, 0x5,
],
[
0x1, 0xE, 0x2, 0xB, 0x4, 0xC, 0x3, 0x7, 0x6, 0xD, 0xA, 0x5, 0xF, 0x9, 0x0, 0x8,
],
[
0x4, 0xC, 0x7, 0x5, 0x1, 0x6, 0x9, 0xA, 0x0, 0xE, 0xD, 0x8, 0x2, 0xB, 0x3, 0xF,
],
[
0xB, 0x9, 0x5, 0x1, 0xC, 0x3, 0xD, 0xE, 0x6, 0x4, 0x7, 0xF, 0x2, 0x0, 0x8, 0xA,
],
];

// Each 4-bit nibble is rotated one bit toward the LSB (to the right)
fn nibble_ror_1(x: u8) -> u8 {
(((x) >> 1) & 0x77) | (((x) & 0x11) << 3)
}
use super::{
super::block_cipher::{BCMode, BCPadding, BlockCipher},
functions::{mds_mult, pht, q0, q1},
};

fn h(x: u32, list: &[u8], offset: usize) -> u32 {
let mut y = x.to_le_bytes();
if K == 4 {
y[0] = q1(y[0]) ^ list[4 * (6 + offset + 0)];
y[1] = q0(y[1]) ^ list[4 * (6 + offset + 1)];
y[2] = q0(y[2]) ^ list[4 * (6 + offset + 2)];
y[3] = q1(y[3]) ^ list[4 * (6 + offset + 3)];
}

fn q0(n: u8) -> u8 {
let a0 = (n >> 4) & 15;
let b0 = n & 15;
let a1 = a0 ^ b0;
let b1 = a0 ^ nibble_ror_1(b0) ^ ((8 * a0) & 15);
let a2 = Q0[0][a1 as usize];
let b2 = Q0[1][b1 as usize];
let a3 = a2 ^ b2;
let b3 = a2 ^ nibble_ror_1(b2) ^ ((8 * a2) & 15);
let a4 = Q0[2][a3 as usize];
let b4 = Q0[3][b3 as usize];
(b4 << 4) | a4
}
if K >= 3 {
y[0] = q1(y[0]) ^ list[4 * (4 + offset + 0)];
y[1] = q1(y[1]) ^ list[4 * (4 + offset + 1)];
y[2] = q0(y[2]) ^ list[4 * (4 + offset + 2)];
y[3] = q0(y[3]) ^ list[4 * (4 + offset + 3)];
}

fn q1(n: u8) -> u8 {
let a0 = (n >> 4) & 15;
let b0 = n & 15;
let a1 = a0 ^ b0;
let b1 = a0 ^ nibble_ror_1(b0) ^ ((8 * a0) & 15);
let a2 = Q1[0][a1 as usize];
let b2 = Q1[1][b1 as usize];
let a3 = a2 ^ b2;
let b3 = a2 ^ nibble_ror_1(b2) ^ ((8 * a2) & 15);
let a4 = Q1[2][a3 as usize];
let b4 = Q1[3][b3 as usize];
(b4 << 4) | a4
let a = 4 * (2 + offset);
let b = 4 * offset;

y[0] = q1(q0(q0(y[0]) ^ list[a + 0]) ^ list[b + 0]);
y[1] = q0(q1(q1(y[1]) ^ list[a + 1]) ^ list[b + 1]);
y[2] = q1(q1(q0(y[2]) ^ list[a + 2]) ^ list[b + 2]);
y[3] = q0(q1(q1(y[3]) ^ list[a + 3]) ^ list[b + 3]);

mds_mult(y)
}

// Pseudo-Hadamard Transform
fn pht(a: u32, b: u32) -> (u32, u32) {
(a.wrapping_add(b), a.wrapping_add(b << 1))
fn g(n: u32) -> u32 {
let mut out = 0;
let mut x = n.to_le_bytes();

for i in 0..4 {}

out
}

fn f(a: u32, b: u32, round: usize, subkeys: &[u32; 40]) -> (u32, u32) {
Expand All @@ -82,11 +51,10 @@ fn f(a: u32, b: u32, round: usize, subkeys: &[u32; 40]) -> (u32, u32) {
o
}

fn g(n: u32) -> u32 {
let mut x = n.to_le_bytes();

todo!()
}
const KEY_BYTES: usize = 16;
const KEY_WORDS: usize = KEY_BYTES / 4;
const K: usize = 2; // Keylength in bits divided by 64
const START: usize = 2;

pub struct TwoFish128 {
pub input_format: ByteFormat,
Expand Down Expand Up @@ -114,11 +82,6 @@ impl Default for TwoFish128 {

crate::block_cipher_builders! {TwoFish128, u128}


const KEY_BYTES: usize = 16;
const KEY_WORDS: usize = KEY_BYTES/4;
const K: usize = 2; // Keylength in bits divided by 64

impl TwoFish128 {
pub fn sbox(&self, n: u32, i: usize) -> u32 {
self.sboxes[i][n as usize]
Expand All @@ -131,7 +94,7 @@ impl TwoFish128 {

// Tale the even and odd words respectively
let m_e = words.into_iter().step_by(2).collect_vec();
let m_o = words.into_iter().skip(1).step_by(2).collect_vec();;
let m_o = words.into_iter().skip(1).step_by(2).collect_vec();
}

pub fn ksa_u32(&mut self, key: [u32; KEY_WORDS]) {}
Expand All @@ -145,28 +108,48 @@ impl TwoFish128 {
self.ksa_u32(bytes);
self
}

fn h(x: u32, list: [u32; K]) -> u32 {
todo!()
}
}

impl BlockCipher<16> for TwoFish128 {
fn encrypt_block(&self, bytes: &mut [u8]) {
let mut block = [0; 4];
fill_u32s_le(&mut block, bytes);

// Input Whitening
for i in 0..4 {
block[i] ^= self.subkeys[i]
}

for i in 0..8 {}

// Output Whitening
for i in 4..8 {
block[i - 4] ^= self.subkeys[i]
}

u32s_to_bytes_le(bytes, &block);
}

fn decrypt_block(&self, bytes: &mut [u8]) {
let mut block = [0; 4];
fill_u32s_le(&mut block, bytes);

// Input Whitening
for i in 0..4 {
block[i] ^= self.subkeys[i]
}

for i in (0..8).rev() {}

// Output Whitening
for i in 4..8 {
block[i - 4] ^= self.subkeys[i]
}

u32s_to_bytes_le(bytes, &block);
}
}

// crate::test_block_cipher!(

// )
// )

0 comments on commit 7529418

Please sign in to comment.