C# rijndael,字符集转换导致麻烦

C# rijndael, characterset conversion causes trouble

我正在研究 AES-256-CBC 的实现(如下所示),这将用于客户端到数据库的设置。密钥存储在本地,此方案的目的是在数据库内容泄漏时使某些值不可读。

由于IV是固定长度的,我打算将密文设为初始化向量前缀为(IV+C)的密文,解密过程取密文,将IV和C分开存储,然后使用存储的初始化向量计算 C。

在多次尝试验证此方法失败后,我注释掉了加密部分以查看会发生什么。事实证明,IV 或密文的长度是错误的,即使这个长度是固定的。起初我以为 Rijndael initialization vector with 16 bytes 会有所帮助,因此我将所有内容都转换为 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;
    }

在使用像 UTF8 这样的可变长度编码时,将随机字节序列当作字符串连接是个坏主意。

您应该连接 IV 字节数组和密文输出缓冲区以生成字节数组,然后 Convert.ToBase64String 生成其可移植字符串表示形式。