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加解密算法的更多相关文章

  1. 数据的加密传输——单片机上实现TEA加密解密算法

    各位大侠在做数据传输时,有没有考虑过把数据加密起来进行传输,若在串口或者无线中把所要传的数据加密起来,岂不是增加了通信的安全性.常用的加密解密算法比如DES.RSA等,受限于单片机的内存和运算速度,实 ...

  2. 3des加解密算法

    编号:1003时间:2016年4月1日09:51:11功能:openssl_3des加解密算法http://blog.csdn.net/alonesword/article/details/17385 ...

  3. DES加解密算法Qt实现

      算法解密qt加密table64bit [声明] (1) 本文源码 大部分源码来自:DES算法代码.在此基础上,利用Qt编程进行了改写,实现了DES加解密算法,并添加了文件加解密功能.在此对署名为b ...

  4. AES加解密算法Qt实现

    [声明] (1) 本文源码 在一位未署名网友源码基础上,利用Qt编程,实现了AES加解密算法,并添加了文件加解密功能.在此表示感谢!该源码仅供学习交流,请勿用于商业目的. (2) 图片及描述 除图1外 ...

  5. C#加解密算法

    先附上源码 加密解密算法目前已经应用到我们生活中的各个方面 加密用于达到以下目的: 保密性:帮助保护用户的标识或数据不被读取. 数据完整性:帮助保护数据不被更改. 身份验证:确保数据发自特定的一方. ...

  6. AES加解密算法在Android中的应用及Android4.2以上版本调用问题

     from://http://blog.csdn.net/xinzheng_wang/article/details/9159969 AES加解密算法在Android中的应用及Android4.2以上 ...

  7. [转]RSA,DSA等加解密算法介绍

    From : http://blog.sina.com.cn/s/blog_a9303fd90101cgw4.html 1)      MD5/SHA MessageDigest是一个数据的数字指纹. ...

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

    原文地址:传送门 本文提供了一个能使JavaScript与C#互通的DES加解密算法的实现,在前台页面中用JavaScript版本的DES算法将数据加密之后,传到服务器端,在服务器端可用C#版本的DE ...

  9. RSA 加解密算法

    与DES不同,RSA算法中,每个通信主体都有两个钥匙,一个公钥一个私钥. 就是有2把钥匙1.使用publicKey可以对数据进行加密2.使用Key才能对数据进行解密单方向传输用公钥加密的数据,只有私钥 ...

随机推荐

  1. ImageView的属性android:scaleType

    ImageView的属性android:scaleType,即 ImageView.setScaleType(ImageView.ScaleType). android:scaleType是控制图片如 ...

  2. Atom编辑器入门到精通(五) Git支持

    版本控制对于开发来说非常重要,Atom当然也提供了很好的支持,本文将介绍如何在Atom中集成使用Git和GitHub 恢复文件 当你修改了某个文件,然后发现改得不满意,希望恢复文件到最后一次提交的状态 ...

  3. MVC小系列(十四)【MVC+ZTree大数据异步树加载】

    ZTree是一个jquery的树插件可以异步加载 第一步定义一个标准的接口(指的是与ztree默认的数据元素保持一致) /// <summary> /// ZTree数据结构 /// &l ...

  4. android开发之应用Crash自动抓取Log_自动保存崩溃日志到本地

    http://blog.csdn.net/jason0539/article/details/45602655 应用发生crash之后要查看log,判断问题出在什么地方,可是一旦应用发布出去,就要想办 ...

  5. 500 OOPS: cannot change directory:/home/test

    问题:  以root   从远程客户端 登录 FTP  一直密码错误.  发现不能以root 登录, 需要创建其它的用户. 创建一个test 用户后(如下): useradd test; passwd ...

  6. Mysql笔记【3】-SQL约束

    SQL 约束 约束用于限制加入表的数据的类型. 可以在创建表时规定约束(通过 CREATE TABLE 语句),或者在表创建之后也可以(通过 ALTER TABLE 语句). 我们将主要探讨以下几种约 ...

  7. 大数据基础知识:分布式计算、服务器集群[zz]

    大数据中的数据量非常巨大,达到了PB级别.而且这庞大的数据之中,不仅仅包括结构化数据(如数字.符号等数据),还包括非结构化数据(如文本.图像.声音.视频等数据).这使得大数据的存储,管理和处理很难利用 ...

  8. itoa : Convert integer to string

      Quote from:  http://www.cplusplus.com/reference/cstdlib/itoa/   function   Required header : <s ...

  9. mysql主从 1050错误

    在mysql从库上查询时出现如下错误 ...................... Last_Errno: 1050                    Last_Error: Error 'Tab ...

  10. RM-Linux驱动--Watch Dog Timer(看门狗)驱动分析

    from:http://blog.csdn.net/geekcome/article/details/6595265 硬件平台:FL2440 内核版本:2.6.28 主机平台:Ubuntu 11,04 ...