TEA算法是由剑桥大学计算机实验室的David Wheeler和Roger Needham于1994年发明,TEA是Tiny Encryption Algorithm的缩写,以加密解密速度快,实现简单著称。TEA算法每一次可以操作64bit(8byte),采用128bit(16byte)作为key,算法采用迭代的形式,推荐的迭代轮数是64轮,最少32轮。为解决TEA算法密钥表攻击的问题,TEA算法先后经历了几次改进,从XTEA到BLOCK TEA,直至最新的XXTEA。XTEA也称做TEAN,它使用与TEA相同的简单运算,但四个子密钥采取不正规的方式进行混合以阻止密钥表攻击。Block TEA算法可以对32位的任意整数倍长度的变量块进行加解密的操作,该算法将XTEA轮循函数依次应用于块中的每个字,并且将它附加于被应用字的邻字。XXTEA使用跟Block TEA相似的结构,但在处理块中每个字时利用了相邻字,且用拥有两个输入量的MX函数代替了XTEA轮循函数。上面提到的相邻字其实就是数组中相邻的项。
TEA系列算法中均使用了一个DELTA常数,但DELTA的值对算法并无什么影响,只是为了避免不良的取值,推荐DELTA的值取为黄金分割数(5√-2)/2与232的乘积,取整后的十六进制值为0x9e3779B9,用于保证每一轮加密都不相同。
TEA采用与DES算法类似的Feistel结构,迭代的每次循环使用加法和移位操作,对明文和密钥进行扩散和混乱,实现明文的非线性变换。TEA密钥长度和迭代次数都是DES的两倍,抗“试错法”攻击的强度不低于DES算法。算法以32bits的字为运算单位,而不是耗费计算能力的逐位运算。算法没有采用DES那样的转换矩阵,它安全、高效、占用存储空间少,非常适合在嵌入式系统中应用, 据说QQ就是使用16轮迭代的TEA算法。
#define DELTA 0x9e3779b9
void tea_encrypt(unsigned int* v, unsigned int* key) {
unsigned int l = v[0], r = v[1], sum = 0;
for (size_t i = 0; i < 32; i++) { //进行32次迭代加密,Tea算法作者的建议迭代次数
l += (((r << 4) ^ (r >> 5)) + r) ^ (sum + key[sum & 3]);
sum += DELTA; //累加Delta的值
r += (((l << 4) ^ (l >> 5)) + l) ^ (sum + key[(sum >> 11) & 3]); //利用多次双位移和异或将明文与密钥扩散混乱,并将两个明文互相加密
}
v[0] = l;
v[1] = r;
}
//利用可逆性将加密过程逆转
void tea_decrypt(unsigned int* v, unsigned int* key) {
unsigned int l = v[0], r = v[1], sum = 0;
sum = DELTA * 32; //32次迭代累加后delta的值
for (size_t i = 0; i < 32; i++) {
r -= (((l << 4) ^ (l >> 5)) + l) ^ (sum + key[(sum >> 11) & 3]);
sum -= DELTA;
l -= (((r << 4) ^ (r >> 5)) + r) ^ (sum + key[sum & 3]);
}
v[0] = l;
v[1] = r;
}
测试:
int main(int argc, char const *argv[])
{
unsigned int v[2]={123,456},key[4]={0x11,0x22,0x33,0x44};
printf("%u,%u\n",v[0],v[1]);
tea_encrypt(v,key);
printf("%u,%u\n",v[0],v[1]);
tea_decrypt(v,key);
printf("%u,%u\n",v[0],v[1]);
return 0;
}
XTEA是TEA的扩展,也称做TEAN,它使用与TEA相同的简单运算,同样是一个64位块的Feistel密码,使用128位密钥,建议64轮, 但四个子密钥采取不正规的方式进行混合以阻止密钥表攻击
#define DELTA 0x9e3779b9
void xtea_encrypt(unsigned int* v, unsigned int* key) {
unsigned int l = v[0], r = v[1], sum = 0;
for (size_t i = 0; i < 32; i++) { //进行32次迭代加密,Tea算法作者的建议迭代次数
l += (((r << 4) ^ (r >> 5)) + r) ^ (sum + key[sum & 3]);
sum += DELTA; //累加Delta的值
r += (((l << 4) ^ (l >> 5)) + l) ^ (sum + key[(sum >> 11) & 3]);
}
v[0] = l;
v[1] = r;
}
void xtea_decrypt(unsigned int* v, unsigned int* key) {
unsigned int l = v[0], r = v[1], sum = 0;
sum = DELTA * 32; //32次迭代累加后delta的值
for (size_t i = 0; i < 32; i++) {
r -= (((l << 4) ^ (l >> 5)) + l) ^ (sum + key[(sum >> 11) & 3]);
sum -= DELTA;
l -= (((r << 4) ^ (r >> 5)) + r) ^ (sum + key[sum & 3]);
}
v[0] = l;
v[1] = r;
}
测试:
int main(int argc, char const *argv[])
{
unsigned int v[2]={123,456},key[4]={0x11,0x22,0x33,0x44};
printf("%u,%u\n",v[0],v[1]);
xtea_encrypt(v,key);
printf("%u,%u\n",v[0],v[1]);
xtea_decrypt(v,key);
printf("%u,%u\n",v[0],v[1]);
return 0;
}
XXTEA是一个非平衡Feistel网络分组密码,在可变长度块上运行,这些块是32位大小的任意倍数(最小64位),使用128位密钥, 是目前TEA系列中最安全的算法,但性能较上两种有所降低。
#define MX (((z >> 5) ^ (y << 2)) + ((y >> 3) ^ (z << 4))) ^ ((sum ^ y) + (key[(p & 3) ^ e] ^ z))
#define DELTA 0x9e3779b9
//XXTEA 加密,在处理数据流中每个数据时利用了相邻数据,使用MX函数计算加密值
static uint32_t * xxtea_uint_encrypt(uint32_t * data, size_t len, uint32_t * key) {
uint32_t n = (uint32_t)len - 1;
// 6 和 52 是怎么来的?
uint32_t z = data[n], y, p, q = 6 + 52 / (n + 1), sum = 0, e;
if (n < 1) return data;
while (0 < q--) {
sum += DELTA;
// 根据sum 计算得出0~3中的某一个数值, 用于MX中与p共同作用选择key数组中某个秘钥值
e = sum >> 2 & 3;
//遍历每个待加密的数据
for (p = 0; p < n; p++) {
//z的初值为data[len - 1],即将数据数组当做是环形队列来处理的,首尾相连,当加密data[0]时,需要用到data[len - 1],data[0],data[0 + 1],以及MX计算返回的的一个加密值,加密值与data[0]相加后达到加密的效果
y = data[p + 1];
z = data[p] += MX;
}
//当加密data[len-1]时,需要用到data[len - 2],data[len-1],data[0],以及MX计算返回的的一个加密值,加密值与data[len-1]相加后达到加密的效果
y = data[0];
z = data[n] += MX;
}
return data;
}
//XXTEA 解密,把加密的步骤反过来即可得到解密的方法
static uint32_t * xxtea_uint_decrypt(uint32_t * data, size_t len, uint32_t * key) {
uint32_t n = (uint32_t)len - 1;
uint32_t z, y = data[0], p, q = 6 + 52 / (n + 1), sum = q * DELTA, e;
if (n < 1) return data;
while (sum != 0) {
e = sum >> 2 & 3;
for (p = n; p > 0; p--) {
z = data[p - 1];
y = data[p] -= MX;
}
z = data[n];
y = data[0] -= MX;
sum -= DELTA;
}
return data;
}
测试:
int main(int argc, char const *argv[])
{
uint32_t v[2]={123,456},key[4]={0x11,0x22,0x33,0x44};
printf("%u,%u\n",v[0],v[1]);
xxtea_uint_encrypt(v,2,key);
printf("%u,%u\n",v[0],v[1]);
xxtea_uint_decrypt(v,2,key);
printf("%u,%u\n",v[0],v[1]);
return 0;
}
https://en.wikipedia.org/wiki/XXTEA
https://www.jiamisoft.com/blog/22953-louy.html
https://www.jiamisoft.com/blog/17621-xxteajiamisuanfa.html
https://www.jianshu.com/p/4272e0805da3