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


     
    TEA(Tiny Encryption Algorithm) 是一种简单高效的加密算法,以加密解密速度快,实现简单著称。算法真的很简单,TEA算法每一次可以操作64-bit(8-byte),采用128-bit(16-byte)作为key,算法采用迭代的形式,推荐的迭代轮数是64轮,最少32轮。目前我只知道QQ一直用的是16轮TEA。没什么好说的,先给出C语言的源代码(默认是32轮):
     
    微型加密算法(TEA)及其相关变种(XTEA,Block TEA,XXTEA) 都是分组加密算法,它们很容易被描述,实现也很简单(典型的几行代码)。
     
    TEA 算法最初是由剑桥计算机实验室的 David Wheeler 和 Roger Needham 在 1994 年设计的。该算法使用 128 位的密钥为 64 位的信息块进行加密,它需要进行 64 轮迭代,尽管作者认为 32 轮已经足够了。该算法使用了一个神秘常数δ作为倍数,它来源于黄金比率,以保证每一轮加密都不相同。但δ的精确值似乎并不重要,这里 TEA 把它定义为 δ=「(√5 - 1)231」(也就是程序中的 0×9E3779B9)。

    之后 TEA 算法被发现存在缺陷,作为回应,设计者提出了一个 TEA 的升级版本——XTEA(有时也被称为“tean”)。XTEA 跟 TEA 使用了相同的简单运算,但它采用了截然不同的顺序,为了阻止密钥表攻击,四个子密钥(在加密过程中,原 128 位的密钥被拆分为 4 个 32 位的子密钥)采用了一种不太正规的方式进行混合,但速度更慢了。

    在跟描述 XTEA 算法的同一份报告中,还介绍了另外一种被称为 Block TEA 算法的变种,它可以对 32 位大小任意倍数的变量块进行操作。该算法将 XTEA 轮循函数依次应用于块中的每个字,并且将它附加于它的邻字。该操作重复多少轮依赖于块的大小,但至少需要 6 轮。该方法的优势在于它无需操作模式(CBC,OFB,CFB 等),密钥可直接用于信息。对于长的信息它可能比 XTEA 更有效率。

    在 1998 年,Markku-Juhani Saarinen 给出了一个可有效攻击 Block TEA 算法的代码,但之后很快 David J. Wheeler 和 Roger M. Needham 就给出了 Block TEA 算法的修订版,这个算法被称为 XXTEA。XXTEA 使用跟 Block TEA 相似的结构,但在处理块中每个字时利用了相邻字。它利用一个更复杂的 MX 函数代替了 XTEA 轮循函数,MX 使用 2 个输入量。
     
     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 *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; /* (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 *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; /* (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
     
     
     
     
     
  • 相关阅读:
    Memcache安全配置
    Iptables DDOS/CC 自动屏蔽脚本
    php浮点数精确运算
    Relearning PHP (2) – php 的浮点数float
    mybatis分页插件PageHelper的使用(转)
    深入理解mybatis参数
    @Param注解在mybatis中的使用以及传入参数的几种方式(转)
    idea常用快捷键大全(转)
    @ModelAttribute注解的作用
    参数绑定
  • 原文地址:https://www.cnblogs.com/huhu0013/p/3334890.html
Copyright © 2020-2023  润新知