2017-05-31 134 views
2

我正在開發一個安全文件傳輸項目,它使用客戶端的c#客戶端加密文件。我需要解密服務器端使用PHP和也許phpseclib文件。這裏的代碼我從一個MSDN例子複製。但我無法解決php中的解密功能。用AES加密C#文件,用phpseclib解密

public static byte[] AES_Encrypt(byte[] bytesToBeEncrypted, byte[] passwordBytes) 
     { 
      byte[] encryptedBytes = null; 
      byte[] saltBytes = passwordBytes; 

      using (MemoryStream ms = new MemoryStream()) 
      { 
       using (RijndaelManaged AES = new RijndaelManaged()) 
       { 
        var key = new Rfc2898DeriveBytes(passwordBytes, saltBytes, 1000); 

        AES.KeySize = 256; 
        AES.BlockSize = 256; 
        AES.Mode = CipherMode.CBC; 
        AES.Padding = PaddingMode.Zeros; 
        AES.Key = key.GetBytes(AES.KeySize/8); 
        AES.IV = key.GetBytes(AES.BlockSize/8);      

        using (CryptoStream cs = new CryptoStream(ms, AES.CreateEncryptor(), CryptoStreamMode.Write)) 
        { 
         cs.Write(bytesToBeEncrypted, 0, bytesToBeEncrypted.Length); 
         cs.Close(); 
        } 
        encryptedBytes = ms.ToArray(); 
       } 
      } 

      return encryptedBytes; 
     } 

這是PHP代碼不工作:

 $pw = "this_is_my_pw"; 
     $aes = new Crypt_AES(CRYPT_AES_MODE_CBC); 
     $aes->setKey($pw); 
     $aes->setKeyLength(256); 
     $aes->disablePadding(); 

     $file = "enc.txt"; 

     $fh = fopen($file, "r"); 
     $contents = trim(fread($fh, filesize($file))); 
     fclose($fh); 

     //echo "Encoded: \n\n" . $contents; 

     $contents = $aes->decrypt($contents); 
     #$block = mcrypt_get_block_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC); 
     #$padding = $block - (strlen($clear) % $block); 

     #$dec = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $pw, base64_decode($contents), MCRYPT_MODE_CBC, $pw); 

     echo "Decoded: \n\n" . $contents; 

有人可以幫助我解決這個或者給我一個提示我做錯了什麼?

回答

0

在Java代碼中,我看到了AES.BlockSize = 256;。從技術上講,AES具有128位的固定塊大小。 Rijndael支持可變塊大小,但AES不支持。如果你想在PHP中使用可變塊大小與phpseclib你需要這樣做:

$pw = "this_is_my_pw"; 
    $aes = new Crypt_Rijndael(CRYPT_RIJNDAEL_MODE_CBC); 
    $aes->setKey($pw); 
    $aes->setKeyLength(256); 
    $aes->setBlockLength(256); 
    $aes->disablePadding(); 

另外,你的重點是13個字節長。 AES密鑰需要16個字節(128位)長,24個字節(192位)長或32個字節(256位)長。 idk你正在使用的是什麼js lib,但是如果它們不夠長,phpseclib 1.0/2.0無效。目前正在開發中的最新版本的phpseclib引發異常。

或者您的意思是使用基於密碼的密鑰派生函數? phpseclib提供了兩個可以通過setPassword()使用的方法,但是如果是這種情況,您需要知道js庫使用的是什麼方法和參數。

+1

使用不是精確支持長度的加密密鑰取決於非標準密鑰填充,這不是一個好主意,並且可能導致互操作性困難。使用文本作爲關鍵還會降低安全性。在這種情況下,密碼代表少於86位的密鑰材料。 – zaph

+0

@ zaph - 抓住關鍵尺寸 - 我沒有看到它。我剛剛注意到有關塊大小的一點,有點大笑起來,大聲笑 – neubert

+0

答案是Rijndael('setBlockLength(256)')不是AES,Rijndael允許128,160,192,224或256的密鑰和塊大小每個比特。 – zaph

1

如果您嘗試使用AES將塊大小設置爲128位,那是唯一支持的塊大小。使用不同的塊大小意味着您正在使用Rijndael加密,這種加密不能很好地支持跨平臺。

AES支持128位,192位和256位多種密鑰大小。有時在使用Rijndael實現來使用AES加密時會出現混淆。

3
  1. 解密時沒有使用初始化向量。您需要發送初始化向量(IV)以及數據 - 您的PHP代碼永遠不會從phpseclib調用$aes->setIV,所以它永遠無法解密文本,因爲如果沒有設置,則phpseclib將使用全零的IV。according to the docs 。我個人推薦使用RijndaelManaged.GenerateIV從C#生成一個安全的隨機IV,但顯然它被認爲可以從PBKDF2密鑰中導出IV。 PBKDF2(在RFC 2898中指定)是密鑰伸縮算法Rfc2898DeriveBytes實現。無論如何,您需要在PHP端重新生成IV,無論這意味着將加密數據(完全正常)傳輸到IV還是在PHP端重新生成IV。

  2. 使用密碼作爲鹽是一個真正糟糕的想法。鹽需要足夠的長度和密碼隨機生成。使用密碼作爲食鹽徹底擊敗了食鹽。 MSDN has some sample code示出如何生成的組合,加密隨機鹽使用Rfc2898DeriveBytes,但重要的部分是在這裏:

byte[] saltBytes = new byte[8]; 
using (RNGCryptoServiceProvider rngCsp = new RNGCryptoServiceProvider()) 
{ 
    // Fill the array with a random value. 
    rngCsp.GetBytes(salt1); 
} 
  • 鹽必須與要發送加密的數據。您需要發送PBKDF2鹽字節以及IV字節和加密數據。 phpseclib將需要所有這些來正確初始化自己並解密數據。您可能需要使用phpseclib的setPassword要做到這一點,像這樣:
  • $salt = ...; // get the salt to your PHP code somehow 
    $iv = ...; // get the IV to your PHP code 
    $pw = "this_is_my_pw"; 
    $aes = new Crypt_AES(CRYPT_AES_MODE_CBC); 
    $aes->setPassword($pw, 'pbkdf2' /* key extension algorithm */, 
        'sha1' /* hash algorithm */, $salt /* generated salt from C# */, 
        1000 /* number of iterations, must be same as C# code */, 
        256/8 /* key size in bytes, 256 bit key/8 bits per byte */ 
    ); 
    $aes->setIV($iv); 
    
  • 記住有關塊大小的答案。 128位是標準的AES塊大小,因此請確保C#和phpseclib可以在更大的塊大小下正常工作,或者只使用AES標準。
  • +0

    在所有偉大的建議。 1.有趣的是,使用不正確的IV將導致第一個塊被解密錯誤地解密,但其餘的消息將被正確解密,這樣的結果有助於指向不正確的IV。將IV加入加密數據的最佳實踐。 2.使用PBKDF2(在RFC 2898中指定)是最佳實踐並提供互操作性。迭代計數也需要提供給解密。 – zaph