CryptographicEngine.Decrypt 方法 return c# UWP 应用中的一个错误
CryptographicEngine.Decrypt method return an error in a c# UWP app
我不明白为什么这段代码 return 出错:
Data error (cyclic redundancy check). (Exception from HRESULT: 0x80070017)
因为来自 Silverlight 平台的等效代码不会引发 exception.This 是下面的 UWP c# 代码:
public static async Task<Stream> Decrypt(Stream source,
IBuffer easKey,IBuffer IV, byte[] masterKey)
{
try
{
SymmetricKeyAlgorithmProvider aes = SymmetricKeyAlgorithmProvider.OpenAlgorithm(SymmetricAlgorithmNames.AesCbcPkcs7);
if ((source.Length % aes.BlockLength) != 0)
{
var temp = new MemoryStream();
temp.SetLength(source.Length + (aes.BlockLength - source.Length % aes.BlockLength));
source.CopyTo(temp);
source = temp;
}
CryptographicKey symmKey = aes.CreateSymmetricKey(easKey);
var sarray = ((MemoryStream)source).ToArray();
IBuffer resultBuffer = CryptographicEngine.Decrypt(symmKey,sarray.AsBuffer(), IV);
byte[] result;
CryptographicBuffer.CopyToByteArray(resultBuffer, out result);
return new MemoryStream(result);
}
catch (Exception e)
{
await new MessageDialog(e.StackTrace, e.Message).ShowAsync();
}
return null;
}
vcsjones 在您的问题下的评论中指出了重要的一点。如果您检查数据长度是块长度的偶数倍,但事实并非如此,您应该立即抛出异常,表明数据是错误的。因为用 AES 加密的任何东西都不会导致与块长度的偶数倍不同的任何东西。即使是空字符串也会产生一个 1 块长的密文。
话虽如此,您已准备好加密算法来解密带有 PKCS7 填充的块。另一方面,如果您得到一个短块,则将其复制到长度正确的 MemoryStream 中。我假设最后一个字节是零。因此该块不是有效的密文块。
PKCS7 填充添加 X 个字节以获得块大小的偶数倍,并且每个字节都是相同的数字。因此,如果您的块大小为 16 字节(128 位),而您的最后一个块仅包含 10 个字节的真实信息,那么您会将最后 6 个字节填充为 0x06 0x06 0x06 0x06 0x06 0x06.
不过,这里的关键是在加密之前将此填充添加到纯文本中。您不能简单地将填充添加到部分密文块的末尾并能够对其进行解密。这些强加密算法的本质是,块中任何给定位的最终值实际上是块中所有其他位的函数。因此,如果您丢失了该块的任何部分,您将无法挽回地丢失整个块。
现在,如果您确实需要尽可能多地解密消息,请丢弃部分块(正如我上面提到的那样,您永远不会解密它)。将其替换为完整的 0x10 块(重复 16 次)。这会告诉算法您正好有 X 个纯文本块,并且根据 PKCS7,您正好添加了一整块符合 PKCS7 标准的填充。这将允许您解密除消息的部分块之外的所有内容。
编辑说您应该使用相同的密钥加密填充块并将其附加到密文,以便能够解密除部分块之外的所有内容。但这无论如何都不是最简单的方法。在你的位置,我只是将我的解密设置更改为 padding = None。再次扔掉部分块,其余的只要没有损坏,应该没有问题解密。
我不明白为什么这段代码 return 出错:
Data error (cyclic redundancy check). (Exception from HRESULT: 0x80070017)
因为来自 Silverlight 平台的等效代码不会引发 exception.This 是下面的 UWP c# 代码:
public static async Task<Stream> Decrypt(Stream source,
IBuffer easKey,IBuffer IV, byte[] masterKey)
{
try
{
SymmetricKeyAlgorithmProvider aes = SymmetricKeyAlgorithmProvider.OpenAlgorithm(SymmetricAlgorithmNames.AesCbcPkcs7);
if ((source.Length % aes.BlockLength) != 0)
{
var temp = new MemoryStream();
temp.SetLength(source.Length + (aes.BlockLength - source.Length % aes.BlockLength));
source.CopyTo(temp);
source = temp;
}
CryptographicKey symmKey = aes.CreateSymmetricKey(easKey);
var sarray = ((MemoryStream)source).ToArray();
IBuffer resultBuffer = CryptographicEngine.Decrypt(symmKey,sarray.AsBuffer(), IV);
byte[] result;
CryptographicBuffer.CopyToByteArray(resultBuffer, out result);
return new MemoryStream(result);
}
catch (Exception e)
{
await new MessageDialog(e.StackTrace, e.Message).ShowAsync();
}
return null;
}
vcsjones 在您的问题下的评论中指出了重要的一点。如果您检查数据长度是块长度的偶数倍,但事实并非如此,您应该立即抛出异常,表明数据是错误的。因为用 AES 加密的任何东西都不会导致与块长度的偶数倍不同的任何东西。即使是空字符串也会产生一个 1 块长的密文。
话虽如此,您已准备好加密算法来解密带有 PKCS7 填充的块。另一方面,如果您得到一个短块,则将其复制到长度正确的 MemoryStream 中。我假设最后一个字节是零。因此该块不是有效的密文块。
PKCS7 填充添加 X 个字节以获得块大小的偶数倍,并且每个字节都是相同的数字。因此,如果您的块大小为 16 字节(128 位),而您的最后一个块仅包含 10 个字节的真实信息,那么您会将最后 6 个字节填充为 0x06 0x06 0x06 0x06 0x06 0x06.
不过,这里的关键是在加密之前将此填充添加到纯文本中。您不能简单地将填充添加到部分密文块的末尾并能够对其进行解密。这些强加密算法的本质是,块中任何给定位的最终值实际上是块中所有其他位的函数。因此,如果您丢失了该块的任何部分,您将无法挽回地丢失整个块。
现在,如果您确实需要尽可能多地解密消息,请丢弃部分块(正如我上面提到的那样,您永远不会解密它)。将其替换为完整的 0x10 块(重复 16 次)。这会告诉算法您正好有 X 个纯文本块,并且根据 PKCS7,您正好添加了一整块符合 PKCS7 标准的填充。这将允许您解密除消息的部分块之外的所有内容。
编辑说您应该使用相同的密钥加密填充块并将其附加到密文,以便能够解密除部分块之外的所有内容。但这无论如何都不是最简单的方法。在你的位置,我只是将我的解密设置更改为 padding = None。再次扔掉部分块,其余的只要没有损坏,应该没有问题解密。