描述
TEA
TEA (Tiny Encryption Algorithm) 是一种块加密的对称加密算法
TEA使用一个128位(16字节)的密钥对64位(8字节)的明文进行分组运算, 明文被分成2个32位的分组( , ), 密钥被分为4个32位的分组 (, , , ). 加密涉及两轮的重复应用, 定义第轮与第轮运算如下:
这里定义:
其中是一个预定义的常量序列, 一般使用
这里的 其实在数学上等于
XTEA
XTEA (eXtended TEA) 是 TEA的升级版
XTEA也使用一个128位(16字节)的密钥对64位(8字节)的明文进行分组运算, 明文被分成2个32位的分组( , ), 密钥被分为4个32位的分组 (, , , ), 不过加密的的轮函数变了:
此时为:
也一般使用
XXTEA (BTEA)
XXTEA (Corrected Block TEA) , 其特点是运行在可变长度的块上, 这些块大小为32位的任意倍数(最小64位), 密钥仍然是128位, 被分为4个32位的分组. 对于较长的消息, XXTEA可能比XTEA更高效.
XXTEA 的轮数由数据长度决定 , 为待加密数据的长度
初始情况下, sum的值为0, z的值为待加密数据的最后一个字节, 在每一轮中进行如下操作
sum += delta;
e = (sum >> 2) & 3;
for r = 0 to datalen do
y = data[(r + 1) % data];
data[r] += MX(z, y, key, r, e, sum)
sum = sum.wrapping_add(DELTA);
let e = (sum >> 2) & 3;
for r in 0..block.len() {
// round
let y = block[(r + 1) % block.len()]; // right neighbour
block[r] = block[r].wrapping_add(mx(z, y, key, r, e as usize, sum));
z = block[r];
}一般是, 其中的定义为:
其结构是
,
,
这里给出2个实现
fn mx(z: u32, y: u32, key: &[u32], r: usize, e: usize, sum: u32) -> u32 {
let term1 = ((z >> 5) ^ (y << 2)).wrapping_add((y >> 3) ^ (z << 4));
let term2 = (sum ^ y).wrapping_add(key[(r ^ e) & 3] ^ z);
term1 ^ term2
}def mx(z, y, key, r, e, sum) -> int:
part1 = (z >> 5) ^ (y << 2)
part2 = (y >> 3) ^ (z << 4)
part3 = sum ^ y
part4 = key[(e ^ r) & 3] ^ z
return (part1 + part2) ^ (part3 + part4)实现
TEA
- rust
use std::mem;
const DELTA: u32 = 0x9E3779B9;
fn signed_tea(data: u32, key1: u32, key2: u32, delta: u32) -> u32 {
let p1 = data.wrapping_shl(4).wrapping_add(key1);
let p2 = data.wrapping_shr(5).wrapping_add(key2);
let p3 = data.wrapping_add(delta);
p1 ^ p2 ^ p3
}
fn encrypt_block(data: u64, key: [u32; 4], rounds: usize) -> u64 {
let [mut v0, mut v1] = unsafe { mem::transmute::<u64, [u32; 2]>(data) };
for i in 1..=rounds {
v0 = v0.wrapping_add(signed_tea(v1, key[0], key[1], DELTA.wrapping_mul(i as u32)));
v1 = v1.wrapping_add(signed_tea(v0, key[2], key[3], DELTA.wrapping_mul(i as u32)));
}
unsafe { mem::transmute::<[u32; 2], u64>([v0, v1]) }
}
fn decrypt_block(data: u64, key: [u32; 4], rounds: usize) -> u64 {
let [mut v0, mut v1] = unsafe { mem::transmute::<u64, [u32; 2]>(data) };
for i in (1..=rounds).rev() {
v1 = v1.wrapping_sub(signed_tea(v0, key[2], key[3], DELTA.wrapping_mul(i as u32)));
v0 = v0.wrapping_sub(signed_tea(v1, key[0], key[1], DELTA.wrapping_mul(i as u32)));
}
unsafe { mem::transmute::<[u32; 2], u64>([v0, v1]) }
}XTEA
- rust
use std::mem;
const DELTA: u32 = 0x9E3779B9;
fn encrypt_block(data: u64, key: [u32; 4], rounds: usize) -> u64 {
let [mut v0, mut v1] = unsafe { mem::transmute::<u64, [u32; 2]>(data) };
let mut sum: u32 = 0;
for _ in 0..rounds {
v0 = v0.wrapping_add(
(v1.wrapping_shl(4) ^ v1.wrapping_shr(5)).wrapping_add(v1)
^ sum.wrapping_add(key[sum as usize & 3]),
);
sum = sum.wrapping_add(DELTA);
v1 = v1.wrapping_add(
(v0.wrapping_shl(4) ^ v0.wrapping_shr(5)).wrapping_add(v0)
^ sum.wrapping_add(key[(sum as usize >> 11) & 3]),
);
}
unsafe { mem::transmute::<[u32; 2], u64>([v0, v1]) }
}
fn decrypt_block(data: u64, key: [u32; 4], rounds: usize) -> u64 {
let [mut v0, mut v1] = unsafe { mem::transmute::<u64, [u32; 2]>(data) };
let mut sum: u32 = DELTA.wrapping_mul(rounds as u32);
for _ in 0..rounds {
v1 = v1.wrapping_sub(
(v0.wrapping_shl(4) ^ v0.wrapping_shr(5)).wrapping_add(v0)
^ sum.wrapping_add(key[(sum as usize >> 11) & 3]),
);
sum = sum.wrapping_sub(DELTA);
v0 = v0.wrapping_sub(
(v1.wrapping_shl(4) ^ v1.wrapping_shr(5)).wrapping_add(v1)
^ sum.wrapping_add(key[sum as usize & 3]),
);
}
unsafe { mem::transmute::<[u32; 2], u64>([v0, v1]) }
}XXTEA
- rust
use std::slice;
const DELTA: u32 = 0x9E3779B9;
fn mx(z: u32, y: u32, key: &[u32], r: usize, e: usize, sum: u32) -> u32 {
(((z >> 5) ^ (y << 2)).wrapping_add((y >> 3) ^ (z << 4)))
^ ((sum ^ y).wrapping_add(key[(r ^ e) & 3] ^ z))
}
fn as_u32_slice(x: &[u8]) -> &[u32] {
unsafe { slice::from_raw_parts(x.as_ptr() as *const u32, x.len() / 4) }
}
fn as_u32_slice_mut(x: &mut [u8]) -> &mut [u32] {
unsafe { slice::from_raw_parts_mut(x.as_mut_ptr() as *mut u32, x.len() / 4) }
}
pub fn encrypt(block: &mut [u8], key: &[u8]) {
assert!(key.len() == 16);
assert!((block.len() & 3) == 0);
let key = as_u32_slice(key);
let block = as_u32_slice_mut(block);
let rounds = 6 + 52 / block.len();
let n = block.len() - 1;
let mut sum = 0u32;
let mut z = block[n]; // left neighbour for the first round
for _ in 0..rounds {
// cycle
sum = sum.wrapping_add(DELTA);
let e = (sum >> 2) & 3;
for r in 0..block.len() {
// round
let y = block[(r + 1) % block.len()]; // right neighbour
block[r] = block[r].wrapping_add(mx(z, y, key, r, e as usize, sum));
z = block[r];
}
}
}
pub fn decrypt(block: &mut [u8], key: &[u8]) {
assert!(key.len() == 16);
assert!((block.len() & 3) == 0);
let key = as_u32_slice(key);
let block = as_u32_slice_mut(block);
let rounds = 6 + 52 / block.len();
let mut sum = (rounds as u32).wrapping_mul(DELTA);
let mut y = block[0];
for _ in 0..rounds {
// cycle
let e = (sum >> 2) & 3;
for r in (0..block.len()).rev() {
// round
let z = block[(r + block.len() - 1) % block.len()];
block[r] = block[r].wrapping_sub(mx(z, y, key, r, e as usize, sum));
y = block[r];
}
sum = sum.wrapping_sub(DELTA);
}
}