文档章节

TEA加密算法的C/C++实现

rise-worlds
 rise-worlds
发布于 2016/06/20 13:42
字数 1616
阅读 0
收藏 0
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;          /*  set up  */
 3      unsigned  long  delta = 0x9e3779b9 ;                  /*  a key schedule constant  */
 4      unsigned  long  a = k[ 0 ], b = k[ 1 ], c = k[ 2 ], d = k[ 3 ];    /*  cache key  */
 5       for  (i = 0 ; i  <   32 ; i ++ ) {                         /*  basic cycle start  */
 6          sum  +=  delta;
 7          y  +=  ((z << 4 +  a)  ^  (z  +  sum)  ^  ((z >> 5 +  b);
 8          z  +=  ((y << 4 +  c)  ^  (y  +  sum)  ^  ((y >> 5 +  d); /*  end cycle  */
 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;  /*  set up  */
16      unsigned  long  delta = 0x9e3779b9 ;                   /*  a key schedule constant  */
17      unsigned  long  a = k[ 0 ], b = k[ 1 ], c = k[ 2 ], d = k[ 3 ];     /*  cache key  */
18       for (i = 0 ; i < 32 ; i ++ ) {                             /*  basic cycle start  */
19          z  -=  ((y << 4 +  c)  ^  (y  +  sum)  ^  ((y >> 5 +  d);
20          y  -=  ((z << 4 +  a)  ^  (z  +  sum)  ^  ((z >> 5 +  b);
21          sum  -=  delta;                                 /*  end cycle  */
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  < cmath >
 6  #include  < cstdlib >
 7 
 8  typedef unsigned  char   byte ;
 9  typedef unsigned  long  ulong;
10 
11  inline  double  logbase( double  base,  double  x) {
12       return  log(x) / log(base);
13  }
14 
15  /*
16  *convert int to hex char.
17  *example:10 -> 'A',15 -> 'F'
18  */
19  char  intToHexChar( int  x);
20 
21  /*
22  *convert hex char to int.
23  *example:'A' -> 10,'F' -> 15
24  */
25  int  hexCharToInt( char  hex);
26 
27  using std::string;
28  /*
29  *convert a byte array to hex string.
30  *hex string format example:"AF B0 80 7D"
31  */
32  string bytesToHexString( const   byte   * in, size_t size);
33 
34  /*
35  *convert a hex string to a byte array.
36  *hex string format example:"AF B0 80 7D"
37  */
38  size_t hexStringToBytes( const  string  & str,  byte   * out);
39 
40  #endif /* UTIL_H */

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  /*
 5  *for htonl,htonl
 6  *do remember link "ws2_32.lib"
 7  */
 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_H */

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  /* = 32 */ , bool isNetByte  /* = false */ )
 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  * =  (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 /*  (sqrt(5)-1)/2*2^32  */
48      register  int  round  =  _round;
49      register ulong sum  =   0 ;
50 
51       while  (round -- ) {     /*  basic cycle start  */
52          sum  +=  delta;
53          y  +=  ((z  <<   4 +  a)  ^  (z  +  sum)  ^  ((z  >>   5 +  b);
54          z  +=  ((y  <<   4 +  c)  ^  (y  +  sum)  ^  ((y  >>   5 +  d);
55      }     /*  end cycle  */
56      out[ 0 =  ntoh(y);
57      out[ 1 =  ntoh(z);
58  }
59 
60  void  TEA::decrypt( const  ulong  * in, ulong  * out) {
61 
62      ulong  * =  (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 /*  (sqrt(5)-1)/2*2^32  */
70      register  int  round  =  _round;
71      register ulong sum  =   0 ;
72 
73       if  (round  ==   32 )
74          sum  =   0xC6EF3720 /*  delta << 5 */
75       else   if  (round  ==   16 )
76          sum  =   0xE3779B90 /*  delta << 4 */
77       else
78          sum  =  delta  <<  static_cast < int > (logbase( 2 , round));
79 
80       while  (round -- ) {     /*  basic cycle start  */
81          z  -=  ((y  <<   4 +  c)  ^  (y  +  sum)  ^  ((y  >>   5 +  d);
82          y  -=  ((z  <<   4 +  a)  ^  (z  +  sum)  ^  ((z  >>   5 +  b);
83          sum  -=  delta;
84      }     /*  end cycle  */
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

源代码下载: 点击下载

本文转载自:http://www.cnblogs.com/flying_bat/archive/2007/09/25/905135.html

共有 人打赏支持
rise-worlds

rise-worlds

粉丝 2
博文 1755
码字总数 0
作品 0
深圳
程序员
私信 提问
Linux下ELF文件的加壳

【业务需求】 1.用c或者c++ 编写一个程序 实现elf文件的加密生成一个新的elf文件,为加壳的elf,加密算法用c,c++自带的AES加密。 2.用c或者c++ 写解密算法,实现对加壳过的elf进行解密。 3....

林志滨
2017/11/20
1
2
无名Android逆向数据分析

第1课 恋恋DES加密初探+smali注入调试 第2课 stl逆向+jni动态加载识别+YOYO卡sha1实战 第3课 4399游戏盒DES-CBC算法+自定义salt分析 第4课 IDEA动态调试搭建与HTTPS抓包 第5课 搜狐AES+MD5+S...

13269051240
2018/05/21
0
0
GO语言版鹅厂广告交易实时平台价格解析

腾讯广告实时交易平台在向竞价胜出一方返回成交价的时候,先对价格进行TEA加密,再对密文进行BASE64编码,接收方先对BASE64解码,再对密文解密,双方事先约定密钥。鹅厂官网提供了C#、C++、J...

厉力文武
2018/08/01
0
0
北京招聘:-C++软件开发工程师-年薪13W以上-北京中讯汉扬科技发展有限公司

公司名称:北京中讯汉扬科技发展有限公司 公司网址:http://www.artmtech.com/ 联系人:赵女士 联系方式: QQ:398988329 请把简历投递到邮箱里:zhaopin_zxhr@163.com 年薪:13W+ (薪水无上限要求,...

落在人间的天使
2011/09/23
1K
15
C语言编程基础新手学习经典练习题和答案详解入门必备

C语言是面向过程的,而C++是面向对象的 C和C++的区别: C是一个结构化语言,它的重点在于算法和数据结构。C程序的设计首要考虑的是如何通过一个过程,对输入(或环境条件)进行运算处理得到...

小辰带你看世界
2018/05/13
0
0

没有更多内容

加载失败,请刷新页面

加载更多

Mysql(Mariadb)数据库主从复制

Mysql主从复制的实现原理图大致如下: MySQL之间数据复制的基础是以二进制日志文件(binary log file)来实现的,一台MySQL数据库一旦启用二进制日志后,其作为master,它数据库中所有操作都...

linux-tao
54分钟前
2
0
Mysql(Mariadb)数据库主从复制

Mysql主从复制的实现原理图大致如下: MySQL之间数据复制的基础是以二进制日志文件(binary log file)来实现的,一台MySQL数据库一旦启用二进制日志后,其作为master,它数据库中所有操作都...

Linux就该这么学
今天
2
0
Mysql(Mariadb)数据库主从复制

Mysql主从复制的实现原理图大致如下: MySQL之间数据复制的基础是以二进制日志文件(binary log file)来实现的,一台MySQL数据库一旦启用二进制日志后,其作为master,它数据库中所有操作都...

xiangyunyan
今天
2
0
Android 自定义Path贝塞尔曲线View实践——旋转的花朵

一、关于贝塞尔曲线 在工业设计方面贝塞尔曲线有很多用途,同样,在Android中,贝塞尔曲线结合Path类可以实现更复杂的图形,这里我们给一个案例,来实现一种旋转的花朵。对于贝赛尔曲线的理解...

IamOkay
今天
3
0
7、redis主从复制和sentinel配置高可用

一:redis主从配置 1、环境准备 master : 192.168.50.10 6179 slave1: 192.168.50.10 6279 slave2: 192.168.50.10 6379 2、redis.conf配置文件配置 master port 6179......

刘付kin
今天
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部