2013-08-02 92 views
2

下面是我用C#解密編碼字符串的C#代碼。使用Rijndael解密時,C#和PHP中的不同結果

RijndaelManaged RijndaelCipher = new RijndaelManaged(); 
string DecryptedData; 
byte[] EncryptedData = Convert.FromBase64String(TextToBeDecrypted); 
byte[] Salt = Encoding.ASCII.GetBytes(Password.Length.ToString()); 
//Making of the key for decryption 
PasswordDeriveBytes SecretKey = new PasswordDeriveBytes(Password, Salt); 
//Creates a symmetric Rijndael decryptor object. 
ICryptoTransform Decryptor = RijndaelCipher.CreateDecryptor(SecretKey.GetBytes(32), SecretKey.GetBytes(16)); 
byte[] plainText = Decryptor.TransformFinalBlock(EncryptedData, 0, EncryptedData.Length); 

//Converting to string 
DecryptedData = Encoding.Unicode.GetString(plainText); 

但我想在PHP中使用相同的代碼。我嘗試了下面的代碼,但它沒有給我正確的輸出。

function Decrypt($encrypted, $key, $iv){ 
$encrypted=base64_decode($encrypted); 
return mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, $encrypted, MCRYPT_MODE_CFB, $iv); 
} 

這裏我得到輸出$)íqyZiG¤õ¡¹¡我通過$s = 'cJ4ZJD3Vkf3Dv5uxrWiTQg=='$key = '123'(這是相同的,所用,而在C#加密)。

我應該傳遞給$iv以便我得到解密後的輸出爲「Snehal」?

+7

嘗試mcrypt_decrypt代替加密 – Anigel

+2

'$ s'是鹽,但'cJ4ZJD3Vkf3Dv5uxrWiTQg =='不是鹽,其在基礎64格式編碼的鹽。嘗試'base64_decode('cJ4ZJD3Vkf3Dv5uxrWiTQg ==')' – Havenard

回答

2

首先你需要MCRYPT_RIJNDAEL_128而不是256和CBC模式。但是,更大的問題是PasswordDeriveBytes。我認爲這不適用於PHP。但是......通過瀏覽MS源和Mono源代碼的一些工作,可以創建類似的東西。

最簡單的一點是:

<?php 
$encb64 = "cJ4ZJD3Vkf3Dv5uxrWiTQg=="; 
$pwd = "123"; 
$salt = "3"; 

$enc = base64_decode($encb64); 
$decpad = Decrypt($enc, $pwd, $salt); 
// Remove the padding 
$pad = ord($decpad[($len = strlen($decpad)) - 1]); 
$dec = substr($decpad, 0, strlen($decpad) - $pad); 

echo "Enc: " . bin2hex($enc) . "\r\n"; 
echo "Dec: " . $dec . "\r\n"; 

function Decrypt($ciphertext, $password, $salt) 
{ 
    $key = PBKDF1($password, $salt, 100, 32); 
    $iv = PBKDF1($password, $salt, 100, 16); 

    // NB: Need 128 not 256 and CBC mode to be compatible 
    return mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $ciphertext, MCRYPT_MODE_CBC, $iv); 
} 

>

然後使用PBKDF1功能從this post爲出發點,看着兩個單聲道和微軟源,我們可以拿出一個具有如下功能? 。

請注意警告。這是一個非常糟糕的做事方式,原因很多,但足以展示如何實現所要求的內容。

<?php 
function PBKDF1($pass, $salt, $count, $cb) 
{ 
    // This is very approximately the way that the Microsoft version of 
    // PasswordDeriveBytes works. 

    /// 
    /// !!!WARNING!!! 
    /// 
    // This is a BAD function! 
    // Irrespective of the fact that the use of PBKDF1 is not recommended anyway. 
    // 
    // This really should be put into a class with a constructor taking the 
    // $pass, $salt and $count. 
    // Then there should be a Reset() method to start from scratch each time a new pwd/salt is used. 
    // And there should be a GetBytes(int) method to get the required info. 
    // But for the sake of simplicity we are assuming the same pwd and salt for each call to 
    // this function. This will not stand up to any scrutiny! 

    static $base; 
    static $extra; 
    static $extracount= 0; 
    static $hashno; 
    static $state = 0; 

    if ($state == 0) 
    { 
    $hashno = 0; 
    $state = 1; 

    $key = $pass . $salt; 
    $base = sha1($key, true); 
    for($i = 2; $i < $count; $i++) 
    { 
     $base = sha1($base, true); 
    } 
    } 

    $result = ""; 

    // Check if we have any bytes left over from a previous iteration. 
    // This is the way MS appears to do it. To me it looks very badly wrong 
    // in the line: "$result = substr($extra, $rlen, $rlen);" 
    // I'm sure it should be more like "$result = substr($extra, $extracount, $rlen);" 
    // Mono have provided what looks like a fixed version at 
    // https://github.com/mono/mono/blob/master/mcs/class/corlib/System.Security.Cryptography/PasswordDeriveBytes.cs 
    // But I'm no cryptographer so I might be wrong. 
    // But this seems to work for low values of $hashno and seems to work 
    // with C# implementations. 

    if ($extracount > 0) 
    { 
    $rlen = strlen($extra) - $extracount; 
    if ($rlen >= $cb) 
    { 
     $result = substr($extra, $extracount, $cb); 
     if ($rlen > $cb) 
     { 
     $extracount += $cb; 
     } 
     else 
     { 
     $extra = null; 
     $extracount = 0; 
     } 
     return $result; 
    } 
    $result = substr($extra, $rlen, $rlen); 
    } 

    $current = ""; 
    $clen = 0; 
    $remain = $cb - strlen($result); 
    while ($remain > $clen) 
    { 
    if ($hashno == 0) 
    { 
     $current = sha1($base, true); 
    } 
    else if ($hashno < 1000) 
    { 
     $n = sprintf("%d", $hashno); 
     $tmp = $n . $base; 
     $current .= sha1($tmp, true); 
    } 
    $hashno++; 
    $clen = strlen($current);  
    } 

    // $current now holds at least as many bytes as we need 
    $result .= substr($current, 0, $remain); 

    // Save any left over bytes for any future requests 
    if ($clen > $remain) 
    { 
    $extra = $current; 
    $extracount = $remain; 
    } 

    return $result; 
} 
?> 
+0

感謝您的幫助。這是我正在尋找的代碼。謝謝你快速的回覆。 – Ash

0

該問題似乎是您正在使用的C#代碼。

爲了加密/解密使用RindjaelManaged你會做這樣的事情(從MSDN例如拍攝):使用RindjaelManaged的IV屬性在

myRijndael = new RijndaelManaged(); 

myRijndael.GenerateKey(); 
myRijndael.GenerateIV(); 

// Encrypt the string to an array of bytes. 
byte[] encrypted = EncryptStringToBytes(original, myRijndael.Key, myRijndael.IV); 

// Decrypt the bytes to a string. 
string roundtrip = DecryptStringFromBytes(encrypted, myRijndael.Key, myRijndael.IV); 

您需要檢索IV(初始化向量)GenerateIV()創建您展示的一段C#代碼,以便將其用於您的PHP例程。即使您必須使用ICryptoTransform代替上述方法。 AFAIK,只有在給定鹽和關鍵字時,沒有辦法檢索它。