TEA(Tiny Encryption Algorithm) 是一种简单高效的加密算法,以加密解密速度快,实现简单著称。算法真的很简单,TEA算法每一次可以操作64-bit(8-byte),采用128-bit(16-byte)作为key,算法采用迭代的形式,推荐的迭代轮数是64轮,最少32轮。目前我只知道QQ一直用的是16轮TEA。没什么好说的,先给出C语言的源代码(默认是32轮):
void encrypt(unsigned long *v, unsigned long *k) { unsigned ], z=v[], sum=, i; /* set up */ unsigned long delta=0x9e3779b9; /* a key schedule constant */ unsigned ], b=k[], c=k[], d=k[]; /* cache key */ ; i < ; i++) { /* basic cycle start */ sum += delta; y += ((z<<) + a) ^ (z + sum) ^ ((z>>) + b); z += ((y<<) + c) ^ (y + sum) ^ ((y>>) + d);/* end cycle */ } v[]=y; v[]=z; } void decrypt(unsigned long *v, unsigned long *k) { unsigned ], z=v[], sum=0xC6EF3720, i; /* set up */ unsigned long delta=0x9e3779b9; /* a key schedule constant */ unsigned ], b=k[], c=k[], d=k[]; /* cache key */ ; i<; i++) { /* basic cycle start */ z -= ((y<<) + c) ^ (y + sum) ^ ((y>>) + d); y -= ((z<<) + a) ^ (z + sum) ^ ((z>>) + b); sum -= delta; /* end cycle */ } v[]=y; v[]=z; }
C语言写的用起来当然不方便,没关系,用C++封装以下就OK了:
util.h
#ifndef UTIL_H #define UTIL_H #include <string> #include <cstdlib> typedef unsigned char byte; typedef unsigned long ulong; /* *convert int to hex char. *example:10 -> 'A',15 -> 'F' */ char intToHexChar(int x); /* *convert hex char to int. *example:'A' -> 10,'F' -> 15 */ int hexCharToInt(char hex); using std::string; /* *convert a byte array to hex string. *hex string format example:"AF B0 80 7D" */ string bytesToHexString(const byte *in, size_t size); /* *convert a hex string to a byte array. *hex string format example:"AF B0 80 7D" */ size_t hexStringToBytes(const string &str, byte *out); #endif/*UTIL_H*/
util.cpp
#include "util.h" #include <vector> using namespace std; char intToHexChar(int x) { ] = { ', ', ', 'A', 'B', 'C', 'D', 'E', 'F' }; return HEX[x]; } int hexCharToInt(char hex) { hex = toupper(hex); if (isdigit(hex)) '); if (isalpha(hex)) ); ; } string bytesToHexString(const byte *in, size_t size) { string str; ; i < size; ++i) { int t = in[i]; ; ; str.append(, intToHexChar(a)); str.append(, intToHexChar(b)); ) str.append(, ' '); } return str; } size_t hexStringToBytes(const string &str, byte *out) { vector<string> vec; , prevPos = ; while ((currPos = str.find(' ', prevPos)) != string::npos) { string b(str.substr(prevPos, currPos - prevPos)); vec.push_back(b); prevPos = currPos + ; } if (prevPos < str.size()) { string b(str.substr(prevPos)); vec.push_back(b); } typedef vector<string>::size_type sz_type; sz_type size = vec.size(); ; i < size; ++i) { ]); ]); + b; } return size; }
tea.h
#ifndef TEA_H #define TEA_H /* *for htonl,htonl *do remember link "ws2_32.lib" */ #include <winsock2.h> #include "util.h" class TEA { public: TEA(, bool isNetByte = false); TEA(const TEA &rhs); TEA& operator=(const TEA &rhs); void encrypt(const byte *in, byte *out); void decrypt(const byte *in, byte *out); private: void encrypt(const ulong *in, ulong *out); void decrypt(const ulong *in, ulong *out); ulong ntoh(ulong netlong) { return _isNetByte ? ntohl(netlong) : netlong; } ulong hton(ulong hostlong) { return _isNetByte ? htonl(hostlong) : hostlong; } private: int _round; //iteration round to encrypt or decrypt bool _isNetByte; //whether input bytes come from network ]; //encrypt or decrypt key }; #endif/*TEA_H*/
tea.cpp
#include "tea.h" #include <cstring> //for memcpy,memset using namespace std; TEA::TEA(const byte *key, int round /*= 32*/, bool isNetByte /*= false*/) :_round(round) ,_isNetByte(isNetByte) { ) memcpy(_key, key, ); else memset(_key, , ); } TEA::TEA(const TEA &rhs) :_round(rhs._round) ,_isNetByte(rhs._isNetByte) { memcpy(_key, rhs._key, ); } TEA& TEA::operator=(const TEA &rhs) { if (&rhs != this) { _round = rhs._round; _isNetByte = rhs._isNetByte; memcpy(_key, rhs._key, ); } return *this; } void TEA::encrypt(const byte *in, byte *out) { encrypt((const ulong*)in, (ulong*)out); } void TEA::decrypt(const byte *in, byte *out) { decrypt((const ulong*)in, (ulong*)out); } void TEA::encrypt(const ulong *in, ulong *out) { ulong *k = (ulong*)_key; register ]); register ]); register ]); register ]); register ]); register ]); register ulong delta = 0x9E3779B9; /* (sqrt(5)-1)/2*2^32 */ register int round = _round; register ; while (round--) { /* basic cycle start */ sum += delta; y += ((z << ) + a) ^ (z + sum) ^ ((z >> ) + b); z += ((y << ) + c) ^ (y + sum) ^ ((y >> ) + d); } /* end cycle */ ] = ntoh(y); ] = ntoh(z); } void TEA::decrypt(const ulong *in, ulong *out) { ulong *k = (ulong*)_key; register ]); register ]); register ]); register ]); register ]); register ]); register ulong delta = 0x9E3779B9; /* (sqrt(5)-1)/2*2^32 */ register int round = _round; register ; ) sum = 0xC6EF3720; /* delta << 5*/ ) sum = 0xE3779B90; /* delta << 4*/ else sum = delta * round; while (round--) { /* basic cycle start */ z -= ((y << ) + c) ^ (y + sum) ^ ((y >> ) + d); y -= ((z << ) + a) ^ (z + sum) ^ ((z >> ) + b); sum -= delta; } /* end cycle */ ] = ntoh(y); ] = ntoh(z); }
需要说明的是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
#include "tea.h" #include "util.h" #include <iostream> using namespace std; int main() { const string plainStr("AD DE E2 DB B3 E2 DB B3"); const string keyStr("3A DA 75 21 DB E2 DB B3 11 B4 49 01 A5 C6 EA D4"); , SIZE_OUT = , SIZE_KEY = ; byte plain[SIZE_IN], crypt[SIZE_OUT], key[SIZE_KEY]; size_t size_in = hexStringToBytes(plainStr, plain); size_t size_key = hexStringToBytes(keyStr, key); if (size_in != SIZE_IN || size_key != SIZE_KEY) ; cout << "Plain: " << bytesToHexString(plain, size_in) << endl; cout << "Key : " << bytesToHexString(key, size_key) << endl; TEA tea(key, , true); tea.encrypt(plain, crypt); cout << "Crypt: " << bytesToHexString(crypt, SIZE_OUT) << endl; tea.decrypt(crypt, plain); cout << "Plain: " << bytesToHexString(plain, SIZE_IN) << endl; ; }
运行结果:
Plain: AD DE E2 DB B3 E2 DB B3 Key : 3A DA DB E2 DB B3 B4 A5 C6 EA D4 Crypt: 3B 3B 4D 8C 3A FD F2 Plain: AD DE E2 DB B3 E2 DB B3