QmcWasm/TencentTea.hpp

290 lines
7.3 KiB
C++
Raw Normal View History

2023-01-19 15:53:57 +00:00
#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*/
/*
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>:nInBufLenΪ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ܵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>IJ<EFBFBD><EFBFBD><EFBFBD>(Body)<EFBFBD><EFBFBD><EFBFBD><EFBFBD>;
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>:<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊ<EFBFBD><EFBFBD><EFBFBD>ܺ<EFBFBD><EFBFBD>ij<EFBFBD><EFBFBD><EFBFBD>(<EFBFBD><EFBFBD>8byte<EFBFBD>ı<EFBFBD><EFBFBD><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*/
/*
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>:pInBufΪ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ܵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>IJ<EFBFBD><EFBFBD><EFBFBD>(Body),nInBufLenΪpInBuf<EFBFBD><EFBFBD><EFBFBD><EFBFBD>;
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>:pOutBufΪ<EFBFBD><EFBFBD><EFBFBD>ĸ<EFBFBD>ʽ,pOutBufLenΪpOutBuf<EFBFBD>ij<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>8byte<EFBFBD>ı<EFBFBD><EFBFBD><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