1

AES 暗号化/復号化に問題があります。コメントされたコードは機能しましたが、「パディングが無効であり、削除できません」というエラーが発生することがあったため、ここで説明されているように変更しました

しかし、試してみると、復号化中に以下のコードで空の文字列が返されます。どこを間違えているのかわからない。2 つの静的関数 bytesToString と stringToBytes は暗号化とは関係なく、別の場所で使用しています。キーの長さとブロック サイズは OKAY です。デバッガーでこれを見つけました:

「'csEncrypt.Length' はタイプ 'System.NotSupportedException' の例外をスローしました」

私は 3.5 .NET Visual STudio 2008 で作業しています

ブロックを暗号化したままにしておくとわかるように、デバッガーの prtscr は 0 バイトの長さであり、cryptostream にはいくつかの例外があります。

デバッガーからの印刷画面

修正方法は?手がかりを教えてください。

static class Aes
{
    public static string bytesToHexString(byte[] key)
    {
        return BitConverter.ToString(key).Replace("-", String.Empty);
    }

    public static byte[] stringToBytes(string key)
    {
        return Enumerable.Range(0, key.Length)
                 .Where(x => x % 2 == 0)
                 .Select(x => Convert.ToByte(key.Substring(x, 2), 16))
                 .ToArray();
    }

    public static void generateKeyAndIv(out byte[] key, out byte[] IV)
    {
        using (AesCryptoServiceProvider aesAlg = new AesCryptoServiceProvider())
        {
            aesAlg.BlockSize = 128;
            aesAlg.KeySize = 256;
            aesAlg.Padding = PaddingMode.None;
            //aesAlg.Mode = CipherMode.CBC;
            aesAlg.GenerateKey();
            aesAlg.GenerateIV();
            key = aesAlg.Key;
            IV = aesAlg.IV;
        }
    }
    public static string EncryptStringToString(string plainText, byte[] Key, byte[] IV)
    {
        byte[] bytes =EncryptStringToBytes_Aes(plainText, Key, IV);
        return Convert.ToBase64String(bytes);
        //return Encoding.UTF8.GetString(bytes, 0, bytes.Length);
    }

    public static string DecryptStringToString(string cipherText, byte[] Key, byte[] IV)
    {
        //byte[] bytes = Encoding.UTF8.GetBytes(cipherText);
        byte[] bytes = Convert.FromBase64String(cipherText);
        return DecryptStringFromBytes_Aes(bytes, Key, IV);
    }

    public static byte[] EncryptStringToBytes_Aes(string plainText, byte[] Key, byte[] IV)
    {
        // Check arguments. 
        if (plainText == null || plainText.Length <= 0)
            throw new ArgumentNullException("plainText");
        if (Key == null || Key.Length <= 0)
            throw new ArgumentNullException("Key");
        if (IV == null || IV.Length <= 0)
            throw new ArgumentNullException("Key");
        /*byte[] encrypted;
        // Create an AesCryptoServiceProvider object 
        // with the specified key and IV. 
        using (AesCryptoServiceProvider aesAlg = new AesCryptoServiceProvider())
        {
            aesAlg.BlockSize = 128;
            aesAlg.KeySize = 256;
            aesAlg.Padding = PaddingMode.PKCS7;
            aesAlg.Mode = CipherMode.CBC;
            aesAlg.Key = Key;
            aesAlg.IV = IV;
            // Create a decrytor to perform the stream transform.
            ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);


            // Create the streams used for encryption. 
            using (MemoryStream msEncrypt = new MemoryStream())
            {
                using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
                {
                    using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
                    {
                        //Write all data to the stream.
                        swEncrypt.Write(plainText);
                    }
                }

                encrypted = msEncrypt.ToArray();
            }
        }*/
        byte[] encrypted;
        // Create an AesManaged object
        // with the specified key and IV.
        using (AesManaged aesAlg = new AesManaged())
        {

            // Create a decrytor to perform the stream transform.
            aesAlg.Padding = PaddingMode.None;
            aesAlg.BlockSize = 128;
            aesAlg.KeySize = 256;
            ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);

            // Create the streams used for encryption.
            using (var msEncrypt = new MemoryStream())
            using (var csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
            using (var swEncrypt = new StreamWriter(csEncrypt))
            {
                swEncrypt.Write(plainText);
                csEncrypt.FlushFinalBlock();
                encrypted = msEncrypt.ToArray();
            }
        }

        //return encrypted;


        // Return the encrypted bytes from the memory stream. 
        return encrypted;

    }

    public static string DecryptStringFromBytes_Aes(byte[] cipherText, byte[] Key, byte[] IV)
    {
        // Check arguments. 
        if (cipherText == null || cipherText.Length <= 0)
            throw new ArgumentNullException("cipherText");
        if (Key == null || Key.Length <= 0)
            throw new ArgumentNullException("Key");
        if (IV == null || IV.Length <= 0)
            throw new ArgumentNullException("IV");

        // Declare the string used to hold 
        // the decrypted text. 
        string plaintext = null;

        // Create an AesCryptoServiceProvider object 
        // with the specified key and IV. 
        using (AesCryptoServiceProvider aesAlg = new AesCryptoServiceProvider())
        {
            aesAlg.BlockSize = 128;
            aesAlg.KeySize = 256;
            aesAlg.Padding = PaddingMode.PKCS7;
            aesAlg.Mode = CipherMode.CBC;
            aesAlg.Key = Key;
            aesAlg.IV = IV;
            // Create a decrytor to perform the stream transform.
            ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);

            // Create the streams used for decryption. 
            using (MemoryStream msDecrypt = new MemoryStream(cipherText))
            {
                using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
                {
                    using (StreamReader srDecrypt = new StreamReader(csDecrypt))
                    {

                        // Read the decrypted bytes from the decrypting stream 
                        // and place them in a string.
                        plaintext = srDecrypt.ReadToEnd();
                    }
                }
            }

        }

        return plaintext;

    }
}

OK、全体の状況をもう少し説明します。私は自分の安全な電子メールを書きました。2倍の暗号化があります。サーバーとクライアント間の通信は、RSA および AES によって暗号化されます。また、ユーザーが作成したメッセージは RSA + AES によって暗号化されます。

送信メッセージは次のようになります。

  1. クライアントがサーバーに接続します。
  2. それらは安全な接続を確立します(サーバーは公開鍵を送信し、クライアントはAESキーを生成し、サーバーの公開鍵を介して暗号化してサーバーに送信します。その後、サーバーとクライアントはAESキーを使用して通信します)。
  3. クライアントは XML でメッセージを作成します。メッセージには、base64 に読み取られた後、AES で暗号化されるファイルを含めることができます。
  4. メッセージは db に書き込まれます。

メッセージの受信は次のようになります。

  1. サーバーへの接続。
  2. 安全な接続を確立します。
  3. サーバーからメッセージを取得します。
  4. RSA 秘密鍵を使用して AES キーを復号化します。
  5. 復号化された AES キーを使用してメッセージを復号化します。
  6. ファイルがある場合は、AES を使用してそれらを復号化し、バイトに base64_decode して保存します。

問題は、大きなデータの暗号化にあります。200 ~ 300 kB でさえ問題になる場合があります。

私が発見したもう 1 つの興味深い点は、デバッガーを介してコードを実行すると機能するが、デバッガーなしでコードを実行すると機能することです。うまくいきません。


解決

問題の解決策を見つけました。異なるキー/ivs を使用して、AES 暗号化/復号化を非常に高速に 2 回使用したため、ガベージ コレクターはこれらのオブジェクトを消去しませんでした。解決策は追加されていました

GC.Collect();
GC.WaitForPendingFinalizers();

DecryptStringFromBytes_Aes と EncryptStringToBytes_Aes で値を返す直前

私と同じように悩んでいる方の参考になれば幸いです。

4

1 に答える 1

1

ストリームの使用方法は、基になるストリームにデータが書き込まれていないことを意味しました。理由はわかりませんが、やり直した別のアプローチを見つけました。

次のコードを使用すると、コンソールアプリケーションとして実行し、目的に合わせて機能するように形状を変更できるはずです。それがどうなるか教えてください:

using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;

namespace Encrypto
{
    public static class Program
    {
        public static void Main()
        {

            const string password = "test";
            const string text = "test";
            var cipherText = Aes.Encrypt(password, text);
            var decrypted = Aes.Decrypt(password, cipherText);

            Console.WriteLine(decrypted);
            Console.ReadKey();
        }
    }

    internal static class Aes
    {
        public static EncryptedData Encrypt(string password, string data)
        {
            return Transform(true, password, data, null) as EncryptedData;
        }

        public static string Decrypt(string password, EncryptedData data)
        {
            return Transform(false, password, data.DataString, data.SaltString) as string;
        }

        private static object Transform(bool encrypt, string password, string data, string saltString)
        {
            using (var aes = new AesManaged())
            {
                aes.Mode = CipherMode.CBC;
                aes.Padding = PaddingMode.PKCS7;
                var keyLen = aes.KeySize/8;
                var ivLen = aes.BlockSize/8;
                const int saltSize = 8;
                const int iterations = 8192;

                var salt = encrypt ? new byte[saltSize] : Convert.FromBase64String(saltString);
                if (encrypt)
                {
                    new RNGCryptoServiceProvider().GetBytes(salt);
                }

                var bcKey = new Rfc2898DeriveBytes("BLK" + password, salt, iterations).GetBytes(keyLen);
                var iv = new Rfc2898DeriveBytes("IV" + password, salt, iterations).GetBytes(ivLen);
                var macKey = new Rfc2898DeriveBytes("MAC" + password, salt, iterations).GetBytes(16);

                aes.Key = bcKey;
                aes.IV = iv;

                var rawData = encrypt ? Encoding.UTF8.GetBytes(data) : Convert.FromBase64String(data);

                using (var transform = encrypt ? aes.CreateEncryptor() : aes.CreateDecryptor())
                using (var memoryStream = encrypt ? new MemoryStream() : new MemoryStream(rawData))
                using (var cryptoStream = new CryptoStream(memoryStream, transform, encrypt ? CryptoStreamMode.Write : CryptoStreamMode.Read))
                {
                    if (encrypt)
                    {
                        cryptoStream.Write(rawData, 0, rawData.Length);
                        cryptoStream.FlushFinalBlock();
                        return new EncryptedData(salt, macKey, memoryStream.ToArray());
                    }
                    var originalData = new byte[rawData.Length];
                    var count = cryptoStream.Read(originalData, 0, originalData.Length);

                    return Encoding.UTF8.GetString(originalData, 0, count);
                }
            }
        }

        public class EncryptedData
        {
            public EncryptedData(byte[] salt, byte[] mac, byte[] data)
            {
                Salt = salt;
                MAC = mac;
                Data = data;
            }

            private byte[] Salt { get; set; }

            public string SaltString
            {
                get { return Convert.ToBase64String(Salt); }
            }

            private byte[] MAC { get; set; }

            private byte[] Data { get; set; }

            public string DataString
            {
                get { return Convert.ToBase64String(Data); }
            }
        }
    }
}

この回答を提供するためのソース:.NETでのAES暗号化の使用-パディングが無効であり、削除できないことを示すCryptographicException

于 2013-03-01T09:13:29.213 に答える