TEA家族详解
TEA
TEA 的全称是“Tiny Encryption Algorithm”,1994年由英国剑桥大学的David j.wheeler发明的一种微型分组加密算法。该算法实现非常简单,通常只需要很精简的十几行代码,它的分组长度为 64 bit,密钥长度为 128 bit,采用 32 轮的 Feistel 结构。
算法原理
TEA 算法比较简单,没有子密钥生成算法,每一轮的 Feistel 结构也简单明了,采用的 ARX 计算也非常简单,值得注意的是 TEA 算法中有一个源于黄金分割比的魔数 0x9E3779B9,故不多分析,直接上 C 语言实现代码:
#include <stdint.h>
void encrypt (uint32_t v[2], const uint32_t k[4]) {
uint32_t v0=v[0], v1=v[1], sum=0, i; /* set up */
uint32_t delta=0x9E3779B9; /* a key schedule constant */
uint32_t k0=k[0], k1=k[1], k2=k[2], k3=k[3]; /* cache key */
for (i=0; i<32; i++) { /* basic cycle start */
sum += delta;
v0 += ((v1<<4) + k0) ^ (v1 + sum) ^ ((v1>>5) + k1);
v1 += ((v0<<4) + k2) ^ (v0 + sum) ^ ((v0>>5) + k3);
} /* end cycle */
v[0]=v0; v[1]=v1;
}
void decrypt (uint32_t v[2], const uint32_t k[4]) {
uint32_t v0=v[0], v1=v[1], sum=0xC6EF3720, i; /* set up; sum is (delta << 5) & 0xFFFFFFFF */
uint32_t delta=0x9E3779B9; /* a key schedule constant */
uint32_t k0=k[0], k1=k[1], k2=k[2], k3=k[3]; /* cache key */
for (i=0; i<32; i++) { /* basic cycle start */
v1 -= ((v0<<4) + k2) ^ (v0 + sum) ^ ((v0>>5) + k3);
v0 -= ((v1<<4) + k0) ^ (v1 + sum) ^ ((v1>>5) + k1);
sum -= delta;
} /* end cycle */
v[0]=v0; v[1]=v1;
}
XTEA
XTEA 算法是 TEA 算法的改进版本,主要修改了 Feistel 结构中的 ARX 计算和密钥的使用顺序,由于改变不大,故不多解释,直接上源码:
#include <stdint.h>
/* take 64 bits of data in v[0] and v[1] and 128 bits of key[0] - key[3] */
void encrypt(unsigned int num_rounds, uint32_t v[2], uint32_t const key[4]) {
unsigned int i;
uint32_t v0=v[0], v1=v[1], sum=0, delta=0x9E3779B9;
for (i=0; i < num_rounds; i++) {
v0 += (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]);
sum += delta;
v1 += (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum>>11) & 3]);
}
v[0]=v0; v[1]=v1;
}
void decrypt(unsigned int num_rounds, uint32_t v[2], uint32_t const key[4]) {
unsigned int i;
uint32_t v0=v[0], v1=v[1], delta=0x9E3779B9, sum=delta*num_rounds;
for (i=0; i < num_rounds; i++) {
v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum>>11) & 3]);
sum -= delta;
v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]);
}
v[0]=v0; v[1]=v1;
}
XXTEA
XXTEA 算法为前两代 TEA 家族算法的改进型,拥有更复杂的非平衡 feistel 结构,更灵活的加密块大小(至少为 64 bit)。源码如下:
#include <stdint.h>
#define DELTA 0x9e3779b9
#define MX (((z>>5^y<<2) + (y>>3^z<<4)) ^ ((sum^y) + (key[(p&3)^e] ^ z)))
void xxtea(uint32_t *v, int n, uint32_t const key[4]) {
uint32_t y, z, sum;
unsigned p, rounds, e;
if (n > 1) { /* Encrypt Part */
rounds = 6 + 52/n; /* calculate rounds */
sum = 0;
z = v[n-1];
do {
sum += DELTA;
e = (sum >> 2) & 3;
for (p=0; p<n-1; p++) {
y = v[p+1];
z = v[p] += MX;
}
y = v[0];
z = v[n-1] += MX;
} while (--rounds);
} else if (n < -1) { /* Decrypt Part */
n = -n;
rounds = 6 + 52/n;
sum = rounds*DELTA;
y = v[0];
do {
e = (sum >> 2) & 3;
for (p=n-1; p>0; p--) {
z = v[p-1];
y = v[p] -= MX;
}
z = v[n-1];
y = v[0] -= MX;
sum -= DELTA;
} while (--rounds);
}
}
是不是看起来和前两代差距很大,感觉像一个全新的算法。上面那个源码之所以看起来变化很大,主要是为了满足可变加密块大小做出的改变。如果将加密块大小固定为熟悉的 64 bit,上面的算法可以简化为:
#include <stdint.h>
void encrypt (uint32_t v[2], const uint32_t k[4]) {
uint32_t v0=v[0], v1=v[1], sum=0, i, e; /* set up */
uint32_t delta=0x9E3779B9; /* a key schedule constant */
for (i=0; i<32; i++) { /* basic cycle start */
sum += delta;
e = (sum >> 2) & 3;
v0 += (((v1>>5 ^ v1<<2) + (v1>>3 ^ v1<<4)) ^ ((sum ^ v1) + (k[e] ^ v1)));
v1 += (((v0>>5 ^ v0<<2) + (v0>>3 ^ v0<<4)) ^ ((sum ^ v0) + (k[e^1] ^ v0)));
} /* end cycle */
v[0]=v0; v[1]=v1;
}
void decrypt (uint32_t v[2], const uint32_t k[4]) {
uint32_t v0=v[0], v1=v[1], sum=0xC6EF3720, i, e; /* set up; sum is (delta << 5) & 0xFFFFFFFF */
uint32_t delta=0x9E3779B9; /* a key schedule constant */
for (i=0; i<32; i++) { /* basic cycle start */
e = (sum >> 2) & 3;
v1 -= (((v0>>5 ^ v0<<2) + (v0>>3 ^ v0<<4)) ^ ((sum ^ v0) + (k[e^1] ^ v0)));
v0 -= (((v1>>5 ^ v1<<2) + (v1>>3 ^ v1<<4)) ^ ((sum ^ v1) + (k[e] ^ v1)));
sum -= delta;
} /* end cycle */
v[0]=v0; v[1]=v1;
}
这个看着是不是顺眼多了。顺便附上正确性验证代码:
nt main(int argc, char** argv)
{
uint32_t v[2]= {1,2};
uint32_t const k[4]= {2,2,3,4};
int n = 2; //n的绝对值表示v的长度,取正表示加密,取负表示解密
// v为要加密的数据是两个32位无符号整数
// k为加密解密密钥,为4个32位无符号整数,即密钥长度为128位
printf("加密前原始数据:%u %u\n",v[0],v[1]);
xxtea(v, n, k);
printf("加密后的数据:%u %u\n",v[0],v[1]);
xxtea(v, -n, k);
printf("解密后的数据:%u %u\n",v[0],v[1]);
encrypt(v, k);
printf("加密后的数据:%u %u\n",v[0],v[1]);
decrypt(v, k);
printf("解密后的数据:%u %u\n",v[0],v[1]);
return 0;
}