使用 AES/CBC/NoPadding 算法解密字符串 [英] Decrypt string using AES/CBC/NoPadding algorithm

查看:70
本文介绍了使用 AES/CBC/NoPadding 算法解密字符串的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在 c# Windows Phone 8 应用程序中使用 AES/CBC/Nopadding 解密加密的 Sting.我的字符串在 IsolatedSorage 的文件中.我粘贴了字符串 HERE 这是垃圾.

I want to decrypt an Encrypted Sting using AES/CBC/Nopadding in c# Windows Phone 8 application. My string is in file of IsolatedSorage. I pasted the string HERE which is junk.

从此文章我我正在使用 AesManaged 类来解密.但是如何将填充设置为 NoPadding 因为默认情况下填充设置为 PKCS7 来自 此处.

From this Article I am using AesManaged class to decrypt. But how to set padding to NoPadding because by default the padding set to PKCS7 from here.

        string fileName = "titlepage.xhtml";

        if (fileStorage.FileExists(fileName))
        {
            IsolatedStorageFileStream someStream = fileStorage.OpenFile(fileName, System.IO.FileMode.Open, FileAccess.Read);
            using (StreamReader reader = new StreamReader(someStream))
            {
                str1 = reader.ReadToEnd();

                MessageBox.Show(str1);

                try
                {
                    string text = Decrypt(str1, "****************", "****************");

                    MessageBox.Show(text);
                }
                catch (CryptographicException cryptEx)
                {
                    MessageBox.Show(cryptEx.Message, "Encryption Error", MessageBoxButton.OK);
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message, "General Error", MessageBoxButton.OK);
                }
            }
        }

    public string Decrypt(string dataToDecrypt, string password, string salt)
    {
        AesManaged aes = null;
        MemoryStream memoryStream = null;

        try
        {
            //Generate a Key based on a Password and HMACSHA1 pseudo-random number generator
            //Salt must be at least 8 bytes long
            //Use an iteration count of at least 1000
            Rfc2898DeriveBytes rfc2898 = new Rfc2898DeriveBytes(password, Encoding.UTF8.GetBytes(salt), 10000);               

            //Create AES algorithm
            aes = new AesManaged();
            //Key derived from byte array with 32 pseudo-random key bytes
            aes.Key = rfc2898.GetBytes(32);
            //IV derived from byte array with 16 pseudo-random key bytes
            aes.IV = rfc2898.GetBytes(16);

            //Create Memory and Crypto Streams
            memoryStream = new MemoryStream();
            CryptoStream cryptoStream = new CryptoStream(memoryStream, aes.CreateDecryptor(), CryptoStreamMode.Write);
            
            byte[] data = Convert.FromBase64String(dataToDecrypt);
            cryptoStream.Write(data, 0, data.Length);
            cryptoStream.FlushFinalBlock();

            //Return Decrypted String
            byte[] decryptBytes = memoryStream.ToArray();

            //Dispose
            if (cryptoStream != null)
                cryptoStream.Dispose();

            //Retval
            return Encoding.UTF8.GetString(decryptBytes, 0, decryptBytes.Length);
        }
        finally
        {
            if (memoryStream != null)
                memoryStream.Dispose();

            if (aes != null)
                aes.Clear();
        }            
    }

编辑 1:

当我在细线上解密我的加密字符串时

When I am decrypting my Encrypted string in thins line

 byte[] data = Convert.FromBase64String(dataToDecrypt);

移动到 Finally block 并得到 的异常输入不是有效的 Base-64 字符串,因为它包含非 Base-64 字符、两个以上的填充字符或非法解密字符串中填充字符中的字符.

这有点令人困惑,Windows Phone 中支持的解密类.

It is bit of confuse on this which is supported class to Decrypt in windows phone.

如果我完全错了,请向我建议有关 Windows Phone 算法的文章网址

If I am completely wrong suggest me url of article regarding algorithm in Windows Phone

编辑 2:

如以下答案所建议的那样我得到 cyperText 作为字节,它在解密方面很好.但它在描述中给出了一个例外

As Below answer suggested " I am getting cyperText as bytes it is fine in decryption side. But it is giving an exception with the description

       [Cryptography_SSD_InvalidDataSize]
    Arguments: 
    Debugging resource strings are unavailable. Often the key and arguments provide 
sufficient information to diagnose the problem

我认为问题在于 IV[salt key] 或将 padding 设置为 AesManged.但我无法将填充属性更改为 AesManaged 在 Windows Phone 中.默认情况下,AesManged 的​​填充是 PKCS7.我想更改为 NoPadding.因为我的 cyperText 是使用 AES/CBC/NoPadding 算法加密的"

I believe that problem is IV[salt key] or setting padding to AesManged. But I can't change padding property to AesManaged in Windows Phone. By default padding to AesManged is PKCS7. I want to change to NoPadding. Because my cyperText is encrypted using AES/CBC/NoPadding algorithm "

推荐答案

如果我理解这个问题,您的数据已经在 AES CBC 模式下加密,没有填充.但是在要解密数据的手机上,唯一的选择是 PKCS#7 填充.

If I understand the problem, you have data that is already encrypted in AES CBC mode, with no padding. But on the phone where you want to decrypt the data, the only option you have is PKCS#7 padding.

好吧,你很幸运!您可以使用 PKCS#7 填充解密密文.您需要做的就是在手机上将填充添加到密文中,然后对其进行解密.

Well, you are in luck! You can decrypt the ciphertext using PKCS#7 padding. All you need to do is add the padding to the ciphertext, on the phone, and then decrypt it.

要在事后添加填充,您将加密一小部分数据并将其附加到密文中.然后,你解密修改后的密文,去掉那一小部分数据,你就有了原始的明文.

To add padding after the fact, you will encrypt a small bit of data and append it to the ciphertext. Then, you decrypt the modified ciphertext, and take that small bit of data off, and you have the original plaintext.

这是你的做法:

  1. 在手机上获取密文.这是 16 字节的倍数,即使没有填充.没有其他可能——AES 密文总是 16 字节的倍数.

  1. Take a ciphertext on the phone. This is a multiple of 16 bytes, even if there is no padding. There is no other possibility -- AES ciphertext is always a multiple of 16 bytes.

将密文的最后 16 个字节放在一边,并将其设置为 AES ENCRYPT 的 IV.(加密,而不是解密.)使用与您稍后将用于解密的密钥相同的密钥.

Take the LAST 16 bytes of the ciphertext aside, and set that as the IV of your AES ENCRYPT. (Encrypt, not decrypt.) Use the same key as you are going to use to decrypt later.

现在加密小于 16 字节的内容,例如字符$".手机将为此添加 PKCS#7 填充.

Now encrypt something smaller than 16 bytes, for example, the character '$'. The phone is going to add PKCS#7 padding to this.

将生成的 16 字节密文附加到步骤 1 的原始密文中,您现在拥有一个正确的 PKCS#7 填充密文,其中包括原始明文和添加的$".

Append the resulting 16-bytes of ciphertext to the original ciphertext from step 1, and you now have a properly PKCS#7-padded ciphertext which includes the original plaintext plus the added '$'.

使用原来的IV,和相同的密钥,现在解密这个组合密文.您现在可以删除将出现在纯文本末尾(或您在步骤 3 中添加的任何内容)的$".

Use the original IV, and the same key, and now DECRYPT this combined ciphertext. You can now remove the '$' that will appear at the end of your plaintext (or whatever you added in step 3.)

当用原始密文的最后 16 字节加密小位时,您实际上是在真正的 AES CBC 模式下扩展密文,而您恰好使用 PKCS#7 填充来做到这一点,因此您现在可以解密整个事情,去掉一点点.您将拥有没有填充的原始明文.

When the small bit is encrypted with the last 16-bytes of the original ciphertext, you are actually extending the ciphertext in true AES CBC mode, and you happen to be doing that with PKCS#7 padding, so you can now decrypt the whole thing and take the small bit off. You will have the original plaintext which had no padding.

我认为在代码中显示会很有趣:

I thought this would be interesting to show in code:

var rfc2898 = new Rfc2898DeriveBytes("password", new byte[8]);

using (var aes = new AesManaged())
{
    aes.Key = rfc2898.GetBytes(32);
    aes.IV = rfc2898.GetBytes(16);

    var originalIV = aes.IV; // keep a copy

    // Prepare sample plaintext that has no padding
    aes.Padding = PaddingMode.None;
    var plaintext = Encoding.UTF8.GetBytes("this plaintext has 32 characters");
    byte[] ciphertext;
    using (var encryptor = aes.CreateEncryptor())
    {
        ciphertext = encryptor.TransformFinalBlock(plaintext, 0, plaintext.Length);
        Console.WriteLine("ciphertext: " + BitConverter.ToString(ciphertext));
    }

    // From this point on we do everything with PKCS#7 padding
    aes.Padding = PaddingMode.PKCS7;

    // This won't decrypt -- wrong padding
    try
    {
        using (var decryptor = aes.CreateDecryptor())
        {
            var oops = decryptor.TransformFinalBlock(ciphertext, 0, ciphertext.Length);
        }
    }
    catch (Exception e)
    {
        Console.WriteLine("caught: " + e.Message);
    }

    // Last block of ciphertext is used as IV to encrypt a little bit more
    var lastBlock = new byte[16];
    var modifiedCiphertext = new byte[ciphertext.Length + 16];

    Array.Copy(ciphertext, ciphertext.Length - 16, lastBlock, 0, 16);
    aes.IV = lastBlock;

    using (var encryptor = aes.CreateEncryptor())
    {
        var dummy = Encoding.UTF8.GetBytes("$");
        var padded = encryptor.TransformFinalBlock(dummy, 0, dummy.Length);

        // Set modifiedCiphertext = ciphertext + padded
        Array.Copy(ciphertext, modifiedCiphertext, ciphertext.Length);
        Array.Copy(padded, 0, modifiedCiphertext, ciphertext.Length, padded.Length);
        Console.WriteLine("modified ciphertext: " + BitConverter.ToString(modifiedCiphertext));
    }

    // Put back the original IV, and now we can decrypt...
    aes.IV = originalIV;

    using (var decryptor = aes.CreateDecryptor())
    {
        var recovered = decryptor.TransformFinalBlock(modifiedCiphertext, 0, modifiedCiphertext.Length);
        var str = Encoding.UTF8.GetString(recovered);
        Console.WriteLine(str);

        // Now you can remove the '$' from the end
    }
}

这篇关于使用 AES/CBC/NoPadding 算法解密字符串的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆