分类
技术

DNF 台服数据库密码加密算法

本来只是想打游戏,结果先研究了加解密。

该算法是 TEA 的变异算法。

TEA 的输入为 32 bit 无符号整数,密钥为 128 bit,输出为 64 bit。

先贴一个我改好的 PHP 源码,文末附上 C 源码。

32 位的 PHP 在右移时,很容易把符号位称过来,又成了负数,因此右移 5 位时,需要 0x07FFFFFF 来修正。

两行在一起的,注释掉的是另一种写法,同样可用。

下面源码在 Windows 10 下测试正常,CentOS 7 结果不同。使用被注释掉的另一种写法在 Windows 10 和 CentOS 7 下测试结果相同。

<?php
// 自定义的 8 位数据库密码
$pwd1 = 'uu5!^%jg';

// 加密后的数据库密码
$pwd2 = '4ae98a7fa5e08783e8b10c1f8bc3595be8b10c1f8bc3595b';

// 以下无需改
$key = '74726f716b64646d74726f716b63646d';
$postfix = 'e8b10c1f8bc3595be8b10c1f8bc3595b';

$res1 = encrypt($pwd1, $key);
$res2 = decrypt(substr($pwd2, 0, 16), $key);

echo '加密:';
echo '<br>';
echo '明文:' . $pwd1;
echo '<br>';
echo '密文:' . $res1 . $postfix;

echo '<br>';
echo '<br>';

echo '解密:';
echo '<br>';
echo '密文:' . $pwd2;
echo '<br>';
echo '明文:' . $res2;


function encrypt($v, $k)
{
    // $v0 = bytes_to_long(substr($v, 0, 4));
    $v0 = _str2long(substr($v, 0, 4))[1];

    // $v1 = bytes_to_long(substr($v, 4));
    $v1 = _str2long(substr($v, 4))[1];

    $sum = 0;

    for ($i = 0; $i < 32; ++$i) {
        // $tv1 = toUInt32(toUInt32($v1 << 4)) ^ toUInt32(($v1 >> 5 & 0x07FFFFFF));
        $tv1 = ($v1 << 4) ^ ($v1 >> 5 & 0x07FFFFFF);

        $tv2 = unpack('V', substr(hex2bin($k), ($sum & 3) * 4, 4))[1];

        // $v0 = toUInt32($v0 + (toUInt32($tv1 + $v1) ^ toUInt32($tv2 + $sum)));
        $v0 = (int)($v0 + (($tv1 + $v1) ^ ($tv2 + $sum)));

        // $sum = toUInt32($sum + 0x9E3779B9);
        $sum += 0x9E3779B9;

        // $tv1 = toUInt32(toUInt32(toUInt32($v0 << 4)) ^ toUInt32(($v0 >> 5 & 0x07FFFFFF)));
        $tv1 = ($v0 << 4) ^ ($v0 >> 5 & 0x07FFFFFF);

        // $tv2 = unpack ('V', substr(hex2bin($k), (toUInt32($sum >> 11) & 3) * 4, 4))[1];
        $tv2 = unpack('V', substr(hex2bin($k), (($sum >> 11) & 3) * 4, 4))[1];

        // $v1 = toUInt32($v1 + (toUInt32($tv1 + $v0) ^ toUInt32($tv2 + $sum)));
        $v1 += (int)(($tv1 + $v0) ^ ($tv2 + $sum));
    }

    // return bin2hex(long_to_bytes($v0, 4)) . bin2hex(long_to_bytes($v1, 4));
    return bin2hex(_long2str($v0)) . bin2hex(_long2str($v1));
}

function decrypt($v, $k)
{
    // $v0 = bytes_to_long(hex2bin(substr($v, 0, 8)));
    $v0 = _str2long(hex2bin(substr($v, 0, 8)))[1];

    // $v1 = bytes_to_long(hex2bin(substr($v, 8)));
    $v1 = _str2long(hex2bin(substr($v, 8)))[1];

    $sum = 0xC6EF3720;

    for ($i = 0; $i < 32; ++$i) {
        // $tv1 = toUInt32(toUInt32(toUInt32($v0 << 4)) ^ toUInt32(($v0 >> 5 & 0x07FFFFFF)));
        $tv1 = ($v0 << 4) ^ ($v0 >> 5 & 0x07FFFFFF);

        // $tv2 = unpack ('V', substr(hex2bin($k), (toUInt32($sum >> 11) & 3) * 4, 4))[1];
        $tv2 = unpack('V', substr(hex2bin($k), (($sum >> 11) & 3) * 4, 4))[1];

        // $v1 = toUInt32($v1 - (toUInt32($tv1 + $v0) ^ toUInt32($tv2 + $sum)));
        $v1 -= (int)(($tv1 + $v0) ^ ($tv2 + $sum));

        // $sum = toUInt32($sum - 0x9E3779B9);
        $sum -= 0x9E3779B9;

        // $tv1 = toUInt32(toUInt32($v1 << 4)) ^ toUInt32(($v1 >> 5 & 0x07FFFFFF));
        $tv1 = ($v1 << 4) ^ ($v1 >> 5 & 0x07FFFFFF);

        $tv2 = unpack('V', substr(hex2bin($k), ($sum & 3) * 4, 4))[1];

        // $v0 = toUInt32($v0 - (toUInt32($tv1 + $v1) ^ toUInt32($tv2 + $sum)));
        $v0 = (int)($v0 - (($tv1 + $v1) ^ ($tv2 + $sum)));
    }

    // return long_to_bytes($v0, 4) . long_to_bytes($v1, 4);
    return _long2str($v0) . _long2str($v1);
}

function _str2long($v)
{
    return unpack('N', $v);
}

function _long2str($v)
{
    return pack('N', $v);
}

function bytes_to_long($v)
{
    $a = (0xFFFFFFFF & ord($v{0})) << 24;
    $b = (0xFFFFFFFF & ord($v{1})) << 16;
    $c = (0xFFFFFFFF & ord($v{2})) << 8;
    $d = ord($v{3});
    return $a + $b + $c + $d;
}

function long_to_bytes($v)
{
    $a = (0xFF000000 & $v) >> 24;
    $b = (0xFF0000 & $v) >> 16;
    $c = (0xFF00 & $v) >> 8;
    $d = 0xFF & $v;
    $tmp = pack('CCCC', $a, $b, $c, $d);
    return $tmp;
}

// 将高 32 位清除  只保留低 32 位
function toUInt32($v)
{
    return $v & 0xFFFFFFFF;
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define BLOCKLEN 8

int hex2bin(char* hexstr,unsigned char* outb)
{
    int len = strlen(hexstr);
    int i=0;
    for(;i<len;i+=2)
    {
        unsigned char v = 0;  
        unsigned  char c1 = hexstr[i];
        unsigned  char c2 = hexstr[i+1];

        if( c1>='0' && c1 <='9')
        {
            v = (c1-'0')<<4;
        }else{
            v = ((c1-'a')+10)<<4;
        }
        
        if( c2>='0' && c2 <='9')
        {
            v += (c2-'0');
        }else{
            v += ((c2-'a')+10);
        }
        
        outb[0]=v;
        outb++;
    }
    return len/2;
}
void bin2hex(unsigned char* inb,int len,char* hexstr)
{
    int i=0;
    for(;i<len;i++)
    {
        unsigned  char v = inb[i];
        unsigned  char vh = (v&0xf0)>>4;
        unsigned  char vl = v&0x0f;

        if(vh>9)
        {
            hexstr[i*2] = vh-10+'a';
        }else{
            hexstr[i*2] = vh+'0';
        }
        if(vl>9)
        {
            hexstr[i*2+1] = vl-10+'a';
        }else{
            hexstr[i*2+1] = vl+'0';
        }
    }
    hexstr[i*2]=0;
}

void b2ws(unsigned char* bs,unsigned int* ws)
{
    int v = 0;
    v |= bs[0]<<24;
    v |= bs[1]<<16;
    v |= bs[2]<<8;
    v |= bs[3];
    ws[0] = v;
}
void w2bs(unsigned int ws,unsigned char* bs)
{
    bs[0] = (unsigned char)(ws>>24);
    bs[1] = (unsigned char)(ws>>16);
    bs[2] = (unsigned char)(ws>>8);
    bs[3] = (unsigned char)ws;
}
void iXor(unsigned char * deced, unsigned char  const* keyd)
{   
    int i=0;
    for(i=0;i<BLOCKLEN;i++)
    {
        deced[i] = deced[i]^keyd[i];
    }
}

void DecryptBlock(unsigned char  * ind, unsigned char * oud,unsigned char * kd)
{
    unsigned int delta=0x9e3779b9;
    unsigned int sum=0xC6EF3720, i=0;

    unsigned int v0 = 0;
    unsigned int v1 = 0;
    unsigned int tv1=0,tv2=0;
    
    b2ws(ind,&v0);
    b2ws(ind+4,&v1);
    
    for(i=0;i<32;i++)
    {       
        tv1 = (v0<<4) ^ (v0>>5);    
        tv2 = *(int*)(kd+ ((sum>>11)&3)*4);
                
        v1 = v1 - ( (sum + tv2) ^ ( tv1  + v0) );

        sum -= delta;           
        
        tv1 = (v1<<4) ^ (v1>>5);        
        tv2 = *(int*)(kd+ (sum&3)*4);   

        v0 = v0 - ( (sum + tv2) ^ ( tv1  + v1) );           
    }

    w2bs(v0,oud);   
    w2bs(v1,oud+4);
}
void EncryptBlock(unsigned char  * ind, unsigned char * oud,unsigned char * kd)
{
    unsigned int delta=0x9e3779b9;
    unsigned int sum=0, i=0;

    unsigned int v0 = 0;
    unsigned int v1 = 0;
    unsigned int tv1=0,tv2=0;
    
    b2ws(ind,&v0);
    b2ws(ind+4,&v1);    
    
    for(i=0;i<32;i++)
    {       
        tv1 = (v1<<4) ^ (v1>>5);    
        tv2 = *(int*)(kd+ (sum&3)*4);       

        v0 = v0 + ( (sum + tv2) ^ ( tv1  + v1) );

        sum += delta;           
        
        tv1 = (v0<<4) ^ (v0>>5);        
        tv2 = *(int*)(kd+ ((sum>>11)&3)*4);

        v1 = v1 + ( (sum + tv2) ^ ( tv1  + v0) );           
    }

    w2bs(v0,oud);   
    w2bs(v1,oud+4);
}

void CTEA_Decrypt(char* inputstr, char * outstr, char* keystr)
{
    unsigned char cachedat[64];

    unsigned char inputbytes[24];
    unsigned char outbytes[24];
    unsigned char keybytes[16];

    int iblock=0;
    int inputlen = strlen(inputstr)/2;

    hex2bin(inputstr,inputbytes);
    hex2bin(keystr,keybytes);

    unsigned char* pIn=inputbytes;
    unsigned char* pOu=outbytes;

    memset(cachedat,0x0,64);

    while(iblock*BLOCKLEN<inputlen)
    {
        DecryptBlock(pIn,pOu,keybytes);

        iXor(pOu,cachedat); 
        pOu[BLOCKLEN]=0;

        memcpy(cachedat,inputbytes,BLOCKLEN);

        pIn += BLOCKLEN;
        pOu += BLOCKLEN;
        iblock++;
    }

    strcpy(outstr,(char*)outbytes);
}

void CTEA_Encrypt(char* plain,char* outstr,char* keystr)
{
    unsigned char cachedat[64];
    unsigned char outbytes[24];
    unsigned char keybytes[16];

    hex2bin(keystr,keybytes);

    int iblock=0;
    int inputlen = strlen(plain);

    unsigned char* pIn=(unsigned char*)plain;
    unsigned char* pOu=outbytes;

    memset(cachedat,0x0,64);

    while(iblock*BLOCKLEN<inputlen)
    {
        iXor(cachedat,pIn);

        EncryptBlock(cachedat,pOu,keybytes);

        memcpy(cachedat,pOu,BLOCKLEN);

        pIn += BLOCKLEN;
        pOu += BLOCKLEN;
        iblock++;
    }

    bin2hex(outbytes,inputlen,outstr);
}

void encrypt()
{
    char key[64],origin[1000],res[1000];//密钥,明文,密文 
    printf("输入明文:");
    fflush(stdin);
    gets(origin); 
    printf("输入密钥:");
    fflush(stdin);
    gets(key); 
    CTEA_Encrypt(origin,res,key);
    printf("密文:%s\n",res);
}

void decrypt()
{
    char key[64],origin[1000],res[1000];//密钥,密文,明文 
    printf("输入密文:");
    fflush(stdin);
    gets(origin); 
    printf("输入密钥:");
    fflush(stdin);
    gets(key); 
    CTEA_Decrypt(origin,res,key);
    printf("明文:%s\n",res);
}

void menu()
{
    int select=0;
    while(1)
    {
         
        printf("\n");
        printf("1、加密\n");
        printf("2、解密\n");
        printf("3、退出\n");
        printf("-----------------------------------------\n");
        printf("输入选项:");
        fflush(stdin);
        scanf("%d",&select);
        switch(select)
        {
            case 1:
            {
                encrypt();
                break;
            }
            case 2:
            {
                decrypt();
                break;
            }
            case 3:
            {
                printf("\nBye~~\n");
                return ; 
            }
            default:{
                printf("输入错误!\n");
                break;
            }
        }
        printf("-----------------------------------------\n");
    }
}

int main()
{
    menu();
    return 0;
}

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注