QQ协议的TEA加解密算法
QQ通讯协议里的加解密算法。
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <string.h>
#include <time.h>
//#define CRYPT_ONE_BYTE
typedef char int8 ;
typedef unsigned char uint8 ;
typedef short int16 ;
typedef unsigned short uint16 ;
typedef long int32 ;
typedef unsigned long uint32 ;
typedef struct tagTEACTX
{
uint8 buf[] ;
uint8 bufPre[] ;
const uint8 *pKey ; //指向16字节的key
uint8 *pCrypt ;
uint8 *pCryptPre ;
} TEACTX, *LPTEACTX ;
uint16 Host2NetShort(uint16 usHost)
{
const uint16 us = 0x1234 ;
] == ) | (usHost<<)) ;
}
uint16 Net2HostShort(uint16 usNet)
{
return Host2NetShort(usNet) ;
}
uint32 Host2NetLong(uint32 ulHost)
{
const uint16 us = 0x1234 ;
] == ) & 0xFF00) |
((ulHost<<) & ) | (ulHost>>)) ;
}
uint32 Net2HostLong(uint32 ulHost)
{
return Host2NetLong(ulHost) ;
}
//TEA加密。v明文8字节。k密钥16字节。w密文输出8字节。
void EnCipher(const uint32 *const v, const uint32 *const k, uint32 *const w)
{
register uint32
y = Host2NetLong(v[]),
z = Host2NetLong(v[]),
a = Host2NetLong(k[]),
b = Host2NetLong(k[]),
c = Host2NetLong(k[]),
d = Host2NetLong(k[]),
n = 0x10, /* do encrypt 16 (0x10) times */
sum = ,
delta = 0x9E3779B9; /* 0x9E3779B9 - 0x100000000 = -0x61C88647 */
)
{
sum += delta;
y += ((z << ) + a) ^ (z + sum) ^ ((z >> ) + b);
z += ((y << ) + c) ^ (y + sum) ^ ((y >> ) + d);
}
w[] = Net2HostLong(y);
w[] = Net2HostLong(z);
}
//TEA解密。v密文8字节。k密钥16字节。w明文输出8字节。
void DeCipher(const uint32 *const v, const uint32 *const k, uint32 *const w)
{
register uint32
y = Host2NetLong(v[]),
z = Host2NetLong(v[]),
a = Host2NetLong(k[]),
b = Host2NetLong(k[]),
c = Host2NetLong(k[]),
d = Host2NetLong(k[]),
n = 0x10,
sum = 0xE3779B90,
/* why this ? must be related with n value*/
delta = 0x9E3779B9;
/* sum = delta<<5, in general sum = delta * n */
)
{
z -= ((y << ) + c) ^ (y + sum) ^ ((y >> ) + d);
y -= ((z << ) + a) ^ (z + sum) ^ ((z >> ) + b);
sum -= delta;
}
w[] = Net2HostLong(y);
w[] = Net2HostLong(z);
}
uint32 Random(void)
{
return (uint32)rand();
//return 0xdead ;
}
//每次8字节加密
static void EncryptEach8Bytes(TEACTX *pCtx)
{
#ifdef CRYPT_ONE_BYTE
uint32 i ;
uint8 *pPlain8, *pPlainPre8, *pCrypt8, *pCryptPre8 ;
pPlain8 = (uint8 *)pCtx->buf ;
pPlainPre8 = (uint8 *)pCtx->bufPre ;
pCrypt8 = (uint8 *)pCtx->pCrypt ;
pCryptPre8 = (uint8 *)pCtx->pCryptPre ;
//本轮明文与上一轮的密文异或
; i<; i++)
pPlain8[i] ^= pCryptPre8[i] ;
//再对异或后的明文加密
EnCipher((uint32 *)pPlain8, (uint32 *)pCtx->pKey, (uint32 *)pCrypt8) ;
//将加密后的密文与上一轮的明文(其实是上一轮明文与上上轮密文异或结果)异或
; i<; i++)
pCrypt8[i] ^= pPlainPre8[i] ;
//
; i<; i++)
pPlainPre8[i] = pPlain8[i] ;
#else
uint32 *pPlain8, *pPlainPre8, *pCrypt8, *pCryptPre8 ;
pPlain8 = (uint32 *)pCtx->buf ;
pPlainPre8 = (uint32 *)pCtx->bufPre ;
pCrypt8 = (uint32 *)pCtx->pCrypt ;
pCryptPre8 = (uint32 *)pCtx->pCryptPre ;
pPlain8[] ^= pCryptPre8[] ;
pPlain8[] ^= pCryptPre8[] ;
EnCipher(pPlain8, (const uint32 *)pCtx->pKey, pCrypt8) ;
pCrypt8[] ^= pPlainPre8[] ;
pCrypt8[] ^= pPlainPre8[] ;
pPlainPre8[] = pPlain8[] ;
pPlainPre8[] = pPlain8[] ;
#endif
pCtx->pCryptPre = pCtx->pCrypt ;
pCtx->pCrypt += ;
}
//加密。pPlain指向待加密的明文。ulPlainLen明文长度。pKey密钥16字节。
//pOut指向密文输出缓冲区。pOutLen输入输出参数,指示输出缓冲区长度、密文长度。
uint32 Encrypt(TEACTX *pCtx, const uint8 *pPlain, uint32 ulPlainLen,
const uint8 *pKey, uint8 *pOut, uint32 *pOutLen)
{
uint32 ulPos, ulPadding, ulOut ;
const uint8 *p ;
|| pOutLen == NULL)
;
//计算需要填充的字节数
//整个加密流程下来,不管明文长度多少,填充10个字节是固定的,
//然后再根据明文的长度计算还需要填充的字节数。
ulPos = ( - ((ulPlainLen + ) & 0x07)) & 0x07 ;
//计算加密后的长度
ulOut = + ulPos + + ulPlainLen + ;
if(*pOutLen < ulOut)
{
*pOutLen = ulOut ;
;
}
*pOutLen = ulOut ;
memset(pCtx, , sizeof(TEACTX)) ;
pCtx->pCrypt = pOut ;
pCtx->pCryptPre = pCtx->bufPre ;
pCtx->pKey = pKey ;
//buf[0]的最低3bit位等于所填充的长度
pCtx->buf[] = (uint8)((Random() & 0xF8) | ulPos) ;
//用随机数填充上面计算得到的填充长度(每个字节填充的内容是一样的)。
//这里填充的起始位置是&buf[1]。
memset(pCtx->buf+, (uint8)Random(), ulPos++) ;
//至少再填充两字节
; ulPadding<; ulPadding++)
{
)
{
EncryptEach8Bytes(pCtx) ;
ulPos = ;
}
pCtx->buf[ulPos++] = (uint8)Random() ;
}
p = pPlain ;
)
{
)
{
EncryptEach8Bytes(pCtx) ;
ulPos = ;
}
pCtx->buf[ulPos++] = *(p++) ;
ulPlainLen-- ;
}
//末尾再添加7字节0后加密,在解密过程的时候可以用来判断key是否正确。
; ulPadding<; ulPadding++)
pCtx->buf[ulPos++] = 0x00 ;
//
EncryptEach8Bytes(pCtx) ;
return ulOut ;
}
//每次8字节进行解密
static void DecryptEach8Bytes(TEACTX *pCtx)
{
#ifdef CRYPT_ONE_BYTE
uint32 i ;
uint8 bufTemp[] ;
uint8 *pBuf8, *pBufPre8, *pCrypt8, *pCryptPre8 ;
pBuf8 = (uint8 *)pCtx->buf ;
pBufPre8 = (uint8 *)pCtx->bufPre ;
pCrypt8 = (uint8 *)pCtx->pCrypt ;
pCryptPre8 = (uint8 *)pCtx->pCryptPre ;
//当前的密文与前一轮明文(实际是前一轮明文与前前轮密文异或结果)异或
; i<; i++)
bufTemp[i] = pCrypt8[i] ^ pBufPre8[i] ;
//异或后的结果再解密(解密后得到当前名文与前一轮密文异或的结果,并非真正明文)
DeCipher((uint32 *)bufTemp, (uint32 *)pCtx->pKey, (uint32 *)pBufPre8) ;
//解密后的结果与前一轮的密文异或,得到真正的明文
; i<; i++)
pBuf8[i] = pBufPre8[i] ^ pCryptPre8[i] ;
#else
uint32 bufTemp[] ;
uint32 *pBuf8, *pBufPre8, *pCrypt8, *pCryptPre8 ;
pBuf8 = (uint32 *)pCtx->buf ;
pBufPre8 = (uint32 *)pCtx->bufPre ;
pCrypt8 = (uint32 *)pCtx->pCrypt ;
pCryptPre8 = (uint32 *)pCtx->pCryptPre ;
bufTemp[] = pCrypt8[] ^ pBufPre8[] ;
bufTemp[] = pCrypt8[] ^ pBufPre8[] ;
DeCipher(bufTemp, (const uint32 *)pCtx->pKey, pBufPre8) ;
pBuf8[] = pBufPre8[] ^ pCryptPre8[] ;
pBuf8[] = pBufPre8[] ^ pCryptPre8[] ;
#endif
pCtx->pCryptPre = pCtx->pCrypt ;
pCtx->pCrypt += ;
}
//解密。pCipher指向待解密密文。ulCipherLen密文长度。pKey密钥16字节。
//pOut指向明文输出缓冲区。pOutLen输入输出参数,指示输出缓冲区长度、明文长度。
uint32 Decrypt(TEACTX *pCtx, const uint8 *pCipher, uint32 ulCipherLen,
const uint8 *pKey, uint8 *pOut, uint32 *pOutLen)
{
uint32 ulPos, ulPadding, ulOut, ul ;
// 待解密的数据长度最少16字节,并且长度满足是8的整数倍。
if(pCipher == NULL || pOutLen == NULL ||
ulCipherLen < || (ulCipherLen & )
;
// 先解密头8字节,以便获取第一轮加密时填充的长度。
DeCipher((const uint32 *)pCipher, (const uint32 *)pKey, (uint32 *)pCtx->bufPre) ;
; ul<; ul++)
pCtx->buf[ul] = pCtx->bufPre[ul] ;
ulPos = pCtx->buf[] & 0x07 ; //第一轮加密时填充的长度
)
{
; ulOut<=ulPos; ulOut++)
{
] != pCtx->buf[ulOut])
{
*pOutLen = ;
; //解密失败
}
}
}
ulOut = ulCipherLen - ulPos - ;
> ulCipherLen || *pOutLen < ulOut)
;
pCtx->pCryptPre = (uint8 *)pCipher ;
pCtx->pCrypt = (uint8 *)pCipher + ;
ulPos++ ;
; ulPadding<; ulPadding++)
{
)
{
DecryptEach8Bytes(pCtx) ;
ulPos = ;
}
ulPos++ ;
}
//
; ul<ulOut; ul++)
{
)
{
DecryptEach8Bytes(pCtx) ;
ulPos = ;
}
pOut[ul] = pCtx->buf[ulPos] ;
ulPos++ ;
}
//
; ulPadding<; ulPadding++)
{
)
{
if(pCtx->buf[ulPos] != 0x00)
{
*pOutLen = ;
;
}
}
ulPos++ ;
}
*pOutLen = ulOut ;
;
}
void PrintBuffer(const uint8 *buf, uint32 ulLen)
{
uint32 i ;
; i<ulLen; i++)
{
printf("%.2X ", buf[i]) ;
) % == )
putchar('\n') ;
}
)
putchar('\n') ;
}
int main(void)
{
] =
{
//明文--密钥
{"tea", "123456789abcdef"},
{"tea", "123456789abcdef"},
{", "password1234567"},
{"AABBCCD", "aabbccddeeffggh"},
{"Hello World 你好世界!", "aabbccddeeffggh"}
} ;
TEACTX ctx ;
uint8 bufEnc[], bufDec[] ;
uint32 ulEnc, ulDec, ulRet ;
int i ;
; i<]); i++)
{
printf(], pPK[i][]) ;
ulEnc = sizeof(bufEnc) ;
Encrypt(&ctx, (], strlen(pPK[i][])+,
(], (uint8 *)bufEnc, &ulEnc) ;
printf("密文:\n") ;
PrintBuffer(bufEnc, ulEnc) ;
ulDec = sizeof(bufDec) ;
ulRet = Decrypt(&ctx, bufEnc, ulEnc, (],
(uint8 *)bufDec, &ulDec) ;
)
printf("解密后明文:%s\n", bufDec) ;
else
printf("解密失败!\n") ;
putchar('\n') ;
}
;
}

QQ协议的TEA加解密算法的更多相关文章
- 数据的加密传输——单片机上实现TEA加密解密算法
各位大侠在做数据传输时,有没有考虑过把数据加密起来进行传输,若在串口或者无线中把所要传的数据加密起来,岂不是增加了通信的安全性.常用的加密解密算法比如DES.RSA等,受限于单片机的内存和运算速度,实 ...
- 3des加解密算法
编号:1003时间:2016年4月1日09:51:11功能:openssl_3des加解密算法http://blog.csdn.net/alonesword/article/details/17385 ...
- DES加解密算法Qt实现
算法解密qt加密table64bit [声明] (1) 本文源码 大部分源码来自:DES算法代码.在此基础上,利用Qt编程进行了改写,实现了DES加解密算法,并添加了文件加解密功能.在此对署名为b ...
- AES加解密算法Qt实现
[声明] (1) 本文源码 在一位未署名网友源码基础上,利用Qt编程,实现了AES加解密算法,并添加了文件加解密功能.在此表示感谢!该源码仅供学习交流,请勿用于商业目的. (2) 图片及描述 除图1外 ...
- C#加解密算法
先附上源码 加密解密算法目前已经应用到我们生活中的各个方面 加密用于达到以下目的: 保密性:帮助保护用户的标识或数据不被读取. 数据完整性:帮助保护数据不被更改. 身份验证:确保数据发自特定的一方. ...
- AES加解密算法在Android中的应用及Android4.2以上版本调用问题
from://http://blog.csdn.net/xinzheng_wang/article/details/9159969 AES加解密算法在Android中的应用及Android4.2以上 ...
- [转]RSA,DSA等加解密算法介绍
From : http://blog.sina.com.cn/s/blog_a9303fd90101cgw4.html 1) MD5/SHA MessageDigest是一个数据的数字指纹. ...
- JavaScript与C#互通的DES加解密算法
原文地址:传送门 本文提供了一个能使JavaScript与C#互通的DES加解密算法的实现,在前台页面中用JavaScript版本的DES算法将数据加密之后,传到服务器端,在服务器端可用C#版本的DE ...
- RSA 加解密算法
与DES不同,RSA算法中,每个通信主体都有两个钥匙,一个公钥一个私钥. 就是有2把钥匙1.使用publicKey可以对数据进行加密2.使用Key才能对数据进行解密单方向传输用公钥加密的数据,只有私钥 ...
随机推荐
- magento 产品列表排序、分页功能
我们以 catalog_category_layered 控制器为例说明 在catalog.xml 找到catalog_category_layered配置段 <catalog_category ...
- OC - 5.内存管理
一.引用计数器 1> 栈和堆 栈 ① 主要存储局部变量 ② 内存自动回收 堆 ① 主要存储需要动态分配内存的变量 ② 需要手动回收内存,是OC内存管理的对象 2> 简介 作用 ① 表示对象 ...
- 深入理解Javascript之this关键字
深入理解Javascript之this关键字 作者: Laruence( ) 本文地址: http://www.laruence.com/2009/09/08/1076.html 转载请注明出处 ...
- JSP EL表达式详细介绍
一.JSP EL语言定义 E L(Expression Language) 目的:为了使JSP写起来更加简单. 表达式语言的灵感来自于 ECMAScript 和 XPath 表达式语言,它提供了在 ...
- 使用CLK.AspNet.Identity提供以角色为基础的访问控制(RBAC)
使用CLK.AspNet.Identity提供以角色为基础的访问控制(RBAC) 程序代码下载 程序代码下载:点此下载 前言 ASP.NET Identity是微软所贡献的开源项目,用来提供ASP.N ...
- jQuery的基础语法实例
jQuery 基础语法 jQuery 语法是为 HTML 元素的选取编制的,可以对元素执行某些操作. 基础语法是:$(selector).action() 美元符号定义 jQuery 选择符(sele ...
- spring mvc 错误
No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin //跨域问题 respons ...
- libsdl中文输入法候选列表不显示解决方案
libsdl输入中文时输入法不显示,将WM_IME_SETCONTEXT事件处理给注释即可. WM_IME_SETCONTEXT If the application draws the compos ...
- 九度OJ 1131 合唱队形 -- 动态规划(最长递增子序列)
题目地址:http://ac.jobdu.com/problem.php?pid=1131 题目描述: N位同学站成一排,音乐老师要请其中的(N-K)位同学出列,使得剩下的K位同学不交换位置就能排成合 ...
- MySQL的多实例
一.准备工作 1.关闭mysql进程 # pkill # service mysqld stop 2.从系统服务中删除mysqld # chkconfi ...