vb.net中有个3DES的加解密示例,用其加密在php中不知如何解密,看了网上很多代码,主要还是编码的问题,将vb.net的代码转为C#的代码如下:
using System;
using System.Security.Cryptography;
public sealed class My3Des
{
private TripleDESCryptoServiceProvider TripleDes = new TripleDESCryptoServiceProvider();
//---指定密钥的哈希创建指定长度的字节数组
private byte[] TruncateHash(string key, int length)
{
// byte[] functionReturnValue = 0;
SHA1CryptoServiceProvider sha1 = new SHA1CryptoServiceProvider();
// Hash the key.
byte[] keyBytes = System.Text.Encoding.Unicode.GetBytes(key);
byte[] hash = sha1.ComputeHash(keyBytes);
// Truncate or pad the hash.
Array.Resize(ref hash,length);
return hash;
}
//添加用来初始化 3DES 加密服务提供程序的构造函数。
//key 参数控制 EncryptData 和 DecryptData 方法。
public My3Des(string key)
{
// Initialize the crypto provider.
TripleDes.Key = TruncateHash(key, TripleDes.KeySize / 8);
TripleDes.IV = TruncateHash("", TripleDes.BlockSize / 8);
}
//添加加密字符串的公共方法
public string EncryptData(string plaintext)
{
byte[] plaintextBytes = System.Text.Encoding.Unicode.GetBytes(plaintext);
System.IO.MemoryStream ms = new System.IO.MemoryStream();
CryptoStream encStream = new CryptoStream(ms, TripleDes.CreateEncryptor(), System.Security.Cryptography.CryptoStreamMode.Write);
encStream.Write(plaintextBytes, 0, plaintextBytes.Length);
encStream.FlushFinalBlock();
return Convert.ToBase64String(ms.ToArray());
}
//添加解密字符串的公共方法
public string DecryptData(string encryptedtext)
{
byte[] encryptedBytes = Convert.FromBase64String(encryptedtext);
System.IO.MemoryStream ms = new System.IO.MemoryStream();
CryptoStream decStream = new CryptoStream(ms, TripleDes.CreateDecryptor(), System.Security.Cryptography.CryptoStreamMode.Write);
decStream.Write(encryptedBytes, 0, encryptedBytes.Length);
decStream.FlushFinalBlock();
return System.Text.Encoding.Unicode.GetString(ms.ToArray());
}
}
在php中使用opensll来解密时,发现无法解密,如果把C#中的编码改为ASCII或UTF8则可以正常解码,而Unicode却出现问题,增加 编码转化UTF-8到UCS-2还是不行,将UCS-2变为UCS-2LE问题解决。C#unicode默认使用little-Endian字节顺序的UTF-16的格式编码,在windows里PHP对应的unicode的编码是UCS-2LE。
class Encrypt
{
//加密秘钥,
private $_key;
private $_iv;
public function __construct($key)
{
$this->_key = $this->pad(SHA1($this->Ucs2Code($key),true),24);
$this->_iv = substr(SHA1($this->Ucs2Code(""),true),0,8);
}
/**
* 对字符串进行3DES加密
* @param string 要加密的字符串
*/
public function encrypt3DES($str)
{
$data = $this->Ucs2Code($str);
$encrypted_openssl = openssl_encrypt($data, 'des-ede3-cbc', $this->_key, OPENSSL_RAW_DATA, $this->_iv);
return $encrypted_openssl;
}
/**
* 对加密的字符串进行3DES解密
* @param string 要解密的字符串
*/
public function decrypt3DES($str)
{
$data = base64_decode($str,true);
$decrypt_openssl = openssl_decrypt($data,'des-ede3-cbc',$this->_key,OPENSSL_RAW_DATA, $this->_iv);
$decrypt_openssl = mb_convert_encoding("decrypt_openssl","UTF-8","UCS-2LE");
return $decrypt_openssl;
}
private function pad($str,$length)
{
if (strlen($str) < $length) {
$message_padded = str_pad($str,$length, "\0");
}
else {
$message_padded = substr($str,0,$length);
}
return $message_padded;
}
public function Ucs2Code($str,$encode="UTF-8"){
$jumpbit=strtoupper($encode)=='GB2312'?2:3;//跳转位数
$strlen=strlen($str);//字符串长度
$pos=0;//位置
$buffer=array();
for($pos=0;$pos<$strlen;){
if(ord(substr($str,$pos,1))>=0xa1){//0xa1(161)汉字编码开始
$tmpChar=substr($str,$pos,$jumpbit);
$pos+=$jumpbit;
}else{
$tmpChar=substr($str,$pos,1);
++$pos;
}
//$buffer[]=bin2hex(iconv("UTF-8","UCS-2",$tmpChar));
$buffer[]=iconv($encode,"UCS-2LE",$tmpChar);
}
return join("",$buffer);
}
}
如果密码相同想得到不同的加密字符,可在原密码前随机加2个字符,解密的时候将前两位去掉。
PHP:
function GetRndChar($n) {
$charid = strtoupper(md5(uniqid(mt_rand(), true)));
return substr($charid, 0, $n);
}
c#
//--随机生成数字和字母的字符串
private string GetRndChar(int n)
{
return System.Guid.NewGuid().ToString().Substring(0, n);
}