2013-07-05 42 views
2

我有以下加密方法。我無法解密它。我繼承了加密算法,因此無法更改。在C中使用Rijndael解密#

public static string Encrypt(string plaintext) 
    { 
     byte[] rgbIV; 
     byte[] key; 

     RijndaelManaged rijndael = BuildRigndaelCommon(out rgbIV, out key); 

     //convert plaintext into a byte array 
     byte[] plaintextBytes = Encoding.UTF8.GetBytes(plaintext); 

     int BlockSize; 
     BlockSize = 16 * (1 + (plaintext.Length/16)); 
     Array.Resize(ref plaintextBytes, BlockSize); 

     // fill the remaining space with 0 
     for (int i = plaintext.Length; i < BlockSize; i++) 
     { 
      plaintextBytes[i] = 0; 
     } 

     byte[] cipherTextBytes = null; 
     //create uninitialized Rijndael encryption obj 
     using (RijndaelManaged symmetricKey = new RijndaelManaged()) 
     { 
      //Call SymmetricAlgorithm.CreateEncryptor to create the Encryptor obj 
      var transform = rijndael.CreateEncryptor(); 

      //Chaining mode 
      symmetricKey.Mode = CipherMode.CFB; 

      //create encryptor from the key and the IV value 
      ICryptoTransform encryptor = symmetricKey.CreateEncryptor(key, rgbIV); 

      //define memory stream to hold encrypted data 
      using (MemoryStream ms = new MemoryStream()) 
      { 
       //define cryptographic stream - contains the transformation key to be used and the mode 
       using (CryptoStream cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write)) 
       { 
        //encrypt contents of cryptostream 
        cs.Write(plaintextBytes, 0, BlockSize); 
        cs.FlushFinalBlock(); 

        //convert encrypted data from a memory stream into a byte array 
        cipherTextBytes = ms.ToArray(); 
       } 
      } 
     } 

     //store result as a hex value 
     string hexOutput = BitConverter.ToString(cipherTextBytes).Replace("-", ""); 
     hexOutput = hexOutput.Substring(0, plaintext.Length * 2); 

     //finially return encrypted string 
     return hexOutput; 
    } 

正如你所看到的,除了最後它被轉換爲十六進制和子字符串之外,它是非常標準的。做相反的事情我很困難。

我的解密方法是這樣的:

 public static string Decrypt(string disguisedtext) 
    { 
     byte[] rgbIV; 
     byte[] key; 

     BuildRigndaelCommon(out rgbIV, out key); 

     byte[] disguishedtextBytes = FromHexString(disguisedtext); 

     string visiabletext = ""; 
     //create uninitialized Rijndael encryption obj 
     using (var symmetricKey = new RijndaelManaged()) 
     { 
      //Call SymmetricAlgorithm.CreateEncryptor to create the Encryptor obj 
      symmetricKey.Mode = CipherMode.CFB; 
      //create encryptor from the key and the IV value 

      // ICryptoTransform encryptor = symmetricKey.CreateEncryptor(key, rgbIV); 
      ICryptoTransform decryptor = symmetricKey.CreateDecryptor(key, rgbIV); 

      //define memory stream to hold encrypted data 
      using (MemoryStream ms = new MemoryStream(disguishedtextBytes)) 
      { 
       //define cryptographic stream - contains the transformation to be used and the mode 
       using (CryptoStream cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Write)) 
       { 

        byte[] plaintextBytes = new Byte[disguishedtextBytes.Length]; 
        cs.Write(disguishedtextBytes, 0, disguishedtextBytes.Length); 
        cs.FlushFinalBlock(); 

        //convert decrypted data from a memory stream into a byte array 
        byte[] visiabletextBytes = ms.ToArray(); 

        visiabletext = Encoding.UTF8.GetString(visiabletextBytes); 
       } 
      } 
     } 
     return visiabletext; 
    } 

輔助方法:

private static RijndaelManaged BuildRigndaelCommon(out byte[] rgbIV, out byte[] key) 
    { 
     rgbIV = new byte[] { 0x0, 0x1, 0x2, 0x3, 0x5, 0x6, 0x7, 0x8, 0xA, 0xB, 0xC, 0xD, 0xF, 0x10, 0x11, 0x12 }; 

     key = new byte[] { 0x0, 0x1, 0x2, 0x3, 0x5, 0x6, 0x7, 0x8, 0xA, 0xB, 0xC, 0xD, 0xF, 0x10, 0x11, 0x12 }; 

     //Specify the algorithms key & IV 
     RijndaelManaged rijndael = new RijndaelManaged{BlockSize = 128, IV = rgbIV, KeySize = 128, Key = key, Padding = PaddingMode.None};   

     return rijndael; 
    } 

    public static byte[] FromHexString(string hexString) 
    { 
     if (hexString == null) 
     { 
      return new byte[0]; 
     } 

     var numberChars = hexString.Length; 
     var bytes = new byte[numberChars/2]; 

     for (var i = 0; i < numberChars; i += 2) 
     { 
      bytes[i/2] = Convert.ToByte(hexString.Substring(i, 2), 16); 
     } 

     return bytes; 
    } 

我收到有關該字符串的長度各種錯誤和填充是無效的。有沒有人有任何想法來解密工作。我試着將輸入字符串填充回32字節,但無濟於事。

+2

它被破壞無法修復。您無法更改CryptoStream的輸出(使用hexOutput變量上的Replace),並期望能夠解密結果。 –

+0

這是我最初的想法。但是,加密算法是從Delphi實現中複製的。在Delphi中,可以解密這個值,這讓我認爲它應該以.net的方式在某種程度上也是可能的。 – keitn

+0

它可能適用於某些數據,但可能只適用於BitConvert結果的結果不包含任何連字符... –

回答

4

您的問題是您的加密方法中的一個微妙的錯誤。通過混淆hexOutput字符串,您正在丟失返回的密文中的數據。相反的:

//store result as a hex value 
string hexOutput = BitConverter.ToString(cipherTextBytes).Replace("-", ""); 
hexOutput = hexOutput.Substring(0, plaintext.Length * 2); 

//finially return encrypted string 
return hexOutput; 

你應該只返回輸出:

return BitConverter.ToString(cipherTextBytes).Replace("-", ""); 

您還需要改變填充模式在你的解密方法爲無。雖然現在可以正確解密,但它也會包含您在加密方法中添加的手動填充字符。由於你不知道你的純文本,你沒有好辦法去除它們。你總是可以添加一個方法來刪除您的數組中的所有不匹配字節的零您填充值:

int endMarker = decryptedData.Length; 
do { endMarker--; } while (decryptedData[endMarker] == 0);    
Array.Resize(ref decryptedData, endMarker + 1); 

然而,這是不是一個真正的好主意,因爲你可能丟棄,否則有效的數據。更好的解決方案是更新你的加密和解密方法,讓密碼處理填充。把它放在一起我們得到(只顯示我已經改變):

private static RijndaelManaged BuildRigndaelCommon(out byte[] rgbIV, out byte[] key) 
{ 
    rgbIV = new byte[] { 0x0, 0x1, 0x2, 0x3, 0x5, 0x6, 0x7, 0x8, 0xA, 0xB, 0xC, 0xD, 0xF, 0x10, 0x11, 0x12 }; 
    key = new byte[] { 0x0, 0x1, 0x2, 0x3, 0x5, 0x6, 0x7, 0x8, 0xA, 0xB, 0xC, 0xD, 0xF, 0x10, 0x11, 0x12 }; 

    //Specify the algorithms key & IV 
    RijndaelManaged rijndael = new RijndaelManaged{BlockSize = 128, IV = rgbIV, KeySize = 128, Key = key, Padding = PaddingMode.PKCS7 };  
    return rijndael; 
} 

public static string Encrypt(string plaintext) 
{ 
    byte[] rgbIV; 
    byte[] key; 

    RijndaelManaged rijndael = BuildRigndaelCommon(out rgbIV, out key); 

    //convert plaintext into a byte array 
    byte[] plaintextBytes = Encoding.UTF8.GetBytes(plaintext); 

    byte[] cipherTextBytes = null; 

    //create uninitialized Rijndael encryption obj 
    using (RijndaelManaged symmetricKey = new RijndaelManaged()) 
    { 
     //Call SymmetricAlgorithm.CreateEncryptor to create the Encryptor obj 
     var transform = rijndael.CreateEncryptor(); 

     //Chaining mode 
     symmetricKey.Mode = CipherMode.CFB;  
     //create encryptor from the key and the IV value 
     ICryptoTransform encryptor = symmetricKey.CreateEncryptor(key, rgbIV); 

     //define memory stream to hold encrypted data 
     using (MemoryStream ms = new MemoryStream()) 
     using (CryptoStream cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write)) 
     { 
      //encrypt contents of cryptostream 
      cs.Write(plaintextBytes, 0, plaintextBytes.Length); 
      cs.Flush(); 
      cs.FlushFinalBlock(); 

      //convert encrypted data from a memory stream into a byte array 
      ms.Position = 0; 
      cipherTextBytes = ms.ToArray(); 

      ms.Close(); 
      cs.Close(); 
     } 
    } 

    //store result as a hex value 
    return BitConverter.ToString(cipherTextBytes).Replace("-", ""); 
} 

public static string Decrypt(string disguisedtext) 
{ 
    byte[] disguishedtextBytes = FromHexString(disguisedtext); 

    byte[] rgbIV; 
    byte[] key; 

    BuildRigndaelCommon(out rgbIV, out key); 



    string visiabletext = ""; 
    //create uninitialized Rijndael encryption obj 
    using (var symmetricKey = new RijndaelManaged()) 
    { 
     //Call SymmetricAlgorithm.CreateEncryptor to create the Encryptor obj 
     symmetricKey.Mode = CipherMode.CFB; 
     symmetricKey.BlockSize = 128; 

     //create encryptor from the key and the IV value 

     // ICryptoTransform encryptor = symmetricKey.CreateEncryptor(key, rgbIV); 
     ICryptoTransform decryptor = symmetricKey.CreateDecryptor(key, rgbIV); 

     //define memory stream to hold encrypted data 
     using (MemoryStream ms = new MemoryStream(disguishedtextBytes)) 
     { 
      //define cryptographic stream - contains the transformation to be used and the mode 
      using (CryptoStream cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Read)) 
      { 
       byte[] decryptedData = new byte[disguishedtextBytes.Length]; 
       int stringSize = cs.Read(decryptedData, 0, disguishedtextBytes.Length); 
       cs.Close(); 

        //Trim the excess empty elements from the array and convert back to a string 
       byte[] trimmedData = new byte[stringSize]; 
       Array.Copy(decryptedData, trimmedData, stringSize);    
       visiabletext = Encoding.UTF8.GetString(trimmedData); 
      } 
     } 
    } 
    return visiabletext; 
} 

希望這有助於指點你的方式。另外,我在Snipt上維護a set of encryption utilities,這對您可能有用,特別是SymmetricEncrypt和SymmetricDecrypt方法。

------編輯------

如在下面的評論指出的那樣,我們是不允許更改的加密方法。我喜歡挑戰!隨着應用適當的字節忙玲,這裏是一個榮譽的回報未來形式的加密方法解密:

public static string Decrypt(string disguisedtext) 
{ 
    byte[] disguishedtextBytes = FromHexString(disguisedtext); 

    var originalLength = disguishedtextBytes.Length; 

    int BlockSize; 
    BlockSize = 16 * (1 + (originalLength/16)); 
    Array.Resize(ref disguishedtextBytes, BlockSize); 

    // fill the remaining space with 0 
    for (int i = originalLength; i < BlockSize; i++) 
    { 
     disguishedtextBytes[i] = 0; 
    } 


    byte[] rgbIV; 
    byte[] key; 

    BuildRigndaelCommon(out rgbIV, out key);  

    string visiabletext = ""; 
    //create uninitialized Rijndael encryption obj 
    using (var symmetricKey = new RijndaelManaged()) 
    { 
      //Call SymmetricAlgorithm.CreateEncryptor to create the Encryptor obj 
     symmetricKey.Mode = CipherMode.CFB; 
     symmetricKey.BlockSize = 128; 
     symmetricKey.Padding = PaddingMode.None;   

      // ICryptoTransform encryptor = symmetricKey.CreateEncryptor(key, rgbIV); 
     ICryptoTransform decryptor = symmetricKey.CreateDecryptor(key, rgbIV); 

      //define memory stream to hold encrypted data 
     using (MemoryStream ms = new MemoryStream(disguishedtextBytes)) 
     using (CryptoStream cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Read)) 
     { 
      byte[] decryptedData = new byte[disguishedtextBytes.Length]; 
      int stringSize = cs.Read(decryptedData, 0, disguishedtextBytes.Length); 
      cs.Close(); 

       //Trim the excess empty elements from the array and convert back to a string 
      byte[] trimmedData = new byte[stringSize]; 
      Array.Copy(decryptedData, trimmedData, originalLength); 
      Array.Resize(ref trimmedData, originalLength); 

      visiabletext = Encoding.UTF8.GetString(trimmedData);   
     } 
    } 
    return visiabletext; 
} 
+1

感謝您花時間回覆。不幸的是,我無法更改加密方法。它實際上在我無法控制的另一個系統中使用。基於該加密算法已經存儲在數據庫中的值。我所能改變的只是Decrypt方法。這是我的問題的根源。 – keitn

+1

@keitn - 更新以履行加密。快樂的字節整頓:) – Wolfwyrd

+1

謝謝沃爾夫威爾。後來我在做一些非常愚蠢的事情,我打電話給我的幫助器方法BuildRigndaelCommon,但沒有將輸出RijndaelManaged分配給一個變量。然後再往下,我有「使用(var symmetricKey = new RijndaelManaged())」。我改變了輔助方法中的填充設置,但顯然沒有任何影響。再次感謝。 – keitn

0

它看起來像你的加密方法輸出一個空格分隔十六進制字符串,代表一個字節數組:「OA FE 82 3B。 ..「。它也會對明文進行假設並刪除任何填充。

第一步是將十六進制字符串轉換回字節數組,這很容易。

要處理丟失的填充只需將解密設置爲NoPadding,正如@Wolfwyrd所示。如果填充長度已關閉,則可能必須檢查您的數據是否正確終止。

如果對明文字符的假設是錯誤的,那麼很可能您必須手動恢復。如果明文是嚴格的ASCII(僅7位字符),那麼這應該不成問題。除此之外的任何內容,例如重音字母:á,é等都將打破假設。