在C#中使用Rijndael进行解密

本文关键字:解密 Rijndael | 更新日期: 2023-09-27 18:21:20

我有以下加密方法。我无法解密它。我继承了加密算法,因此无法更改它。

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个字节,但没有成功。

在C#中使用Rijndael进行解密

您的问题是Encrypt方法中的一个细微错误。通过扰乱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("-", "");

您还需要将Decrypt方法中的填充模式更改为None。虽然这将正确解密,但它也将包括您在加密方法中添加的手动填充字符。由于你不知道你的纯文本,你没有很好的方法来删除它们。您可以随时添加一个方法来删除数组中与零填充值不匹配的所有字节:

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;
}

希望这能帮你指明方向。顺便说一句,我在Snipp上维护了一组可能对您有用的加密实用程序,特别是SymmetricEncrypt和SymmetricDecrypt方法。

------编辑------

正如下面的评论中所指出的,我们不允许更改Encrypt方法。我真的很喜欢挑战!在应用了适当的字节篡改后,这里有一个解密,它尊重来自Encrypt方法的返回:

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;
}

看起来您的加密方法输出一个空格分隔的十六进制字符串,表示一个字节数组:"OA FE 82 3B…"。它还对明文进行了假设,并去掉了任何填充。

您的第一步是将十六进制字符串转换回字节数组,这非常容易。

为了处理丢失的填充,只需将解密设置为NoPadding,正如@Wolfwyrd所建议的那样。如果填充长度不正确,您可能需要检查数据是否正确终止。

如果关于明文字符的假设是错误的,那么很可能您将不得不手动恢复。如果明文是严格的ASCII(仅限7位字符),那么这应该不是问题。除此之外的任何东西,比如重音字母:á、é等,都会打破这种假设。