天天看點

TEA加密算法的C/C++實作

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

源代碼下載下傳: 點選下載下傳

繼續閱讀