首页 > 编程语言 > 详细

QQ通讯协议里的TEA加解密算法

时间:2015-04-15 21:13:15      阅读:374      评论:0      收藏:0      [点我收藏+]

 

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

 

QQ通讯协议里的TEA加解密算法

原文:http://www.cnblogs.com/zaiiiPan/p/4430039.html

踩
(0)
赞
(0)
   
举报
评论 一句话评论(0)
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!