QmcWasm/TencentTea.hpp
2023-01-19 23:53:57 +08:00

290 lines
7.3 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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*/
/*
<20><><EFBFBD><EFBFBD>:nInBufLenΪ<6E><CEAA><EFBFBD><EFBFBD><EFBFBD>ܵ<EFBFBD><DCB5><EFBFBD><EFBFBD>IJ<EFBFBD><C4B2><EFBFBD>(Body)<29><><EFBFBD><EFBFBD>;
<20><><EFBFBD><EFBFBD>:<3A><><EFBFBD><EFBFBD>Ϊ<EFBFBD><CEAA><EFBFBD>ܺ<EFBFBD><DCBA>ij<EFBFBD><C4B3><EFBFBD>(<28><>8byte<74>ı<EFBFBD><C4B1><EFBFBD>);
*/
/*TEA<45><41><EFBFBD><EFBFBD><EFBFBD>㷨,CBCģʽ*/
/*<2A><><EFBFBD>ĸ<EFBFBD>ʽ:PadLen(1byte)+Padding(var,0-7byte)+Salt(2byte)+Body(var byte)+Zero(7byte)*/
int encryptTencentTeaLen(int nInBufLen)
{
int nPadSaltBodyZeroLen/*PadLen(1byte)+Salt+Body+Zero<72>ij<EFBFBD><C4B3><EFBFBD>*/;
int nPadlen;
/*<2A><><EFBFBD><EFBFBD>Body<64><79><EFBFBD>ȼ<EFBFBD><C8BC><EFBFBD>PadLen,<2C><>С<EFBFBD><D0A1><EFBFBD><EFBFBD>ȱ<EFBFBD><C8B1><EFBFBD>Ϊ8byte<74><65><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>*/
nPadSaltBodyZeroLen = nInBufLen/*Body<64><79><EFBFBD><EFBFBD>*/ + 1 + SALT_LEN + ZERO_LEN/*PadLen(1byte)+Salt(2byte)+Zero(7byte)*/;
if ((nPadlen = nPadSaltBodyZeroLen % 8)) /*len=nSaltBodyZeroLen%8*/
{
/*ģ8<C4A3><38>0<EFBFBD>貹0,<2C><>1<EFBFBD><31>7,<2C><>2<EFBFBD><32>6,...,<2C><>7<EFBFBD><37>1*/
nPadlen = 8 - nPadlen;
}
return nPadlen;
}
/*pKeyΪ16byte*/
/*
<20><><EFBFBD><EFBFBD>:pInBufΪ<66><CEAA><EFBFBD><EFBFBD><EFBFBD>ܵ<EFBFBD><DCB5><EFBFBD><EFBFBD>IJ<EFBFBD><C4B2><EFBFBD>(Body),nInBufLenΪpInBuf<75><66><EFBFBD><EFBFBD>;
<20><><EFBFBD><EFBFBD>:pOutBufΪ<66><CEAA><EFBFBD>ĸ<EFBFBD>ʽ,pOutBufLenΪpOutBuf<75>ij<EFBFBD><C4B3><EFBFBD><EFBFBD><EFBFBD>8byte<74>ı<EFBFBD><C4B1><EFBFBD>;
*/
/*TEA<45><41><EFBFBD><EFBFBD><EFBFBD>㷨,CBCģʽ*/
/*<2A><><EFBFBD>ĸ<EFBFBD>ʽ: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;
/*<2A><><EFBFBD>ܵ<EFBFBD>һ<EFBFBD><D2BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD>(8byte),ȡǰ<C8A1><C7B0>10byte*/
srcBuf[0] = (((char)rand()) & 0x0f8)/*<2A><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>λ<EFBFBD><CEBB>PadLen,<2C><><EFBFBD><EFBFBD>*/ | (char)nPadlen;
tmpIdx = 1; /*tmpIdxָ<78><D6B8>srcBuf<75><66>һ<EFBFBD><D2BB>λ<EFBFBD><CEBB>*/
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++) /*<2A><><EFBFBD><EFBFBD>ǰ<EFBFBD><C7B0><EFBFBD><EFBFBD>ǰ8<C7B0><38>byte<74><65><EFBFBD><EFBFBD><EFBFBD><EFBFBD>(iv_cryptָ<74><D6B8><EFBFBD><EFBFBD>)*/\
srcBuf[j] ^= outBuf[j + ivCrypt];\
/*pOutBuffer<65><72>pInBuffer<65><72>Ϊ8byte, pKeyΪ16byte*/\
/*<2A><><EFBFBD><EFBFBD>*/\
TeaEncryptECB(srcBuf.data(), outBuf.data()+outBufPos, key, 16);\
for (j = 0; j < 8; j++) /*<2A><><EFBFBD>ܺ<EFBFBD><DCBA><EFBFBD><EFBFBD><EFBFBD>ǰ8<C7B0><38>byte<74><65><EFBFBD><EFBFBD><EFBFBD><EFBFBD>(iv_plainָ<6E><D6B8><EFBFBD><EFBFBD>)*/\
outBuf[j + outBufPos] ^= ivPlain[j];\
/*<2A><><EFBFBD>浱ǰ<E6B5B1><C7B0>iv_plain*/\
for (j = 0; j < 8; j++) ivPlain[j] = srcBuf[j];\
/*<2A><><EFBFBD><EFBFBD>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ָ<78><D6B8>srcBuf<75><66>һ<EFBFBD><D2BB>λ<EFBFBD><CEBB>*/
auto inBufPos = 0;
while (inBufPos < inBuf.size())
{
if (tmpIdx < 8)
{
srcBuf[tmpIdx++] = inBuf[inBufPos];
inBufPos++;
}
if (tmpIdx == 8)
{
cryptBlock
}
}
/*tmpIdxָ<78><D6B8>srcBuf<75><66>һ<EFBFBD><D2BB>λ<EFBFBD><CEBB>*/
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; //ֻҪ<D6BB><D2AA><EFBFBD><EFBFBD><EFBFBD><EFBFBD>λ
/*<2A><><EFBFBD>ĸ<EFBFBD>ʽ: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;
// <20><><EFBFBD><EFBFBD> Padding Len <20><> Padding
auto tmpIdx = 1 + nPadLen;
// CBC IV <20><><EFBFBD><EFBFBD>
#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;\
}
// <20><><EFBFBD><EFBFBD> Salt
for (size_t i = 1; i <= SALT_LEN; ) {
if (tmpIdx < 8) {
tmpIdx++;
i++;
}
else {
cryptBlock
}
}
// <20><>ԭ<EFBFBD><D4AD><EFBFBD><EFBFBD>
auto outBufPos = 0;
while (outBufPos < outLen) {
if (tmpIdx < 8) {
outBuf[outBufPos] = tmpBuf[tmpIdx] ^ ivPrev[tmpIdx];
outBufPos++;
tmpIdx++;
}
else {
cryptBlock
}
}
// У<><D0A3>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