- A+
所属分类:杂七杂八
使用TEA的变异算法——不知能否这样称呼。
TEA的输入为32bit无符号整数,密钥为128bit,输出为64bit。
先贴一个我改好的PHP源码,文末附上C源码。
32位的PHP在右移时,很容易把符号位称过来,又成了负数,因此右移5位时,需要0x07FFFFFF来修正。
两行在一起的,注释掉的是另一种写法,同样可用。
下面源码在Windows10下测试正常,CentOS7结果不同。使用被注释掉的另一种写法在Windows10和CentOS7下测试结果相同。
以下是PHP代码:
<?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;
}
以下是C代码:
#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;
}