2

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

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 个字节,但无济于事。

4

2 回答 2

4

您的问题是您的 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;
}

希望这有助于为您指明方向。顺便说一句,我在 Snipt 上维护了一组可能对您有用的加密实用程序,尤其是 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;
}
于 2013-07-05T10:53:08.557 回答
0

看起来您的加密方法输出了一个空格分隔的十六进制字符串,代表一个字节数组:“OA FE 82 3B ...”。它还对明文做出假设并删除任何填充。

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

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

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

于 2013-07-05T11:50:22.337 回答