You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

289 lines
7.3 KiB

#ifndef QQMUSIC_CPP_TENCENTTEA_HPP
#define QQMUSIC_CPP_TENCENTTEA_HPP
#include <cstdlib>
#include <cstdio>
#include <cstdint>
#include <vector>
#include <time.h>
#include <arpa/inet.h>
const uint32_t DELTA = 0x9e3779b9;
#define ROUNDS 32
#define SALT_LEN 2
#define ZERO_LEN 7
void TeaDecryptECB(uint8_t* src, uint8_t* dst, std::vector<uint8_t> key, size_t rounds = ROUNDS) {
if (key.size() != 16 || (rounds & 1) != 0)
{
return;
}
uint32_t y, z, sum;
uint32_t k[4];
int i;
//now encrypted buf is TCP/IP-endian;
//TCP/IP network byte order (which is big-endian).
y = ntohl(*((uint32_t*)src));
z = ntohl(*((uint32_t*)(src + 4)));
//std::cout << ntohl(0x0a3aea41);
for (i = 0; i < 4; i++) {
//key is TCP/IP-endian;
k[i] = ntohl(*((uint32_t*)(key.data() + i * 4)));
}
sum = (DELTA * rounds);
for (i = 0; i < rounds; i++) {
z -= ((y << 4) + k[2]) ^ (y + sum) ^ ((y >> 5) + k[3]);
y -= ((z << 4) + k[0]) ^ (z + sum) ^ ((z >> 5) + k[1]);
sum -= DELTA;
}
*((uint32_t*)dst) = ntohl(y);
*((uint32_t*)(dst + 4)) = ntohl(z);
//now plain-text is TCP/IP-endian;
}
void TeaEncryptECB(uint8_t* src, uint8_t* dst, std::vector<uint8_t> key, size_t rounds = ROUNDS) {
if (key.size() != 16 || (rounds & 1) != 0)
{
return;
}
uint32_t y, z, sum;
uint32_t k[4];
int i;
//now encrypted buf is TCP/IP-endian;
//TCP/IP network byte order (which is big-endian).
y = ntohl(*((uint32_t*)src));
z = ntohl(*((uint32_t*)(src + 4)));
//std::cout << ntohl(0x0a3aea41);
for (i = 0; i < 4; i++) {
//key is TCP/IP-endian;
k[i] = ntohl(*((uint32_t*)(key.data() + i * 4)));
}
sum = 0;
for (i = 0; i < rounds; i++) {
sum += DELTA;
y += ((z << 4) + k[0]) ^ (z + sum) ^ ((z >> 5) + k[1]);
z += ((y << 4) + k[2]) ^ (y + sum) ^ ((y >> 5) + k[3]);
}
*((uint32_t*)dst) = ntohl(y);
*((uint32_t*)(dst + 4)) = ntohl(z);
//now plain-text is TCP/IP-endian;
}
/*pKeyΪ16byte*/
/*
����:nInBufLenΪ�����ܵ����IJ���(Body)����;
����:����Ϊ���ܺ��ij���(��8byte�ı���);
*/
/*TEA�����㷨,CBCģʽ*/
/*���ĸ�ʽ:PadLen(1byte)+Padding(var,0-7byte)+Salt(2byte)+Body(var byte)+Zero(7byte)*/
int encryptTencentTeaLen(int nInBufLen)
{
int nPadSaltBodyZeroLen/*PadLen(1byte)+Salt+Body+Zero�ij���*/;
int nPadlen;
/*����Body���ȼ���PadLen,��С���賤�ȱ���Ϊ8byte��������*/
nPadSaltBodyZeroLen = nInBufLen/*Body����*/ + 1 + SALT_LEN + ZERO_LEN/*PadLen(1byte)+Salt(2byte)+Zero(7byte)*/;
if ((nPadlen = nPadSaltBodyZeroLen % 8)) /*len=nSaltBodyZeroLen%8*/
{
/*ģ8��0�貹0,��1��7,��2��6,...,��7��1*/
nPadlen = 8 - nPadlen;
}
return nPadlen;
}
/*pKeyΪ16byte*/
/*
����:pInBufΪ�����ܵ����IJ���(Body),nInBufLenΪpInBuf����;
����:pOutBufΪ���ĸ�ʽ,pOutBufLenΪpOutBuf�ij�����8byte�ı���;
*/
/*TEA�����㷨,CBCģʽ*/
/*���ĸ�ʽ:PadLen(1byte)+Padding(var,0-7byte)+Salt(2byte)+Body(var byte)+Zero(7byte)*/
bool encryptTencentTea(std::vector<uint8_t> inBuf, std::vector<uint8_t> key, std::vector<uint8_t> &outBuf)
{
srand(time(0));
int nPadlen = encryptTencentTeaLen(inBuf.size());
size_t ivCrypt;
std::vector<uint8_t> srcBuf;
srcBuf.resize(8);
std::vector<uint8_t> ivPlain;
ivPlain.resize(8);
int tmpIdx, i, j;
/*���ܵ�һ������(8byte),ȡǰ��10byte*/
srcBuf[0] = (((char)rand()) & 0x0f8)/*�������PadLen,����*/ | (char)nPadlen;
tmpIdx = 1; /*tmpIdxָ��srcBuf��һ��λ��*/
while (nPadlen--) srcBuf[tmpIdx++] = (char)rand(); /*Padding*/
/*come here, tmpIdx must <= 8*/
for (i = 0; i < 8; i++) ivPlain[i] = 0;
ivCrypt = 0;//ivPlain /*make zero iv*/
auto outBufPos = 0; /*init outBufPos*/
#define cryptBlock {\
/*tmpIdx==8*/\
outBuf.resize(outBuf.size() + 8);\
for (j = 0; j < 8; j++) /*����ǰ����ǰ8��byte������(iv_cryptָ����)*/\
srcBuf[j] ^= outBuf[j + ivCrypt];\
/*pOutBuffer��pInBuffer��Ϊ8byte, pKeyΪ16byte*/\
/*����*/\
TeaEncryptECB(srcBuf.data(), outBuf.data()+outBufPos, key, 16);\
for (j = 0; j < 8; j++) /*���ܺ�����ǰ8��byte������(iv_plainָ����)*/\
outBuf[j + outBufPos] ^= ivPlain[j];\
/*���浱ǰ��iv_plain*/\
for (j = 0; j < 8; j++) ivPlain[j] = srcBuf[j];\
/*����iv_crypt*/\
tmpIdx = 0;\
ivCrypt = outBufPos;\
outBufPos += 8;\
}
for (i = 1; i <= SALT_LEN;) /*Salt(2byte)*/
{
if (tmpIdx < 8)
{
srcBuf[tmpIdx++] = (char)rand();
i++; /*i inc in here*/
}
if (tmpIdx == 8)
{
cryptBlock
}
}
/*tmpIdxָ��srcBuf��һ��λ��*/
auto inBufPos = 0;
while (inBufPos < inBuf.size())
{
if (tmpIdx < 8)
{
srcBuf[tmpIdx++] = inBuf[inBufPos];
inBufPos++;
}
if (tmpIdx == 8)
{
cryptBlock
}
}
/*tmpIdxָ��srcBuf��һ��λ��*/
for (i = 1; i <= ZERO_LEN;)
{
if (tmpIdx < 8)
{
srcBuf[tmpIdx++] = 0;
i++; //i inc in here
}
if (tmpIdx == 8)
{
cryptBlock
}
}
return true;
#undef cryptBlock
}
bool decryptTencentTea(std::vector<uint8_t> inBuf, std::vector<uint8_t> key, std::vector<uint8_t> &out) {
if (inBuf.size() % 8 != 0) {
return false;
//inBuf size not a multiple of the block size
}
if (inBuf.size() < 16) {
return false;
//inBuf size too small
}
std::vector<uint8_t> tmpBuf;
tmpBuf.resize(8);
TeaDecryptECB(inBuf.data(), tmpBuf.data(), key, 16);
auto nPadLen = tmpBuf[0] & 0x7; //ֻҪ������λ
/*���ĸ�ʽ:PadLen(1byte)+Padding(var,0-7byte)+Salt(2byte)+Body(var byte)+Zero(7byte)*/
auto outLen = inBuf.size() - 1 /*PadLen*/ - nPadLen - SALT_LEN - ZERO_LEN;
std::vector<uint8_t> outBuf;
outBuf.resize(outLen);
std::vector<uint8_t> ivPrev;
ivPrev.resize(8);
std::vector<uint8_t> ivCur;
ivCur.resize(8);
for (size_t i = 0; i < 8; i++)
{
ivCur[i] = inBuf[i]; // init iv
}
auto inBufPos = 8;
// ���� Padding Len �� Padding
auto tmpIdx = 1 + nPadLen;
// CBC IV ����
#define cryptBlock {\
ivPrev = ivCur;\
for (size_t k = inBufPos; k < inBufPos + 8; k++)\
{\
ivCur[k - inBufPos] = inBuf[k];\
}\
for (size_t j = 0; j < 8; j++) {\
tmpBuf[j] ^= ivCur[j];\
}\
TeaDecryptECB(tmpBuf.data(), tmpBuf.data(), key, 16);\
inBufPos += 8;\
tmpIdx = 0;\
}
// ���� Salt
for (size_t i = 1; i <= SALT_LEN; ) {
if (tmpIdx < 8) {
tmpIdx++;
i++;
}
else {
cryptBlock
}
}
// ��ԭ����
auto outBufPos = 0;
while (outBufPos < outLen) {
if (tmpIdx < 8) {
outBuf[outBufPos] = tmpBuf[tmpIdx] ^ ivPrev[tmpIdx];
outBufPos++;
tmpIdx++;
}
else {
cryptBlock
}
}
// ��Zero
for (size_t i = 1; i <= ZERO_LEN; i++) {
if (tmpBuf[i] != ivPrev[i]) {
return false;
//zero check failed
}
}
out = outBuf;
return true;
#undef cryptBlock
}
#endif //QQMUSIC_CPP_TENCENTTEA_HPP