Tiny Encryption Algorithm

(微型加密算法)

性质

块加密,对称加密

  • 块加密:将明文按一定大小分组之后用确定的算法和对称密钥对魅族分别加密,一般来说加密和解密函数为反函数,一般会进行多轮加密
  • 对称加密:加密解密双方使用同一个密钥加密解密或双方使用的是两个可以简单地相互推算的密钥

过程

定义与初始化

1
2
key = [a,b,c,d]#一般是4个值
delta = 0x9E3779B9

轮加密

1
2
3
4
5
6
7
for i in (0,len(m),2):
x = m[i]
y = m[i+1]
for j in range(32):
delta++
x += ((y << 4) + Key[0]) ^ (y + delta) ^ ((y >> 5) + Key[1])
y += ((x << 4) + Key[2]) ^ (x + delta) ^ ((x >> 5) + Key[3])

注:具体算法可能不同,但是一般都是x 由y和key改变,y由x和key改变,delta可能加可能减,但是一般情况不会把for i in (0,len(m),2)改成for i in (len-1),这样就不是块加密了

此处省略了&0xffffffff,需要让所有值都是int/dword,下面也是,之后不说了


XTEA的加密部分:

1
2
3
4
for i in range(n):
x += (((y << 4) ^ (y >> 5)) + y) ^ (delta + key[delta & 3])
delta++
y += (((x << 4) ^ (x >> 5)) + x) ^ (delta + key[(delta>>11) & 3])

注;相当于添加了与和位移,让key的取值不固定,但是框架没啥区别


XXTEA的加密部分

1
2
3
4
5
6
7
8
round = 6 + 52 // n #n为数据个数(输入数组长度),长度可以不是4的倍数
MX = lambda sum, y, z, p, e, k: ((z >> 5 ^ y << 2) + (y >> 3 ^ z << 4)) ^ ((sum ^ y) + (k[p & 3 ^ e] ^ z))
for i in range (round):
sum = (sum + DELTA) & 0xffffffff
e = sum >> 2 & 3
for p in range(n):
y = m[(p + 1) % n]
z = m[p] = (m[p] + MX(sum, y, z, p, e, k)) & 0xffffffff

贴一个c语言版

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
//也不知道网上都写的啥,看都看不懂//终于看懂了,好耶
#include <stdio.h>
#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* key)
{
uint32_t y, z, sum;
unsigned p, rounds, e;

if (n > 1) // encrypt
{
rounds = 6 + 52/n;
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
{
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);
}
}

// test
int main()
{
// 两个32位无符号整数,即待加密的64bit明文数据
uint32_t v[2] = {0x12345678, 0x78563412};
// 四个32位无符号整数,即128bit的key
uint32_t k[4]= {0x1, 0x2, 0x3, 0x4};
//n的绝对值表示v的长度,取正表示加密,取负表示解密
int n = 2;

printf("Data is : %x %x\n", v[0], v[1]);
xxtea(v, n, k);
printf("Encrypted data is : %x %x\n", v[0], v[1]);
xxtea(v, -n, k);
printf("Decrypted data is : %x %x\n", v[0], v[1]);

return 0;
}

修正:XXTEA和前面两个的区别在于:

前两个加密只是两个两个地相互加密,但是xxtea是用前一个值和后一个值加密这个位,按每个都加密一遍算一轮,一共进行round轮,这里放一个我理解的XXTEA,根据网上的测试,都是一样的,但是不知道为什么如果用我的测试样例就过不了(网上的版本会失效)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
//main.cpp
#include <iostream>
#include <stdint.h>
#include "Arr.h"

int XXTEA(Arr& input, uint32_t* const key) {
uint32_t delta = 0x9E3779B9;
uint32_t sum = 0;
uint32_t len = input.getsize();
uint32_t round = 52 / len + 6;
//初始化
for (int i = 0; i < round; i++)
{
sum += delta;
for (int now = 0; now < len; now++)
{
input[now] += (((input[now - 1] >> 5 ^ input[now + 1] << 2) +
(input[now + 1] >> 3 ^ input[now - 1] << 4)) ^ ((sum ^ input[now + 1]) +
(key[(now & 3) ^ ((sum >> 2) & 3)] ^ input[now - 1])));
}
}
return 0;
}

int deXXTEA(Arr& input, uint32_t* const key) {
uint32_t delta = 0x9E3779B9;
uint32_t len = input.getsize();
uint32_t round = 52 / len + 6;
uint32_t sum = delta * round;
for (int i = 0; i < round; i++)
{
for (int now = len - 1; now > -1; now--)
{
input[now] -= (((input[now - 1] >> 5 ^ input[now + 1] << 2) +
(input[now + 1] >> 3 ^ input[now - 1] << 4)) ^ ((sum ^ input[now + 1]) +
(key[(now & 3) ^ ((sum >> 2) & 3)] ^ input[now - 1])));
}
sum -= delta;
}
return 0;
}

int main(void) {
//Arr test = { 0x1234,0x5678,0x7777,0xbead };
Arr* test = new Arr((uint32_t*)"HELLO_MESSAGE_he", 4);//XXTEA要求必须是4的倍数
//Arr test = { 1,2 };
uint32_t const key[4] = { 2,2,3,4 };

XXTEA(*test, (uint32_t*)key);
std::cout << *test;
deXXTEA(*test, (uint32_t*)key);
std::cout << *test;
std::cout << (char*)test->getarr();
return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
//Arr.h
#pragma once
#include <initializer_list>
#include<algorithm>
#include<iostream>
#include <iomanip>
#include <cstring>
class Arr
{
private:
size_t size;
unsigned int* arr;
public:
Arr(size_t s);
Arr(uint32_t* p, unsigned s);
Arr(std::initializer_list<unsigned int> init);
~Arr();

unsigned int getsize() const;
unsigned int* getarr() const;

friend std::ostream& operator<<(std::ostream& os, const Arr& obj);
unsigned int& operator[](unsigned i);

unsigned int* begin() const;
unsigned int* end() const;
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
//Arr.cpp
#include "Arr.h"

Arr::Arr(size_t s) : size(s), arr(new uint32_t[s]) {
std::fill_n(arr, s, 0);
}

Arr::Arr(uint32_t* p, unsigned s) : Arr(s)
{
for (size_t i = 0; i < size; i++)
{
arr[i] = p[i];
}
}


Arr::Arr(std::initializer_list<unsigned int> init) :size(init.size()), arr(new unsigned int[init.size()])
{
std::copy(init.begin(), init.end(), arr);
}

Arr::~Arr()
{
delete[] arr;
}

unsigned int Arr::getsize() const
{
return size;
}

unsigned int* Arr::getarr() const
{
return arr;
}

unsigned int& Arr::operator[](unsigned i)
{
i = (i + size) % size;
i = i >= 0 ? i : (i + size);
return arr[i];
}

unsigned int* Arr::begin() const
{
return arr;
}

unsigned int* Arr::end() const
{
return arr + size;
}

std::ostream& operator<<(std::ostream& os, const Arr& obj)
{
os << "len: " << obj.getsize() << std::endl;
os << "element list:" << std::endl;
for (unsigned i : obj) {
os << "0x" << std::hex << std::uppercase << std::setw(8) << std::setfill('0') << i << std::endl;
}

return os;
}

破解方法

缺陷

似乎网上很多blog都提到了密钥表攻击TEA,但是我没找到

[等待施工][QAQ]