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才能对数据进行解密单方向传输用公钥加密的数据,只有私钥 ...
随机推荐
- SQL查询数据库表字段值不为空或Null的所有列
) set @TableName = 'Agency' -- 表名 declare @querySql nvarchar(max) set @querySql = 'select ' ) declar ...
- jQuery Validate验证框架使用
jQuery Validate使用前的准备,需要下载相应js包括:1.jquery.validate.min.js.2.additional-methods.min.js. 当然必不可少的js jQu ...
- 2013年10月13日学习:SQL通过命令语句来创建表
优点:操作简单,不容易出错,易于调试 缺点:需要记住命令.命令多了就容易混淆,是吧!但是熟悉了时间长了就OK了! step 1. 新建数据库,命名为Test 点击图形化界面中的新建查询,此时就可以输入 ...
- ios Objective-C的动态特性
这是一篇译文,原文在此,上一篇文章就是受这篇文章启发,这次干脆都翻译过来. 过去的几年中涌现了大量的Objective-C开发者.有些是从动态语言转过来的,比如Ruby或Python,有些是从强类型语 ...
- CentOS 7 安装 Apache PHP MariaDB
准备篇: 一.配置防火墙,开启80端口.3306端口 CentOS 7 默认使用的是firewall作为防火墙,这里改为iptables防火墙. 1.关闭firewall: systemctl sto ...
- 01_JavaMail_05_创建邮件工具类MailUtils等方便发送邮件
[工程截图] [代码实现] [Mail.java] package com.Higgin.Utils; import java.util.ArrayList; import java.util.Lis ...
- VMProtect使用小计【一】
文章列表 VMProtect使用小计[一] – 初次使用VMProtect使用小计[二] – 加壳查看VMProtect使用小计[三] – 权限管理 说明 VMProtect的功能我就不说了,详情大家 ...
- 九度OJ 1202 排序 -- 堆排序
题目地址:http://ac.jobdu.com/problem.php?pid=1202 题目描述: 对输入的n个数进行排序并输出. 输入: 输入的第一行包括一个整数n(1<=n<=10 ...
- 在Windows下不使用密码远程登陆Linux
在登陆Linux进行管理的时候我们通常会使用用户名和密码进行登陆,这样一来是比较麻烦,二来是不安全,为了解决这个问题,我们可以使用公私钥 (public keys和private keys)进行认证. ...
- php 魔术方法
PHP5.0后,php面向对象提成更多方法,使得php更加的强大!! 一些在PHP叫魔术方法的函数,在这里介绍一下:其实在一般的应用中,我们都需要用到他们!! 1.__construct() 当实例化 ...