我需要在写入数据库之前加密一些数据,并在从数据库读取时解密。
我在这里使用了本指南中提供的代码: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中吗?
答案 0 :(得分:3)
不要相信互联网上的随机代码。你需要知道你在做什么。 ECB模式加密对于文本消息是不安全的 - 以及大多数其他加密操作。
您的问题直接依赖于加密方法中生成的密文的解码(使用Encoding.Unicode.GetString
,即错误的Microsoft名称UTF-16LE)。现在,密文总是包含随机字节。这些字节对并不总是构成有效的UTF-16LE编码字符。所以通常那些是从stringyfied密文遗漏的,或者它们被替换字符替换。
显然,如果引入了替换字符,那么特定的密文块将被解密成一块随机数据,使你的CRC校验失败。
如果由于某种原因需要将密文显示为文本,则base64对其进行编码。