使用有效值初始化SymmetricAlgorithm

时间:2014-07-23 05:18:21

标签: c# .net security cryptography encryption-symmetric

我没有安全背景,而且我处理密码学的最多是使用从网上获取的代码段。经过一些阅读后,很明显我需要更好地理解这些算法的工作原理。所以请忍受任何天真。

我试图实现一些期望完全初始化SymmetricAlgorithm实例的通用/抽象方法。据我所知,转换方法很好,而调用代码却没有。我得到以下例外:

The input data is not a complete block.
Length of the data to decrypt is invalid.

USAGE:

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

public class Program
{
    private static void Main (string [] args)
    {
        var cycled = "";
        Exception exception = null;
        var output = new byte [] { };
        var encoding = Encoding.UTF8;
        var source = "Dude, where's my car?!";

        var algorithm = RijndaelManaged.Create();
        algorithm.GenerateIV();
        algorithm.GenerateKey();
        algorithm.Mode = CipherMode.CBC; // CipherMode.OFB;

        // I've tried multiple combinations of algorithms and modes, which all result in exceptions.

        if (SecurityUtilities.Encrypt(source, encoding, algorithm, out output, out exception))
        {
            if (SecurityUtilities.Decrypt(output, encoding, algorithm, out cycled, out exception))
            {
                var r = cycled == source;
                Console.Write("{0} = {1} == {2}.", r, source, cycled);
            }
            else
            {
                Console.Write(exception);
            }
        }
        else
        {
            Console.Write(exception);
        }

        Console.ReadKey();
    }
}

通用代码:

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

public static class SecurityUtilities
{
    public static bool Encrypt (string source, Encoding encoding, SymmetricAlgorithm algorithm, out string output, out Exception exception)
    {
        var result = false;

        output = "";
        exception = null;

        if (source == null) { throw (new ArgumentNullException("source")); }
        if (encoding == null) { throw (new ArgumentNullException("encoding")); }
        if (algorithm == null) { throw (new ArgumentNullException("algorithm")); }

        try
        {
            var bytesEncrypted = new byte [] { };
            var bytesSource = encoding.GetBytes(source);

            if (SecurityUtilities.Encrypt(bytesSource, algorithm, out bytesEncrypted, out exception))
            {
                output = encoding.GetString(bytesEncrypted);

                result = true;
            }
        }
        catch (Exception e)
        {
            exception = e;
        }

        return (result);
    }

    public static bool Encrypt (string source, Encoding encoding, SymmetricAlgorithm algorithm, out byte [] output, out Exception exception)
    {
        var result = false;

        output = null;
        exception = null;

        if (source == null) { throw (new ArgumentNullException("source")); }
        if (encoding == null) { throw (new ArgumentNullException("encoding")); }
        if (algorithm == null) { throw (new ArgumentNullException("algorithm")); }

        try
        {
            var bytesEncrypted = new byte [] { };
            var bytesSource = encoding.GetBytes(source);

            if (SecurityUtilities.Encrypt(bytesSource, algorithm, out bytesEncrypted, out exception))
            {
                output = bytesEncrypted;

                result = true;
            }
        }
        catch (Exception e)
        {
            exception = e;
        }

        return (result);
    }

    public static bool Encrypt (byte [] source, SymmetricAlgorithm algorithm, out byte [] output, out Exception exception)
    {
        var result = false;

        output = null;
        exception = null;

        if (source == null) { throw (new ArgumentNullException("source")); }
        if (algorithm == null) { throw (new ArgumentNullException("algorithm")); }

        try
        {
            using (var memoryStream = new MemoryStream())
            {
                using (var transform = algorithm.CreateEncryptor())
                {
                    using (var cryptoStream = new CryptoStream(memoryStream, transform, CryptoStreamMode.Write))
                    {
                        cryptoStream.Write(source, 0, source.Length);
                    }
                }

                output = memoryStream.ToArray();
            }

            result = true;
        }
        catch (Exception e)
        {
            exception = e;
        }

        return (result);
    }

    public static bool Decrypt (string source, Encoding encoding, SymmetricAlgorithm algorithm, out string output, out Exception exception)
    {
        var result = false;

        output = "";
        exception = null;

        if (source == null) { throw (new ArgumentNullException("source")); }
        if (encoding == null) { throw (new ArgumentNullException("encoding")); }
        if (algorithm == null) { throw (new ArgumentNullException("algorithm")); }

        try
        {
            var bytesDecrypted = new byte [] { };
            var bytesSource = encoding.GetBytes(source);

            if (SecurityUtilities.Decrypt(bytesSource, algorithm, out bytesDecrypted, out exception))
            {
                output = encoding.GetString(bytesDecrypted);

                result = true;
            }
        }
        catch (Exception e)
        {
            exception = e;
        }

        return (result);
    }

    public static bool Decrypt (byte [] source, Encoding encoding, SymmetricAlgorithm algorithm, out string output, out Exception exception)
    {
        var result = false;

        output = "";
        exception = null;

        if (source == null) { throw (new ArgumentNullException("source")); }
        if (encoding == null) { throw (new ArgumentNullException("encoding")); }
        if (algorithm == null) { throw (new ArgumentNullException("algorithm")); }

        try
        {
            var bytesSource = source;
            var bytesDecrypted = new byte [] { };

            if (SecurityUtilities.Decrypt(bytesSource, algorithm, out bytesDecrypted, out exception))
            {
                output = encoding.GetString(bytesDecrypted);

                result = true;
            }
        }
        catch (Exception e)
        {
            exception = e;
        }

        return (result);
    }

    public static bool Decrypt (byte [] source, SymmetricAlgorithm algorithm, out byte [] output, out Exception exception)
    {
        var result = false;

        output = null;
        exception = null;

        if (source == null) { throw (new ArgumentNullException("source")); }
        if (algorithm == null) { throw (new ArgumentNullException("algorithm")); }

        try
        {
            using (var memoryStream = new MemoryStream(source))
            {
                using (var transform = algorithm.CreateDecryptor())
                {
                    using (var cryptoStream = new CryptoStream(memoryStream, transform, CryptoStreamMode.Read))
                    {
                        cryptoStream.Read(source, 0, source.Length);
                    }
                }

                output = memoryStream.ToArray();
            }

            result = true;
        }
        catch (Exception e)
        {
            exception = e;
        }

        return (result);
    }
}

核心问题是,Encrypt/Decrypt方法中是否存在错误,如果没有,调用代码中所需的最小变化是什么?

1 个答案:

答案 0 :(得分:2)

您提到的两个错误是同一问题的结果 - 许多对称算法是“分组密码”,即它们在特定大小的一个或多个块上工作。使用分组密码加密任意长度数据时,必须对其进行填充,使其长度为块大小的倍数,类似地,在解密时,必须删除填充以提供原始的未填充明文。

填充明文有多种不同的方法,使用的方法由Padding的{​​{1}}属性决定。如果设置为SymmetricAlgorithm,那么明文的长度必须PaddingMode.None的倍数。

如果我们假设BlockSize实例设置为使用除SymmetricAlgorithm以外的填充模式,则必须告诉算法您已完成加密并且应该添加填充(或者何时添加填充)解密你已经读过所有的密文,它应该删除填充)。使用None时,这是使用CryptoStream方法实现的,并且应该在将所有数据写入流后立即执行:

FlushFinalBlock()

using (var memoryStream = new MemoryStream()) { using (var transform = algorithm.CreateEncryptor()) { using (var cryptoStream = new CryptoStream(memoryStream, transform, CryptoStreamMode.Write)) { cryptoStream.Write(source, 0, source.Length); // Tell the CryptoStream we've written all the data and padding should be applied cryptoStream.FlushFinalBlock(); } } output = memoryStream.ToArray(); } 中,Decrypt(byte[], SymmetricAlgorithm, ...)使用memoryStream.ToArray()作为output,但memoryStream包含密文,生成的纯文本。您应该使用与加密相同的构造,除了使用transform.CreateDecryptor()而不是transform.CreateEncryptor()

using (var memoryStream = new MemoryStream())
{
    using (var transform = algorithm.CreateDecryptor())
    {
        using (var cryptoStream = new CryptoStream(memoryStream, transform, CryptoStreamMode.Write))
        {
            cryptoStream.Write(source, 0, source.Length);
            // Tell the CryptoStream we've written all the data and padding should be removed
            cryptoStream.FlushFinalBlock();
        }
    }
    output = memoryStream.ToArray();
}

最后,在您的Encrypt (string, Encoding, ...)中,您使用二进制密文并使用encoding.GetString()将其转换为字符串,这是无效的。如果您希望将二进制数据表示为字符串,则应使用类似Convert.ToBase64String()的内容。同样在Decrypt(string, Encoding, ...)中,您应该使用Convert.FromBase64String()将传入的Base64编码密文字符串转换为解密所需的字节数组。