最近工作中做了一些有关对称加密的算法,遇到的三种办法及思路,记录如下:
1.自己定义对称加密算法
这个算法是工作对接的同事提出的,例如需要传一个手机号,使用下面的方法:
2. 除4取余对称算法
一次同事提供使用Delphi语言写的“除4取余对称算”,要求转换成PHP语言,PHP版本我丢失了,现在把用Delphi语言写的算法贴上:
//==================================================================
//函数名:
//作者:
//日期: 2008-10-4
//功能: 对称解密。算法:除4取余,此算法明文与密文长度相同
// 余数 1位 2位 3位 4位 5位 6位 7位 8位
// 0 0 0 1 1 2 2 2 3
// 1 0 0 -1 -1 2 2 2 1
// 2 0 0 1 1 -2 -2 -2 -1
// 3 0 0 -1 -1 -2 -2 -3 -3
//如为数字+-1
//==================================================================
function pass(pwd:string):string;
var
pw:array[0..3,1..8] of integer; //定义密钥
i,r:integer;
ch:char;
begin
pwd:=UpperCase(pwd);
pw[0,1]:=0;
pw[0,2]:=0;
pw[1,1]:=0;
pw[1,2]:=0;
pw[2,1]:=0;
pw[2,2]:=0;
pw[3,1]:=0;
pw[3,2]:=0;
pw[1,5]:=2;
pw[1,6]:=2;
pw[0,3]:=1;
pw[0,4]:=1;
pw[0,5]:=2;
pw[0,6]:=2;
pw[0,7]:=2;
pw[0,8]:=3;
pw[1,3]:=-1;
pw[1,4]:=-1;
pw[1,5]:=2;
pw[1,6]:=2;
pw[1,7]:=2;
pw[1,8]:=1;
pw[2,3]:=1;
pw[2,4]:=1;
pw[2,5]:=-2;
pw[2,6]:=-2;
pw[2,7]:=-2;
pw[2,8]:=-1;
pw[3,3]:=-1;
pw[3,4]:=-1;
pw[3,5]:=-2;
pw[3,6]:=-2;
pw[3,7]:=-2;
pw[3,8]:=-3;
try
result:='';
strtoint(pwd); //如果全为数字
for i:=1 to length(pwd) do
begin
ch:=pwd[i];
r:=ord(ch) mod 4;
if i>3 then
result:=result+string(chr(ord(ch)+pw[r][3]))
else
result:=result+string(chr(ord(ch)+pw[r][1]));
end;
except
begin
for i:=1 to length(pwd) do
begin
ch:=pwd[i];
r:=ord(ch) mod 4;
if (ch in ['0'..'9']) then
if i<4 then
result:=result+string(chr(ord(ch)+pw[r][1]))
else
result:=result+string(chr(ord(ch)+pw[r][3]))
else
result:=result+string(chr(ord(ch)+pw[r][i]));
end;
end;
end;
end;
3. 工作中有次需要对称加密算法,规定加密后长度不能超过32,查了一下使用RC4对称加密算法可以满足要求,使用方便,这个算法明文与密文算法长度相等,记录如下:
/**
* RC4算法,对称加密,加解密字符串,加解密使用同一套函数
* 使用方法:
* 加密 :cryptRc4('str','nowamagic'); 注意:因为RC4是二进制加密算法,所以密文是无法直接当作文本查看的,你可以用base64对它编码,例如下test()调用及打印
* 解密 :cryptRc4('被加密过的字符串','nowamagic');
* @param string $data 需要加密/解密的字符串
* @param string $pwd 密钥
* @return string $cipher 加密或解密后的字符串
*/
function cryptRc4 ($data, $pwd='')
{
$key[] = ""; // 临时向量
$box[] = ""; // 状态向量
$cipher = '';
// $pwd = str_pad($pwd, 256, chr(0)); // 将密钥扩展到256位
$pwd_length = strlen($pwd);
$data_length = strlen($data);
// 初始化状态向量$box及临时向量$key
for ($i = 0; $i < 256; $i++) {
$key[$i] = ord($pwd[$i % $pwd_length]); // 产生密钥簿
$box[$i] = $i;
}
// 用固定的算法,打乱密匙簿,增加随机性,好像很复杂,实际上对并不会增加密文的强度,即初始排列$box
for ($j = $i = 0; $i < 256; $i++) {
$j = ($j + $box[$i] + $key[$i]) % 256;
$tmp = $box[$i];
$box[$i] = $box[$j];
$box[$j] = $tmp;
}
/*
* 产生密钥流,RC4算法的关键是根据明文和密钥生成相应的密钥流,密钥流的长度和明文的长度是对应的
* */
for ($a = $j = $i = 0; $i < $data_length; $i++) {
$a = ($a + 1) % 256;
$j = ($j + $box[$a]) % 256;
$tmp = $box[$a];
$box[$a] = $box[$j];
$box[$j] = $tmp;
// 从密匙簿得出密匙进行异或,再转成字符
$k = $box[(($box[$a] + $box[$j]) % 256)];
$cipher .= chr(ord($data[$i]) ^ $k);
}
return $cipher;
}
/**
* 加密/解密 及打印密文的使用举例
*/
function test(){
//第一种方法:不能打印密文
$a = cryptRc4('17*******29', '密钥'); //加密,此处加密的密文是ASCII码,不能打印
$b = cryptRc4($a, '密钥'); // 解密
echo $b;
//第二种方法:可以打印查看密文
echo "=======================\r\n";
$msgkey = '密钥';
$enstr = base64_encode(cryptRc4('17*******29', $msgkey)); //加密,用base64对它编码,打印查看密文
echo "rc4-enstr:{$enstr}\r\n";
$destr = cryptRc4(base64_decode($enstr), $msgkey); // 解密
echo "rc4-destr:{$destr}\r\n";
}