我试图使用存储过程将文档加密/解密到表中,所以我创建了一个CLR程序集,该程序集具有使用RijndaelManaged类的加密/解密功能。我可以加密字节,但是当我解密字节并保存文档时,我注意到在编码方面存在差异,这会破坏文档。我直接将varbinary(max)
字节发送到加密/解密函数,因此我不确定是什么导致了不同的编码。我想知道如何才能以正确的编码将其解密?
这是我的程序集的样子:
public static byte[] AES_EncryptBytes(byte[] input, string pass)
{
try
{
return EncryptBytesToBytes(input, System.Text.Encoding.UTF8.GetBytes(pass));
}
catch (Exception)
{
return null;
}
}
public static byte[] AES_DecryptBytes(byte[] input, string pass)
{
try
{
return DecryptBytesFromBytes(input, System.Text.Encoding.UTF8.GetBytes(pass));
}
catch (Exception)
{
return null;
}
}
private static byte[] EncryptBytesToBytes(byte[] Input, byte[] Key)
{
return EncryptBytesToBytes(Input, Key, null);
}
private static byte[] EncryptBytesToBytes(byte[] Input, byte[] Key, byte[] IV)
{
// Check arguments.
if ((Input == null) || (Input.Length <= 0))
{
throw (new ArgumentNullException("plainText"));
}
if ((Key == null) || (Key.Length <= 0))
{
throw (new ArgumentNullException("Key"));
}
// Create an RijndaelManaged object
// with the specified key and IV.
RijndaelManaged rijAlg = new RijndaelManaged();
rijAlg.Key = Key;
if (!(IV == null))
{
if (IV.Length > 0)
{
rijAlg.IV = IV;
}
else
{
rijAlg.Mode = CipherMode.ECB;
}
}
else
{
rijAlg.Mode = CipherMode.ECB;
}
byte[] encrypted = null;
// Create a decrytor to perform the stream transform.
ICryptoTransform encryptor = rijAlg.CreateEncryptor(rijAlg.Key, rijAlg.IV);
encrypted = encryptor.TransformFinalBlock(Input, 0, Input.Length);
// Return the encrypted bytes from the memory stream.
return encrypted;
}
private static byte[] DecryptBytesFromBytes(byte[] cipherText, byte[] Key)
{
return DecryptBytesFromBytes(cipherText, Key, null);
}
private static byte[] DecryptBytesFromBytes(byte[] cipherText, byte[] Key, byte[] IV)
{
// Check arguments.
if ((cipherText == null) || (cipherText.Length <= 0))
{
throw (new ArgumentNullException("cipherText"));
}
if ((Key == null) || (Key.Length <= 0))
{
throw (new ArgumentNullException("Key"));
}
// Create an RijndaelManaged object
// with the specified key and IV.
RijndaelManaged rijAlg = new RijndaelManaged();
rijAlg.Key = Key;
if (!(IV == null))
{
if (IV.Length > 0)
{
rijAlg.IV = IV;
}
else
{
rijAlg.Mode = CipherMode.ECB;
}
}
else
{
rijAlg.Mode = CipherMode.ECB;
}
byte[] output = null;
// Create a decrytor to perform the stream transform.
ICryptoTransform decryptor = rijAlg.CreateDecryptor(rijAlg.Key, rijAlg.IV);
// Create the streams used for decryption.
MemoryStream msDecrypt = new MemoryStream(cipherText);
CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read);
StreamReader srDecrypt = new StreamReader(csDecrypt);
// Read the decrypted bytes from the decrypting stream
// and place them in a string.
MemoryStream ms = new MemoryStream();
while (!srDecrypt.EndOfStream)
{
ms.WriteByte((byte)(srDecrypt.Read()));
}
ms.Position = 0;
output = ms.ToArray();
return output;
}
这是我的函数:
CREATE FUNCTION [dbo].EncryptBytes
(@Input VARBINARY(MAX), @KEY [NVARCHAR](100))
RETURNS VARBINARY(MAX)
WITH EXECUTE AS CALLER
AS
EXTERNAL NAME [DocumentsEncryption].[AES_EncryptDecrypt.AES_EncryptDecryptLibrary].AES_EncryptBytes
GO
CREATE FUNCTION [dbo].[DecryptBytes]
(@Input VARBINARY(MAX), @KEY [NVARCHAR](100))
RETURNS VARBINARY(MAX)
WITH EXECUTE AS CALLER
AS
EXTERNAL NAME [DocumentsEncryption].[AES_EncryptDecrypt.AES_EncryptDecryptLibrary].[AES_DecryptBytes]
GO
例如,这是如何执行的:
DECLARE @DocumentStream VARBINARY(MAX)
--these bytes below represent a document
SET @DocumentStream = 0x255044462D312E350D25E2E3CFD30D0A
DECLARE @EncryptionKey NVARCHAR(100)
SET @EncryptionKey = 'ayb&e#i&BWLGMe2V'
DECLARE @EncryptedDocumentStream VARBINARY(MAX)
SET @EncryptedDocumentStream = dbo.[EncryptBytes](@DocumentStream, @EncryptionKey)
DECLARE @DecryptedDocumentStream VARBINARY(MAX)
SET @DecryptedDocumentStream = dbo.[DecryptBytes](@EncryptedDocumentStream,@EncryptionKey)
--@DecryptedDocumentStream will return the decrypted bytes but the encoding is wrong
SELECT @DecryptedDocumentStream
--This will return: 0x255044462D312E350D25FDFDFDFD0D0A
--Instead of the original bytes: 0x255044462D312E350D25E2E3CFD30D0A
答案 0 :(得分:1)
问题在于您的解密方法中所有流处理代码中的“某处”。我这么说是因为我不会深入挖掘并找到确切的错误。跳出来的第一件事是您的加密和解密方法看起来并不“对称”-彼此之间做的大致相同(但某些操作相反)。对于成对的加密/解密方法 1 ,通常是一个不好的迹象。
因此,如果我使解密看起来像加密,而不要对流进行所有处理:
private static byte[] DecryptBytesFromBytes(byte[] cipherText, byte[] Key, byte[] IV)
{
if ((cipherText == null) || (cipherText.Length <= 0))
{
throw (new ArgumentNullException("cipherText"));
}
if ((Key == null) || (Key.Length <= 0))
{
throw (new ArgumentNullException("Key"));
}
RijndaelManaged rijAlg = new RijndaelManaged();
rijAlg.Key = Key;
if (!(IV == null))
{
if (IV.Length > 0)
{
rijAlg.IV = IV;
}
else
{
rijAlg.Mode = CipherMode.ECB;
}
}
else
{
rijAlg.Mode = CipherMode.ECB;
}
ICryptoTransform decryptor = rijAlg.CreateDecryptor(rijAlg.Key, rijAlg.IV);
return decryptor.TransformFinalBlock(cipherText, 0, cipherText.Length);
}
(我也跳过了一个output
变量-我没有看到它的需要,也没有评论只是告诉我们代码在做什么 ,我们可以通过阅读来确定代码)。
现在(与您的问题中的EncryptBytesToBytes
配对)可以成功地往返采样数据:
static void Main()
{
var inp = new byte[] { 0x25, 0x50, 0x44, 0x46, 0x2D, 0x31, 0x2E, 0x35,
0x0D, 0x25, 0xE2, 0xE3, 0xCF, 0xD3, 0x0D, 0x0A };
var key = "ayb&e#i&BWLGMe2V";
var oup = AES_DecryptBytes(AES_EncryptBytes(inp, key), key);
Console.ReadLine();
}
肉眼来看,inp
和oup
包含相同的数据。
(插入有关ECB是一种可怕模式的常见警告,除非出于很多特定的正当理由而选择它)
1 如果要建立一对加密/解密方法,我通常的建议是 slowly 和 simply 并确保该对可以在每个阶段进行往返,然后再添加更多复杂性。
第一步将是“返回输入缓冲区,忽略键和IV”。编写一些单元测试,以确认它具有一些适当大小的缓冲区以及特定的键和IV的往返行程。
然后只给实现增加一个小复杂度,并检查单元测试是否仍然通过,并进行迭代,直到方法完成您想要/需要的操作为止。
如果您需要“用一种语言加密,用另一种语言解密”,则实际上我建议对这两种语言都进行两次,以使它们都具有两种方法。然后验证您的实现之间在每个阶段的输出 匹配。