【问题标题】:Symmetric Encryption cyclic redundancy check对称加密循环冗余校验
【发布时间】:2017-11-04 16:19:52
【问题描述】:

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

我在这里使用了本指南中提供的代码: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 中吗?

【问题讨论】:

  • 不要使用 ECB 模式,它不安全,请参阅ECB mode,向下滚动到企鹅。

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


【解决方案1】:

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

您的问题直接依赖于加密方法中生成的密文的解码(使用Encoding.Unicode.GetString,UTF-16LE 的坏微软名称)。现在密文总是包含随机字节。并且这些字节对并不总是构成有效的 UTF-16LE 编码字符。所以通常那些从字符串化的密文中被忽略或者被替换字符替换。

显然,如果引入了替代字符,那么特定的密文块将被解密为随机数据块,从而使您的 CRC 校验失败。


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

【讨论】:

  • 您建议对字符串进行何种加密?
  • 除 ECB 之外的任何东西,带有随机 IV(以密文为前缀)。 GCM 是一个不错的选择,因为它还对密文进行身份验证。请注意,GCM 的 IV 需要为 12 个字节并且应该从不重复。
猜你喜欢
  • 2016-10-20
  • 2015-02-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多