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

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

QQ通讯协议里的TEA加解密算法的相关文章

数据的加密传输——单片机上实现TEA加密解密算法(转)

源:数据的加密传输——单片机上实现TEA加密解密算法 各位大侠在做数据传输时,有没有考虑过把数据加密起来进行传输,若在串口或者无线中把所要传的数据加密起来,岂不是增加了通信的安全性.常用的加密解密算法比如DES.RSA等,受限于单片机的内存和运算速度,实现起来比较困难,但一种叫TEA的加密算法特别适合单片机使用. TEA(Tiny Encryption Algorithm)是一种简单高效的加密算法,以加密解密速度快,实现简单著称.算法很简单,TEA算法每一次可以操作64-bit(8-byte),

AES加解密算法Qt实现

[声明] (1) 本文源码 在一位未署名网友源码基础上,利用Qt编程,实现了AES加解密算法,并添加了文件加解密功能.在此表示感谢!该源码仅供学习交流,请勿用于商业目的. (2) 图片及描述 除图1外,图片及部分解析来自http://zh.wikipedia.org/wiki/%E9%AB%98%E7%BA%A7%E5%8A%A0%E5%AF%86%E6%A0%87%E5%87%86.图1为个人劳动成果,请勿盗用此图. [简介] AES(Advanced Encryption Standard,

[掌眼]iOS / Android / java / node.js 通用的 AES256 加解密算法

example.m NSString *text = @"text"; NSString *key32 = @"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; NSData *data = [text dataUsingEncoding:NSUTF8StringEncoding]; NSString *encryptedData = [[data AES256EncryptWithKey:key32] base64EncodedStringWi

加解密算法

加解密算法概述 工作中经常用到加解密算法大概有以下三种: 单项散列算法 对称散列算法 非对称散列算法 单项散列算法 由不定长的数据转化为固定长的字符串,代表有: sha1 sha1($str[,raw_out=false]);//算法不够复杂 raw_out默认为false,生成一个32位的加密串 如果为true,则生成一个16位的二进制流 md5 md5($str[,strict=false]) strict默认为false,生成一个32位的加密串 如果为true,则生成一个16位的二进制流

DES加解密算法Qt实现

算法解密qt加密table64bit [声明] (1) 本文源码 大部分源码来自:DES算法代码.在此基础上,利用Qt编程进行了改写,实现了DES加解密算法,并添加了文件加解密功能.在此对署名为bengold1979的网友表示感谢!本文是对DES算法代码一文代码的具体描述.该源码仅供学习交流,请勿用于商业目的. (2) 图片及描述 图片及部分解析来自 http://zh.wikipedia.org/wiki/%E8%B3%87%E6%96%99%E5%8A%A0%E5%AF%86%E6%A8%9

【转】各种加解密算法比较

转自: http://blog.csdn.net/pengzp/article/details/6556674 二.          加密算法介绍 对称加密算法 对称加密算法用来对敏感数据等信息进行加密,常用的算法包括: DES(Data Encryption Standard):数据加密标准,速度较快,适用于加密大量数据的场合. 3DES(Triple DES):是基于DES,对一块数据用三个不同的密钥进行三次加密,强度更高. AES(Advanced Encryption Standard

python实现的Caesar加解密算法

Caesar算法是最简单的加解密算法... # Caeser Cipher import sys,os MyCypher = 25 MyDict = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz `[email protected]#$%^&*()_+[]\\;\',./{}|:"<>?' plaintext = 'Hello World!' cryptmsg = '' def encrypt(text, cyph

JavaScript与C#互通的DES加解密算法

原文地址:传送门 本文提供了一个能使JavaScript与C#互通的DES加解密算法的实现,在前台页面中用JavaScript版本的DES算法将数据加密之后,传到服务器端,在服务器端可用C#版本的DES解密算法将其解密,得到原始数据,以起到一定的保密作用.但基于算法本身和密钥保密程度方面的考虑,使用本算法加密后的数据,其保密程度不是很高,故请酌情使用. 声明:本文中的JavaScript版的DES加解密算法来自于互联网,但为了方便于转化成C#版本的代码,本人对其进行了细微调整. JavaScri

【加解密专辑】对接触到的PGP、RSA、AES加解密算法整理

先贴代码,有空再整理思路 PGP加密 using System; using System.IO; using Org.BouncyCastle.Bcpg; using Org.BouncyCastle.Bcpg.OpenPgp; using Org.BouncyCastle.Security; using Org.BouncyCastle.Utilities.IO; using System.Linq; namespace Server5.V2.Common { public static c