TEA(Tiny Encryption Algorithm) 是一種簡單高效的加密算法,以加密解密速度快,實作簡單著稱。算法真的很簡單,TEA算法每一次可以操作64-bit(8-byte),采用128-bit(16-byte)作為key,算法采用疊代的形式,推薦的疊代輪數是64輪,最少32輪。目前我隻知道QQ一直用的是16輪TEA。沒什麼好說的,先給出C語言的源代碼(預設是32輪):
1 void encrypt(unsigned long *v, unsigned long * k) {
2 unsigned long y=v[0], z=v[1], sum=0, i;
3 unsigned long delta=0x9e3779b9;
4 unsigned long a=k[0], b=k[1], c=k[2], d=k[3];
5 for (i=0; i < 32; i++) {
6 sum += delta;
7 y += ((z<<4) + a) ^ (z + sum) ^ ((z>>5) + b);
8 z += ((y<<4) + c) ^ (y + sum) ^ ((y>>5) + d);
9 }
10 v[0]= y;
11 v[1]= z;
12 }
13
14 void decrypt(unsigned long *v, unsigned long * k) {
15 unsigned long y=v[0], z=v[1], sum=0xC6EF3720, i;
16 unsigned long delta=0x9e3779b9;
17 unsigned long a=k[0], b=k[1], c=k[2], d=k[3];
18 for(i=0; i<32; i++) {
19 z -= ((y<<4) + c) ^ (y + sum) ^ ((y>>5) + d);
20 y -= ((z<<4) + a) ^ (z + sum) ^ ((z>>5) + b);
21 sum -= delta;
22 }
23 v[0]= y;
24 v[1]= z;
25 }
C語言寫的用起來當然不友善,沒關系,用C++封裝以下就OK了:
util.h
1 #ifndef UTIL_H
2 #define UTIL_H
3
4 #include <string>
5 #include <cstdlib>
6
7 typedef unsigned char byte ;
8 typedef unsigned long ulong;
9
10
14 char intToHexChar(int x);
15
16
20 int hexCharToInt(char hex);
21
22 using std::string;
23
27 string bytesToHexString(const byte * in, size_t size);
28
29
33 size_t hexStringToBytes(const string &str, byte * out);
34
35 #endif
util.cpp
1 #include "util.h"
2 #include <vector>
3
4 using namespace std;
5
6 char intToHexChar(int x) {
7 static const char HEX[16] = {
8 '0', '1', '2', '3' ,
9 '4', '5', '6', '7' ,
10 '8', '9', 'A', 'B' ,
11 'C', 'D', 'E', 'F'
12 };
13 return HEX[x];
14 }
15
16 int hexCharToInt(char hex) {
17 hex = toupper(hex);
18 if (isdigit(hex))
19 return (hex - '0' );
20 if (isalpha(hex))
21 return (hex - 'A' + 10 );
22 return 0 ;
23 }
24
25 string bytesToHexString(const byte * in, size_t size) {
26 string str;
27 for (size_t i = 0; i < size; ++ i) {
28 int t = in[i];
29 int a = t / 16 ;
30 int b = t % 16 ;
31 str.append(1 , intToHexChar(a));
32 str.append(1 , intToHexChar(b));
33 if (i != size - 1 )
34 str.append(1, ' ' );
35 }
36 return str;
37 }
38
39 size_t hexStringToBytes(const string &str, byte * out) {
40
41 vector<string> vec;
42 string::size_type currPos = 0, prevPos = 0 ;
43 while ((currPos = str.find(' ', prevPos)) != string::npos) {
44 string b(str.substr(prevPos, currPos - prevPos));
45 vec.push_back(b);
46 prevPos = currPos + 1 ;
47 }
48 if (prevPos < str.size()) {
49 string b(str.substr(prevPos));
50 vec.push_back(b);
51 }
52 typedef vector<string> ::size_type sz_type;
53 sz_type size = vec.size();
54 for (sz_type i = 0; i < size; ++ i) {
55 int a = hexCharToInt(vec[i][0 ]);
56 int b = hexCharToInt(vec[i][1 ]);
57 out[i] = a * 16 + b;
58 }
59 return size;
60 }
tea.h
1 #ifndef TEA_H
2 #define TEA_H
3
4
8 #include <winsock2.h>
9 #include "util.h"
10
11 class TEA {
12 public :
13 TEA(const byte *key, int round = 32, bool isNetByte = false );
14 TEA(const TEA & rhs);
15 TEA& operator=(const TEA & rhs);
16 void encrypt(const byte *in, byte * out);
17 void decrypt(const byte *in, byte * out);
18 private :
19 void encrypt(const ulong *in, ulong * out);
20 void decrypt(const ulong *in, ulong * out);
21 ulong ntoh(ulong netlong) { return _isNetByte ? ntohl(netlong) : netlong; }
22 ulong hton(ulong hostlong) { return _isNetByte ? htonl(hostlong) : hostlong; }
23 private :
24 int _round; //iteration round to encrypt or decrypt
25 bool _isNetByte; //whether input bytes come from network
26 byte _key[16]; //encrypt or decrypt key
27 };
28
29 #endif
tea.cpp
1 #include "tea.h"
2 #include <cstring> //for memcpy,memset
3
4 using namespace std;
5
6 TEA::TEA(const byte *key, int round , bool isNetByte )
7 :_round(round)
8 ,_isNetByte(isNetByte) {
9 if (key != 0 )
10 memcpy(_key, key, 16 );
11 else
12 memset(_key, 0, 16 );
13 }
14
15 TEA::TEA(const TEA & rhs)
16 :_round(rhs._round)
17 ,_isNetByte(rhs._isNetByte) {
18 memcpy(_key, rhs._key, 16 );
19 }
20
21 TEA& TEA::operator=(const TEA & rhs) {
22 if (&rhs != this ) {
23 _round = rhs._round;
24 _isNetByte = rhs._isNetByte;
25 memcpy(_key, rhs._key, 16 );
26 }
27 return *this ;
28 }
29
30 void TEA::encrypt(const byte *in, byte * out) {
31 encrypt((const ulong*)in, (ulong* )out);
32 }
33
34 void TEA::decrypt(const byte *in, byte * out) {
35 decrypt((const ulong*)in, (ulong* )out);
36 }
37
38 void TEA::encrypt(const ulong *in, ulong * out) {
39
40 ulong *k = (ulong* )_key;
41 register ulong y = ntoh(in[0 ]);
42 register ulong z = ntoh(in[1 ]);
43 register ulong a = ntoh(k[0 ]);
44 register ulong b = ntoh(k[1 ]);
45 register ulong c = ntoh(k[2 ]);
46 register ulong d = ntoh(k[3 ]);
47 register ulong delta = 0x9E3779B9;
48 register int round = _round;
49 register ulong sum = 0 ;
50
51 while (round--) {
52 sum += delta;
53 y += ((z << 4) + a) ^ (z + sum) ^ ((z >> 5) + b);
54 z += ((y << 4) + c) ^ (y + sum) ^ ((y >> 5) + d);
55 }
56 out[0] = ntoh(y);
57 out[1] = ntoh(z);
58 }
59
60 void TEA::decrypt(const ulong *in, ulong * out) {
61
62 ulong *k = (ulong* )_key;
63 register ulong y = ntoh(in[0 ]);
64 register ulong z = ntoh(in[1 ]);
65 register ulong a = ntoh(k[0 ]);
66 register ulong b = ntoh(k[1 ]);
67 register ulong c = ntoh(k[2 ]);
68 register ulong d = ntoh(k[3 ]);
69 register ulong delta = 0x9E3779B9;
70 register int round = _round;
71 register ulong sum = 0 ;
72
73 if (round == 32 )
74 sum = 0xC6EF3720;
75 else if (round == 16 )
76 sum = 0xE3779B90;
77 else
78 sum = delta * round;
79
80 while (round--) {
81 z -= ((y << 4) + c) ^ (y + sum) ^ ((y >> 5) + d);
82 y -= ((z << 4) + a) ^ (z + sum) ^ ((z >> 5) + b);
83 sum -= delta;
84 }
85 out[0] = ntoh(y);
86 out[1] = ntoh(z);
87 }
需要說明的是TEA的構造函數:
TEA(const byte *key, int round = 32, bool isNetByte = false);
1. key - 加密或解密用的128-bit(16byte)密鑰。
2. round - 加密或解密的輪數,常用的有64,32,16。
3. isNetByte - 用來标記待處理的位元組是不是來自網絡,為true時在加密/解密前先要轉換成本地位元組,執行加密/解密,然後再轉換回網絡位元組。偷偷告訴你,QQ就是這樣做的!
最後當然少不了測試代碼:
test.cpp
1 #include "tea.h"
2 #include "util.h"
3 #include <iostream>
4
5 using namespace std;
6
7 int main() {
8
9 const string plainStr("AD DE E2 DB B3 E2 DB B3" );
10 const string keyStr("3A DA 75 21 DB E2 DB B3 11 B4 49 01 A5 C6 EA D4" );
11 const int SIZE_IN = 8, SIZE_OUT = 8, SIZE_KEY = 16 ;
12 byte plain[SIZE_IN], crypt[SIZE_OUT], key[SIZE_KEY];
13
14 size_t size_in = hexStringToBytes(plainStr, plain);
15 size_t size_key = hexStringToBytes(keyStr, key);
16
17 if (size_in != SIZE_IN || size_key != SIZE_KEY)
18 return -1 ;
19
20 cout << "Plain: " << bytesToHexString(plain, size_in) << endl;
21 cout << "Key : " << bytesToHexString(key, size_key) << endl;
22
23 TEA tea(key, 16, true );
24 tea.encrypt(plain, crypt);
25 cout << "Crypt: " << bytesToHexString(crypt, SIZE_OUT) << endl;
26
27 tea.decrypt(crypt, plain);
28 cout << "Plain: " << bytesToHexString(plain, SIZE_IN) << endl;
29 return 0 ;
30 }
運作結果:
Plain: AD DE E2 DB B3 E2 DB B3
Key : 3A DA 75 21 DB E2 DB B3 11 B4 49 01 A5 C6 EA D4
Crypt: 3B 3B 4D 8C 24 3A FD F2
Plain: AD DE E2 DB B3 E2 DB B3
源代碼下載下傳: 點選下載下傳