对称加密循环冗余校验

时间:2017-06-03 10:04:08

标签: c# encryption uwp windows-10-mobile

我需要在写入数据库之前加密一些数据,并在从数据库读取时解密。

我在这里使用了本指南中提供的代码:Encrypting and Decrypting data in an Universal Windows App

当我尝试解密时,我收到错误:

  

数据错误(循环冗余校验)。 (来自HRESULT的异常:0x80070017)

我认为这是因为密钥不同,因为我实例化SymmetricEncryptionHelper对象一次用于加密然后再次用于解密。为了解决这个问题,我将课程改为单身,但我仍然得到同样的错误:

public class SymmetricEncryptionHelper
{
    private readonly IBuffer randomBuffer;
    private readonly IBuffer randomBufferCBC;
    private readonly CryptographicKey cryptographicKey;
    private readonly string algorithmName;
    private readonly SymmetricKeyAlgorithmProvider cryptingProvider;

    private static SymmetricEncryptionHelper _instance;

    public static SymmetricEncryptionHelper Instance
    {
        get
        {
            if (_instance == null)
            {
                _instance = new SymmetricEncryptionHelper();
            }
            return _instance;
        }
    }


    /// <summary>
    /// Instantiate with a random generated buffer (not an option if
    /// you want to persist the encryption to disk)
    /// </summary>
    private SymmetricEncryptionHelper()
    {
        algorithmName = SymmetricAlgorithmNames.AesEcbPkcs7;
        cryptingProvider = SymmetricKeyAlgorithmProvider.OpenAlgorithm(algorithmName);
        randomBuffer = CryptographicBuffer.GenerateRandom(cryptingProvider.BlockLength);
        randomBufferCBC = null;
        cryptographicKey = cryptingProvider.CreateSymmetricKey(randomBuffer);
    }

    /// <summary>
    /// Instantiate with a custom generated buffer (good for
    /// persisting the encryption to disk)
    /// </summary>
    /// <param name="randomBuffer">The custom generated buffer</param>
    private SymmetricEncryptionHelper(IBuffer randomBuffer)
        : this()
    {
        this.randomBuffer = randomBuffer;
        cryptographicKey = cryptingProvider.CreateSymmetricKey(randomBuffer);
    }
    /// <summary>
    /// Instantiate with a custom generated buffer (good for
    /// persisting the encryption to disk) and with a custom
    /// generated CBC buffer (is using CBC algorithms)
    /// </summary>
    /// <param name="randomBuffer">The custom generated buffer</param>
    /// <param name="randomBufferCBC">The custom generated CBC buffer</param>
    private SymmetricEncryptionHelper(IBuffer randomBuffer, IBuffer randomBufferCBC)
        : this(randomBuffer)
    {
        this.randomBufferCBC = randomBufferCBC;
    }

    private bool IsMultipleOfBlockLength(IBuffer binaryData)
    {
        return (binaryData.Length % cryptingProvider.BlockLength) != 0;
    }
    /// <summary>
    /// Encrypts a given string
    /// </summary>
    /// <param name="data">Data to be encrypted</param>
    /// <returns>An encrypted string in Unicode</returns>
    public string Encrypt(string data)
    {
        if (string.IsNullOrEmpty(data))
        {
            return data;
        }

        var binaryData = Encoding.Unicode.GetBytes(data).AsBuffer();
        if (!algorithmName.Contains("PKCS7") && IsMultipleOfBlockLength(binaryData))
            throw new Exception("Message buffer length must be multiple of block length !!");
        var encryptedBinaryData = CryptographicEngine.Encrypt(cryptographicKey, binaryData, randomBufferCBC);
        return Encoding.Unicode.GetString(encryptedBinaryData.ToArray());
    }
    /// <summary>
    /// Decrypts a string in Unicode
    /// </summary>
    /// <param name="encryptedData">An encrypted string in Unicode</param>
    /// <returns>The decrypted string in Unicode</returns>
    public string Decrypt(string encryptedData)
    {
        if (string.IsNullOrEmpty(encryptedData))
        {
            return encryptedData;
        }

        try
        {
            var encryptedBinaryData = Encoding.Unicode.GetBytes(encryptedData).AsBuffer();
            var decryptedData = CryptographicEngine.Decrypt(cryptographicKey, encryptedBinaryData, randomBufferCBC);
            return Encoding.Unicode.GetString(decryptedData.ToArray());
        }
        catch (Exception ex)
        {
            return null;
        }
    }

}

任何人都可以看到我出错的地方 - 我已经搜索了错误,但似乎无法找到适合我的答案。

此外 - 一旦应用程序关闭,我将丢失密钥,那么这里的最佳做法是什么?我应该将密钥保存在PasswordVault中吗?

1 个答案:

答案 0 :(得分:3)

不要相信互联网上的随机代码。你需要知道你在做什么。 ECB模式加密对于文本消息是不安全的 - 以及大多数其他加密操作。

您的问题直接依赖于加密方法中生成的密文的解码(使用Encoding.Unicode.GetString,即错误的Microsoft名称UTF-16LE)。现在,密文总是包含随机字节。这些字节对并不总是构成有效的UTF-16LE编码字符。所以通常那些是从stringyfied密文遗漏的,或者它们被替换字符替换。

显然,如果引入了替换字符,那么特定的密文块将被解密成一块随机数据,使你的CRC校验失败。

如果由于某种原因需要将密文显示为文本,则base64对其进行编码。