2013-07-05 45 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位字符),那么这应该不成问题。除此之外的任何内容,例如重音字母:á,é等都将打破假设。