zoukankan      html  css  js  c++  java
  • QQ通讯协议里的TEA加解密算法

    1. #include <stdio.h> 
    2. #include <stdlib.h> 
    3. #include <memory.h> 
    4. #include <string.h> 
    5. #include <time.h> 
    6.   
    7. //#define CRYPT_ONE_BYTE 
    8.   
    9. typedef char int8 ; 
    10. typedef unsigned char uint8 ; 
    11. typedef short int16 ; 
    12. typedef unsigned short uint16 ; 
    13. typedef long int32 ; 
    14. typedef unsigned long uint32 ; 
    15.   
    16. typedef struct tagTEACTX 
    17.     uint8 buf[8] ; 
    18.     uint8 bufPre[8] ; 
    19.     const uint8 *pKey ; //指向16字节的key  
    20.     uint8 *pCrypt ; 
    21.     uint8 *pCryptPre ; 
    22. } TEACTX, *LPTEACTX ; 
    23.   
    24. uint16 Host2NetShort(uint16 usHost) 
    25.     const uint16 us = 0x1234 ; 
    26.     return ((uint8 *)&us)[0] == 0x12 ? usHost : ((usHost>>8) | (usHost<<8)) ; 
    27.   
    28. uint16 Net2HostShort(uint16 usNet) 
    29.     return Host2NetShort(usNet) ; 
    30.   
    31. uint32 Host2NetLong(uint32 ulHost) 
    32.     const uint16 us = 0x1234 ; 
    33.     return ((uint8 *)&us)[0] == 0x12 ? ulHost : (((ulHost>>8) & 0xFF00) |  
    34.         ((ulHost<<8) & 0xFF0000) | (ulHost<<24) | (ulHost>>24)) ; 
    35.   
    36. uint32 Net2HostLong(uint32 ulHost) 
    37.     return Host2NetLong(ulHost) ; 
    38.   
    39. //TEA加密。v明文8字节。k密钥16字节。w密文输出8字节。  
    40. void EnCipher(const uint32 *const v, const uint32 *const k, uint32 *const w) 
    41.     register uint32  
    42.         y     = Host2NetLong(v[0]), 
    43.         z     = Host2NetLong(v[1]), 
    44.         a     = Host2NetLong(k[0]), 
    45.         b     = Host2NetLong(k[1]), 
    46.         c     = Host2NetLong(k[2]), 
    47.         d     = Host2NetLong(k[3]), 
    48.         n     = 0x10,       /* do encrypt 16 (0x10) times */ 
    49.         sum   = 0, 
    50.         delta = 0x9E3779B9; /*  0x9E3779B9 - 0x100000000 = -0x61C88647 */ 
    51.   
    52.     while (n-- > 0) 
    53.     { 
    54.         sum += delta; 
    55.         y += ((z << 4) + a) ^ (z + sum) ^ ((z >> 5) + b); 
    56.         z += ((y << 4) + c) ^ (y + sum) ^ ((y >> 5) + d); 
    57.     } 
    58.   
    59.     w[0] = Net2HostLong(y); 
    60.     w[1] = Net2HostLong(z); 
    61.   
    62. //TEA解密。v密文8字节。k密钥16字节。w明文输出8字节。  
    63. void DeCipher(const uint32 *const v, const uint32 *const k, uint32 *const w) 
    64.     register uint32 
    65.         y     = Host2NetLong(v[0]), 
    66.         z     = Host2NetLong(v[1]), 
    67.         a     = Host2NetLong(k[0]), 
    68.         b     = Host2NetLong(k[1]), 
    69.         c     = Host2NetLong(k[2]), 
    70.         d     = Host2NetLong(k[3]), 
    71.         n     = 0x10, 
    72.         sum   = 0xE3779B90,  
    73.         /* why this ? must be related with n value*/ 
    74.         delta = 0x9E3779B9; 
    75.   
    76.     /* sum = delta<<5, in general sum = delta * n */ 
    77.     while (n-- > 0) 
    78.     { 
    79.         z -= ((y << 4) + c) ^ (y + sum) ^ ((y >> 5) + d); 
    80.         y -= ((z << 4) + a) ^ (z + sum) ^ ((z >> 5) + b); 
    81.         sum -= delta; 
    82.     } 
    83.   
    84.     w[0] = Net2HostLong(y); 
    85.     w[1] = Net2HostLong(z); 
    86.   
    87. uint32 Random(void) 
    88.     return (uint32)rand(); 
    89.     //return 0xdead ; 
    90.   
    91. //每次8字节加密  
    92. static void EncryptEach8Bytes(TEACTX *pCtx) 
    93. #ifdef CRYPT_ONE_BYTE 
    94.     uint32 i ; 
    95.     uint8 *pPlain8, *pPlainPre8, *pCrypt8, *pCryptPre8 ; 
    96.     pPlain8 = (uint8 *)pCtx->buf ; 
    97.     pPlainPre8 = (uint8 *)pCtx->bufPre ; 
    98.     pCrypt8 = (uint8 *)pCtx->pCrypt ; 
    99.     pCryptPre8 = (uint8 *)pCtx->pCryptPre ; 
    100.     //本轮明文与上一轮的密文异或  
    101.     for(i=0; i<8; i++) 
    102.         pPlain8[i] ^= pCryptPre8[i] ; 
    103.     //再对异或后的明文加密  
    104.     EnCipher((uint32 *)pPlain8, (uint32 *)pCtx->pKey, (uint32 *)pCrypt8) ; 
    105.     //将加密后的密文与上一轮的明文(其实是上一轮明文与上上轮密文异或结果)异或 
    106.     for(i=0; i<8; i++) 
    107.         pCrypt8[i] ^= pPlainPre8[i] ; 
    108.     // 
    109.     for(i=0; i<8; i++) 
    110.         pPlainPre8[i] = pPlain8[i] ; 
    111. #else 
    112.     uint32 *pPlain8, *pPlainPre8, *pCrypt8, *pCryptPre8 ; 
    113.     pPlain8 = (uint32 *)pCtx->buf ; 
    114.     pPlainPre8 = (uint32 *)pCtx->bufPre ; 
    115.     pCrypt8 = (uint32 *)pCtx->pCrypt ; 
    116.     pCryptPre8 = (uint32 *)pCtx->pCryptPre ; 
    117.     pPlain8[0] ^= pCryptPre8[0] ; 
    118.     pPlain8[1] ^= pCryptPre8[1] ; 
    119.     EnCipher(pPlain8, (const uint32 *)pCtx->pKey, pCrypt8) ; 
    120.     pCrypt8[0] ^= pPlainPre8[0] ; 
    121.     pCrypt8[1] ^= pPlainPre8[1] ; 
    122.     pPlainPre8[0] = pPlain8[0] ; 
    123.     pPlainPre8[1] = pPlain8[1] ; 
    124. #endif 
    125.     pCtx->pCryptPre = pCtx->pCrypt ; 
    126.     pCtx->pCrypt += 8 ; 
    127.   
    128. //加密。pPlain指向待加密的明文。ulPlainLen明文长度。pKey密钥16字节。 
    129. //pOut指向密文输出缓冲区。pOutLen输入输出参数,指示输出缓冲区长度、密文长度。  
    130. uint32 Encrypt(TEACTX *pCtx, const uint8 *pPlain, uint32 ulPlainLen,  
    131.     const uint8 *pKey, uint8 *pOut, uint32 *pOutLen) 
    132.     uint32 ulPos, ulPadding, ulOut ; 
    133.     const uint8 *p ; 
    134.     if(pPlain == NULL || ulPlainLen == 0 || pOutLen == NULL) 
    135.         return 0 ; 
    136.     //计算需要填充的字节数 
    137.     //整个加密流程下来,不管明文长度多少,填充10个字节是固定的, 
    138.     //然后再根据明文的长度计算还需要填充的字节数。  
    139.     ulPos = (8 - ((ulPlainLen + 10) & 0x07)) & 0x07 ; 
    140.     //计算加密后的长度 
    141.     ulOut = 1 + ulPos + 2 + ulPlainLen + 7 ; 
    142.     if(*pOutLen < ulOut) 
    143.     { 
    144.         *pOutLen = ulOut ; 
    145.         return 0 ; 
    146.     } 
    147.     *pOutLen = ulOut ; 
    148.     memset(pCtx, 0, sizeof(TEACTX)) ; 
    149.     pCtx->pCrypt = pOut ; 
    150.     pCtx->pCryptPre = pCtx->bufPre ; 
    151.     pCtx->pKey = pKey ; 
    152.     //buf[0]的最低3bit位等于所填充的长度 
    153.     pCtx->buf[0] = (uint8)((Random() & 0xF8) | ulPos) ; 
    154.     //用随机数填充上面计算得到的填充长度(每个字节填充的内容是一样的)。 
    155.     //这里填充的起始位置是&buf[1]。 
    156.     memset(pCtx->buf+1, (uint8)Random(), ulPos++) ; 
    157.     //至少再填充两字节 
    158.     for(ulPadding=0; ulPadding<2; ulPadding++) 
    159.     { 
    160.         if(ulPos == 8) 
    161.         { 
    162.             EncryptEach8Bytes(pCtx) ; 
    163.             ulPos = 0 ; 
    164.         } 
    165.         pCtx->buf[ulPos++] = (uint8)Random() ; 
    166.     } 
    167.     p = pPlain ; 
    168.     while(ulPlainLen > 0) 
    169.     { 
    170.         if(ulPos == 8) 
    171.         { 
    172.             EncryptEach8Bytes(pCtx) ; 
    173.             ulPos = 0 ; 
    174.         } 
    175.         pCtx->buf[ulPos++] = *(p++) ; 
    176.         ulPlainLen-- ; 
    177.     } 
    178.     //末尾再添加7字节0后加密,在解密过程的时候可以用来判断key是否正确。  
    179.     for(ulPadding=0; ulPadding<7; ulPadding++) 
    180.         pCtx->buf[ulPos++] = 0x00 ; 
    181.     // 
    182.     EncryptEach8Bytes(pCtx) ; 
    183.     return ulOut ; 
    184.   
    185. //每次8字节进行解密  
    186. static void DecryptEach8Bytes(TEACTX *pCtx) 
    187. #ifdef CRYPT_ONE_BYTE 
    188.     uint32 i ; 
    189.     uint8 bufTemp[8] ; 
    190.     uint8 *pBuf8, *pBufPre8, *pCrypt8, *pCryptPre8 ; 
    191.     pBuf8 = (uint8 *)pCtx->buf ; 
    192.     pBufPre8 = (uint8 *)pCtx->bufPre ; 
    193.     pCrypt8 = (uint8 *)pCtx->pCrypt ; 
    194.     pCryptPre8 = (uint8 *)pCtx->pCryptPre ; 
    195.     //当前的密文与前一轮明文(实际是前一轮明文与前前轮密文异或结果)异或  
    196.     for(i=0; i<8; i++) 
    197.         bufTemp[i] = pCrypt8[i] ^ pBufPre8[i] ; 
    198.     //异或后的结果再解密(解密后得到当前名文与前一轮密文异或的结果,并非真正明文) 
    199.     DeCipher((uint32 *)bufTemp, (uint32 *)pCtx->pKey, (uint32 *)pBufPre8) ; 
    200.     //解密后的结果与前一轮的密文异或,得到真正的明文  
    201.     for(i=0; i<8; i++) 
    202.         pBuf8[i] = pBufPre8[i] ^ pCryptPre8[i] ; 
    203. #else 
    204.     uint32 bufTemp[2] ; 
    205.     uint32 *pBuf8, *pBufPre8, *pCrypt8, *pCryptPre8 ; 
    206.     pBuf8 = (uint32 *)pCtx->buf ; 
    207.     pBufPre8 = (uint32 *)pCtx->bufPre ; 
    208.     pCrypt8 = (uint32 *)pCtx->pCrypt ; 
    209.     pCryptPre8 = (uint32 *)pCtx->pCryptPre ; 
    210.     bufTemp[0] = pCrypt8[0] ^ pBufPre8[0] ; 
    211.     bufTemp[1] = pCrypt8[1] ^ pBufPre8[1] ; 
    212.     DeCipher(bufTemp, (const uint32 *)pCtx->pKey, pBufPre8) ; 
    213.     pBuf8[0] = pBufPre8[0] ^ pCryptPre8[0] ; 
    214.     pBuf8[1] = pBufPre8[1] ^ pCryptPre8[1] ; 
    215. #endif 
    216.     pCtx->pCryptPre = pCtx->pCrypt ; 
    217.     pCtx->pCrypt += 8 ; 
    218.   
    219. //解密。pCipher指向待解密密文。ulCipherLen密文长度。pKey密钥16字节。 
    220. //pOut指向明文输出缓冲区。pOutLen输入输出参数,指示输出缓冲区长度、明文长度。  
    221. uint32 Decrypt(TEACTX *pCtx, const uint8 *pCipher, uint32 ulCipherLen,  
    222.     const uint8 *pKey, uint8 *pOut, uint32 *pOutLen) 
    223.     uint32 ulPos, ulPadding, ulOut, ul ; 
    224.     // 待解密的数据长度最少16字节,并且长度满足是8的整数倍。 
    225.     if(pCipher == NULL || pOutLen == NULL ||  
    226.             ulCipherLen < 16 || (ulCipherLen & 0x07) != 0) 
    227.         return 0 ; 
    228.     // 先解密头8字节,以便获取第一轮加密时填充的长度。 
    229.     DeCipher((const uint32 *)pCipher, (const uint32 *)pKey, (uint32 *)pCtx->bufPre) ; 
    230.     for(ul=0; ul<8; ul++) 
    231.         pCtx->buf[ul] = pCtx->bufPre[ul] ; 
    232.     ulPos = pCtx->buf[0] & 0x07 ; //第一轮加密时填充的长度 
    233.     if(ulPos > 1) 
    234.     { 
    235.         for(ulOut=2; ulOut<=ulPos; ulOut++) 
    236.         { 
    237.             if(pCtx->buf[1] != pCtx->buf[ulOut]) 
    238.             { 
    239.                 *pOutLen = 0 ; 
    240.                 return 0 ; //解密失败  
    241.             } 
    242.         } 
    243.     } 
    244.     ulOut = ulCipherLen - ulPos - 10 ; 
    245.     if(ulPos + 10 > ulCipherLen || *pOutLen < ulOut) 
    246.         return 0 ; 
    247.     pCtx->pCryptPre = (uint8 *)pCipher ; 
    248.     pCtx->pCrypt = (uint8 *)pCipher + 8 ; 
    249.     ulPos++ ; 
    250.     for(ulPadding=0; ulPadding<2; ulPadding++) 
    251.     { 
    252.         if(ulPos == 8) 
    253.         { 
    254.             DecryptEach8Bytes(pCtx) ; 
    255.             ulPos = 0 ; 
    256.         } 
    257.         ulPos++ ; 
    258.     } 
    259.     // 
    260.     for(ul=0; ul<ulOut; ul++) 
    261.     { 
    262.         if(ulPos == 8) 
    263.         { 
    264.             DecryptEach8Bytes(pCtx) ; 
    265.             ulPos = 0 ; 
    266.         } 
    267.         pOut[ul] = pCtx->buf[ulPos] ; 
    268.         ulPos++ ; 
    269.     } 
    270.     // 
    271.     for(ulPadding=0; ulPadding<7; ulPadding++) 
    272.     { 
    273.         if(ulPos < 8) 
    274.         { 
    275.             if(pCtx->buf[ulPos] != 0x00) 
    276.             { 
    277.                 *pOutLen = 0 ; 
    278.                 return 0 ; 
    279.             } 
    280.         } 
    281.         ulPos++ ; 
    282.     } 
    283.     *pOutLen = ulOut ; 
    284.     return 1 ; 
    285.   
    286. void PrintBuffer(const uint8 *buf, uint32 ulLen) 
    287.     uint32 i ; 
    288.     for(i=0; i<ulLen; i++) 
    289.     { 
    290.         printf("%.2X ", buf[i]) ; 
    291.         if((i+1) % 16 == 0) 
    292.             putchar(' ') ; 
    293.     } 
    294.     if((ulLen & 0x0F) != 0) 
    295.         putchar(' ') ; 
    296.   
    297. int main(void) 
    298.     const char *pPK[][2] =  
    299.     { 
    300.         //明文--密钥  
    301.         {"tea", "123456789abcdef"}, 
    302.         {"tea", "123456789abcdef"}, 
    303.         {"123456",  "password1234567"}, 
    304.         {"AABBCCD", "aabbccddeeffggh"}, 
    305.         {"Hello World 你好世界!", "aabbccddeeffggh"} 
    306.     } ; 
    307.     TEACTX ctx ; 
    308.     uint8 bufEnc[512], bufDec[512] ; 
    309.     uint32 ulEnc, ulDec, ulRet ; 
    310.     int i ; 
    311.     for(i=0; i<sizeof(pPK)/sizeof(pPK[0]); i++) 
    312.     { 
    313.         printf("明文:%s 密钥:%s ", pPK[i][0], pPK[i][1]) ; 
    314.         ulEnc = sizeof(bufEnc) ; 
    315.         Encrypt(&ctx, (const uint8 *)pPK[i][0], strlen(pPK[i][0])+1,  
    316.                 (const uint8 *)pPK[i][1], (uint8 *)bufEnc, &ulEnc) ; 
    317.         printf("密文: ") ; 
    318.         PrintBuffer(bufEnc, ulEnc) ; 
    319.         ulDec = sizeof(bufDec) ; 
    320.         ulRet = Decrypt(&ctx, bufEnc, ulEnc, (const uint8 *)pPK[i][1],  
    321.                 (uint8 *)bufDec, &ulDec) ; 
    322.         if(ulRet != 0) 
    323.             printf("解密后明文:%s ", bufDec) ; 
    324.         else 
    325.             printf("解密失败! ") ; 
    326.         putchar(' ') ; 
    327.     } 
    328.     return 0 ; 
  • 相关阅读:
    C#中double转int时需要注意的地方
    OracleHelper类
    POJ2570, ZOJ1967
    ZOJ3088
    POJ3259(spfa判负环)
    POJ3268
    ZOJ1092 POJ2240
    ZOJ1298 POJ1135
    SRM587 div2
    POJ1679判断最小生成树是否唯一
  • 原文地址:https://www.cnblogs.com/zaiiiPan/p/4430039.html
Copyright © 2011-2022 走看看