C# rijndael, преобразование набора символов вызывает проблемы

Я работаю над реализацией AES-256-CBC (показанной ниже), она будет использоваться в настройке клиент-база данных. Ключ хранится локально, и цель этой схемы состоит в том, чтобы сделать некоторые значения нечитаемыми, если утечка содержимого базы данных.

Поскольку IV имеет фиксированную длину, я планировал сделать зашифрованный текст зашифрованным сообщением с префиксом вектора инициализации (IV+C), а процедура дешифрования взять зашифрованный текст, отдельно сохранить IV и C и обработать C с помощью сохраненный вектор инициализации.

После нескольких неудачных попыток проверки этого метода я закомментировал часть шифрования, чтобы увидеть, что происходит. Оказывается, что либо IV, либо зашифрованный текст имеют неправильную длину, даже если эта длина фиксирована. Сначала я предположил, что вектор инициализации Rijndael с 16 байтами должен был помочь, поэтому я конвертировал все в UTF8, но он все еще не работает, как предполагалось. Хуже того: зашифрованный текст пропускает первый символ случайным образом (что для меня большая проблема, чем постоянная ошибка).

У меня нет идей, что мне здесь не хватает? (примечание: ящики сообщений предназначены для отладки)

    public string Encrypt(string input)
    {
        string cipher = null;

        RijndaelManaged Crypto = new RijndaelManaged();
        Random r = new Random();

        Crypto.KeySize = 256;
        Crypto.BlockSize = 128;
        Crypto.Mode = CipherMode.CBC;
        Crypto.Padding = PaddingMode.PKCS7;

        byte[] message = Encoding.UTF8.GetBytes(@input);
        byte[] pubkey = Encoding.UTF8.GetBytes(@public_key.PadRight(16, '#').Substring(0, 16));
        byte[] iv = new byte[16];

        r.NextBytes(iv);

        Crypto.Key = pubkey;
        Crypto.IV = iv; 

        try
        {
            ICryptoTransform Encrypt = Crypto.CreateEncryptor();
            cipher = @Encoding.UTF8.GetString(iv) + @Encoding.UTF8.GetString(message);//@Encoding.UTF8.GetString(iv) + @Encoding.UTF8.GetString(Encrypt.TransformFinalBlock(message, 0, message.Length));

            if (debug)
                MessageBox.Show("ENC\r\ninput (" + input.Length + "): " + @input + "\r\nmessage (" + message.Length + "): " + @System.Text.Encoding.UTF8.GetString(message) + "\r\npubkey (" + pubkey.Length + "):" + @System.Text.Encoding.UTF8.GetString(pubkey) + "\r\ninitialization vector (" + iv.Length + "): " + @System.Text.Encoding.UTF8.GetString(iv) + "\r\ncipher (" + cipher.Length + "): " + @cipher);
        }
        catch (CryptographicException e)
        {
            MessageBox.Show("ENC\r\ninput (" + input.Length + "): " + @input + "\r\nmessage (" + message.Length + "): " + @System.Text.Encoding.UTF8.GetString(message) + "\r\npubkey (" + pubkey.Length + "):" + @System.Text.Encoding.UTF8.GetString(pubkey) + "\r\ninitialization vector (" + iv.Length + "): " + @System.Text.Encoding.UTF8.GetString(iv) + "\r\ncipher (" + cipher.Length + "): " + @cipher + "\r\n\r\nException:\r\n" + e.ToString());
            cipher = "ENCRYPTION ERROR";
        }
        return cipher;
    }

    public string Decrypt(string input)
    {
        string message = "";

        byte[] iv = Encoding.UTF8.GetBytes(@input.Substring(0, 15)); // ლ(ಠ益ಠლ)
        byte[] cipherdata = Encoding.UTF8.GetBytes(@input.Substring(16, input.Length - 16)); // ಥ‸ಥ
        byte[] pubkey = Encoding.UTF8.GetBytes(public_key.PadRight(16, '#').Substring(0, 16));
        RijndaelManaged Crypto = new RijndaelManaged();

        Crypto.Key = pubkey;
        Crypto.Mode = CipherMode.CBC;
        Crypto.Padding = PaddingMode.PKCS7;
        Crypto.KeySize = 256;
        Crypto.BlockSize = 128;

        try
        {
            ICryptoTransform Decrypt = Crypto.CreateDecryptor();
            Decrypt.TransformFinalBlock(cipherdata, 0, cipherdata.Length);
            message = System.Text.Encoding.UTF8.GetString(cipherdata);

            if (debug)
                MessageBox.Show("DEC\r\ninput (" + input.Length + "): " + @input + "\r\ncipherdata (" + cipherdata.Length + "): " + @Encoding.UTF8.GetString(cipherdata) + "\r\ninitialization vector (" + iv.Length + "): " + @Encoding.UTF8.GetString(iv) + "\r\npubkey (" + pubkey.Length + "): " + @Encoding.UTF8.GetString(pubkey) + "\r\nMessage (" + message.Length + "): " + message);
        }
        catch (CryptographicException e)
        {
            MessageBox.Show("DEC\r\ninput (" + input.Length + "): " + @input + "\r\ncipherdata (" + cipherdata.Length + "): " + @Encoding.UTF8.GetString(cipherdata) + "\r\ninitialization vector (" + iv.Length + "): " + @Encoding.UTF8.GetString(iv) + "\r\npubkey (" + pubkey.Length + "): " + @Encoding.UTF8.GetString(pubkey) + "\r\nMessage (" + message.Length + "): " + message + "\r\n\r\nException:\r\n" + e.ToString());
            message = "DECRYPTION ERROR";
        }
        return message;
    }

1 ответ

Решение

Конкатенация случайных байтовых последовательностей, как если бы они были строками, при использовании кодировки переменной длины, такой как UTF8, является плохой идеей.

Вы должны объединить байтовый массив IV и выходной буфер зашифрованного текста, чтобы создать байтовый массив, затем Convert.ToBase64String создать переносимое строковое представление.

Другие вопросы по тегам