首页 新闻 会员 周边

3DES PHP 与.NET 兼容问题,解密之后出现部分乱码

0
悬赏园豆:200 [已解决问题] 解决于 2013-10-16 12:08

php 针对 “89407737” ,3DES之后的结果是 “04cd1b1572ff6e02e70205bb633b6d70”。 我c# 解密之后的结果是 “�6�ƋC89407737”  ,前面一部分乱码,后面的正确。 换了几种方式,都是前部分乱码。后面的正确。

 

c#

TripleDESCryptoServiceProvider DES = new TripleDESCryptoServiceProvider();
DES.Key = Encoding.UTF8.GetBytes(txtKey);
DES.IV = Encoding.UTF8.GetBytes(txtIV);
DES.Mode = CipherMode.CFB;
DES.Padding = PaddingMode.None;
ICryptoTransform tf = DES.CreateDecryptor();

string hexString = Value;
byte[] bytes = new byte[hexString.Length / 2];
for (int i = 0; i < bytes.Length; i++)
{
bytes[i] = byte.Parse(hexString.Substring(i * 2, 2),
System.Globalization.NumberStyles.HexNumber);
}

return UTF8Encoding.UTF8.GetString(tf.TransformFinalBlock(bytes, 0, 16));

 

 

php:

<?php defined('SYSPATH') OR die('No direct script access.');
/**
* The Encrypt library provides two-way encryption of text and binary strings
* using the [Mcrypt](http://php.net/mcrypt) extension, which consists of three
* parts: the key, the cipher, and the mode.
*
* The Key
* : A secret passphrase that is used for encoding and decoding
*
* The Cipher
* : A [cipher](http://php.net/mcrypt.ciphers) determines how the encryption
* is mathematically calculated. By default, the "rijndael-128" cipher
* is used. This is commonly known as "AES-128" and is an industry standard.
*
* The Mode
* : The [mode](http://php.net/mcrypt.constants) determines how the encrypted
* data is written in binary form. By default, the "nofb" mode is used,
* which produces short output with high entropy.
*
* @package Kohana
* @category Security
* @author Kohana Team
* @copyright (c) 2007-2012 Kohana Team
* @license http://kohanaframework.org/license
*/
class Encrypt {

/**
* @var string default instance name
*/
public static $default = 'default';

/**
* @var array Encrypt class instances
*/
public static $instances = array();

/**
* @var string OS-dependent RAND type to use
*/
protected static $_rand;

/**
* Returns a singleton instance of Encrypt. An encryption key must be
* provided in your "encrypt" configuration file.
*
* $encrypt = Encrypt::instance();
*
* @param string $name configuration group name
* @return Encrypt
*/
public static function instance($name = NULL)
{
if ($name === NULL)
{
// Use the default instance name
$name = Encrypt::$default;
}

if ( ! isset(Encrypt::$instances[$name]))
{
// Load the configuration data
$config = Kohana::$config->load('encrypt')->$name;

if ( ! isset($config['key']))
{
// No default encryption key is provided!
throw new Kohana_Exception('No encryption key is defined in the encryption configuration group: :group',
array(':group' => $name));
}

if ( ! isset($config['mode']))
{
// Add the default mode
$config['mode'] = MCRYPT_MODE_NOFB;
}

if ( ! isset($config['cipher']))
{
// Add the default cipher
$config['cipher'] = MCRYPT_RIJNDAEL_128;
}

// Create a new instance
Encrypt::$instances[$name] = new Encrypt($config['key'], $config['mode'], $config['cipher']);
}

return Encrypt::$instances[$name];
}

/**
* Creates a new mcrypt wrapper.
*
* @param string $key encryption key
* @param string $mode mcrypt mode
* @param string $cipher mcrypt cipher
*/
public function __construct($key, $mode, $cipher)
{
// Find the max length of the key, based on cipher and mode
$size = mcrypt_get_key_size($cipher, $mode);

if (isset($key[$size]))
{
// Shorten the key to the maximum size
$key = substr($key, 0, $size);
}

// Store the key, mode, and cipher
$this->_key = $key;
$this->_mode = $mode;
$this->_cipher = $cipher;

// Store the IV size
$this->_iv_size = mcrypt_get_iv_size($this->_cipher, $this->_mode);
}

/**
* Encrypts a string and returns an encrypted string that can be decoded.
*
* $data = $encrypt->encode($data);
*
* The encrypted binary data is encoded using [base64](http://php.net/base64_encode)
* to convert it to a string. This string can be stored in a database,
* displayed, and passed using most other means without corruption.
*
* @param string $data data to be encrypted
* @return string
*/
public function encode($data)
{
// Set the rand type if it has not already been set
if (Encrypt::$_rand === NULL)
{
if (Kohana::$is_windows)
{
// Windows only supports the system random number generator
Encrypt::$_rand = MCRYPT_RAND;
}
else
{
if (defined('MCRYPT_DEV_URANDOM'))
{
// Use /dev/urandom
Encrypt::$_rand = MCRYPT_DEV_URANDOM;
}
elseif (defined('MCRYPT_DEV_RANDOM'))
{
// Use /dev/random
Encrypt::$_rand = MCRYPT_DEV_RANDOM;
}
else
{
// Use the system random number generator
Encrypt::$_rand = MCRYPT_RAND;
}
}
}

if (Encrypt::$_rand === MCRYPT_RAND)
{
// The system random number generator must always be seeded each
// time it is used, or it will not produce true random results
mt_srand();
}

// Create a random initialization vector of the proper size for the current cipher
$iv = mcrypt_create_iv($this->_iv_size, Encrypt::$_rand);

// Encrypt the data using the configured options and generated iv
$data = mcrypt_encrypt($this->_cipher, $this->_key, $data, $this->_mode, $iv);

// Use base64 encoding to convert to a string
//return base64_encode($iv.$data);
return str2hex($iv.$data);
}

/**
* Decrypts an encoded string back to its original value.
*
* $data = $encrypt->decode($data);
*
* @param string $data encoded string to be decrypted
* @return FALSE if decryption fails
* @return string
*/
public function decode($data)
{
$data = base64_encode(hex2str($data));
// Convert the data back to binary
$data = base64_decode($data, TRUE);

if ( ! $data)
{
// Invalid base64 data
return FALSE;
}

// Extract the initialization vector from the data
$iv = substr($data, 0, $this->_iv_size);

if ($this->_iv_size !== strlen($iv))
{
// The iv is not the expected size
return FALSE;
}

// Remove the iv from the data
$data = substr($data, $this->_iv_size);

// Return the decrypted data, trimming the \0 padding bytes from the end of the data
return rtrim(mcrypt_decrypt($this->_cipher, $this->_key, $data, $this->_mode, $iv), "\0");
}

}
/**
* 16进制编码转字符串
*
* @param string 16进制编码
*
* @return string 字符串
*/
function hex2str($s)
{
$r = "";
for($i=0; $i<strlen($s); $i+=2)
{
$r .= chr(hexdec('0x'.$s{$i}.$s{$i+1}));
}
return $r;
}

/**
* 字符串转16进制编码
*
* @param string 字符串
*
* @return string 16进制编码
*/
function str2Hex($s)
{
$r = "";
$hexes = array("0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f");
for($i=0; $i<strlen($s); $i++)
{
$r .= ($hexes [(ord($s{$i}) >> 4)] . $hexes [(ord($s{$i}) & 0xf)]);
}
return $r;
}

top15from的主页 top15from | 初学一级 | 园豆:2
提问于:2013-10-15 20:54
< >
分享
最佳答案
0

php 用了 hexString   其中包含了 IV + dataString

C#是不是要用

hexString to original string,  

然后把 IV先取出来  再解密剩下的dataString。

其实你已经解密成功了, 只不过前面包含了IV 一起解密后就显示为乱码

 

还有你用的key是什么,没有key没法debug

---------------------------------

成功了

 

string encrypted = "04cd1b1572ff6e02e70205bb633b6d70";
string txtKey = "mrj2nzn3j4jc2mv4e68ymkrr";

 

string hexString = encrypted;
byte[] bytes = new byte[hexString.Length / 2];
for (int i = 0; i < bytes.Length; i++)
{
bytes[i] = byte.Parse(hexString.Substring(i * 2, 2), System.Globalization.NumberStyles.HexNumber);
}

byte[] iv = bytes.Take(8).ToArray();
byte[] encrytedData = bytes.Skip(8).Take(bytes.Length - 8).ToArray();
TripleDESCryptoServiceProvider DES = new TripleDESCryptoServiceProvider();
DES.Mode = CipherMode.CFB;
DES.Key = Encoding.UTF8.GetBytes(txtKey);
DES.IV = iv;

DES.Padding = PaddingMode.None;
ICryptoTransform tf = DES.CreateDecryptor();
string result = UTF8Encoding.UTF8.GetString(tf.TransformFinalBlock(encrytedData, 0, bytes.Length - 8));

收获园豆:200
gunsmoke | 老鸟四级 |园豆:3592 | 2013-10-16 07:45

我用的KEY : mrj2nzn3j4jc2mv4e68ymkrr

top15from | 园豆:2 (初学一级) | 2013-10-16 09:18

@top15from: 答案已经更新  成功解密

gunsmoke | 园豆:3592 (老鸟四级) | 2013-10-16 10:07
其他回答(1)
0

我也遇到了,你把PaddingMode换成PKCS7Padding试试。

我用PKCS7Padding的时候,乱码会出现在最后,这是由于填充方式不一致导致的,但是最后也没解决掉,由于我解密出的串肯定是json串,所以我自己做了处理把乱码都去掉了。下面是我的代码,你可以参考。

 TripleDesCipher cp = new TripleDesCipher(arrayOfByte2, new CbcCipherMode(Encoding.UTF8.GetBytes("12345678")), new PKCS7Padding());
            byte[] output = cp.Decrypt(arrayOfByte1);

            int llength = output.Length;
            for (int b = (output.Length - 1); b >= 0; b--)
            {
                if (output[b] == (byte)125 || output[b] == (byte)93)
                {
                    llength = b + 1;
                    break;
                }
            }

            return Encoding.UTF8.GetString(output, 0, llength);
小蔡 | 园豆:214 (菜鸟二级) | 2013-10-16 09:58
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册