如何获得C#和SQL2k8 AES加密之间的兼容性?

Vic*_*ues 11 .net encryption aes sql-server-2008

我在两列上进行了AES加密:其中一列存储在SQL Server 2000数据库中; 另一个存储在SQL Server 2008数据库中.

由于第一列的数据库(2000)没有加密/解密的本机功能,我们决定在应用程序级别使用.NET类进行加密逻辑.

但作为第二列的数据库(2008)允许这种功能,我们想使用数据库的功能,以更快的速度进行数据迁移,因为在SQL 2K数据迁移比这第二小得多,它会持续多因为在应用程序级别制作而超过50小时.

我的问题从这一点开始:使用相同的密钥,我在加密一个值时没有达到相同的结果,也没有相同的结果大小.

下面我们在两边都有完整的逻辑.当然我没有显示密钥,但其他一切都是一样的:

private byte[] RijndaelEncrypt(byte[] clearData, byte[] Key)
{
    var memoryStream = new MemoryStream();

    Rijndael algorithm = Rijndael.Create();

    algorithm.Key = Key;
    algorithm.IV = InitializationVector;

    var criptoStream = new CryptoStream(memoryStream, algorithm.CreateEncryptor(), CryptoStreamMode.Write);
    criptoStream.Write(clearData, 0, clearData.Length);
    criptoStream.Close();

    byte[] encryptedData = memoryStream.ToArray();
    return encryptedData;
}

private byte[] RijndaelDecrypt(byte[] cipherData, byte[] Key)
{
    var memoryStream = new MemoryStream();

    Rijndael algorithm = Rijndael.Create();

    algorithm.Key = Key;
    algorithm.IV = InitializationVector;

    var criptoStream = new CryptoStream(memoryStream, algorithm.CreateDecryptor(), CryptoStreamMode.Write);

    criptoStream.Write(cipherData, 0, cipherData.Length);

    criptoStream.Close();

    byte[] decryptedData = memoryStream.ToArray();

    return decryptedData;
}
Run Code Online (Sandbox Code Playgroud)

这是SQL Code示例:

open symmetric key columnKey decryption by password = N'{pwd!!i_ll_not_show_it_here}'

declare @enc varchar(max)

set @enc = dbo.VarBinarytoBase64(EncryptByKey(Key_GUID('columnKey'), 'blablabla'))

select LEN(@enc), @enc
Run Code Online (Sandbox Code Playgroud)

这个varbinaryToBase64是一个经过测试的sql函数,我们用它来将varbinary转换为我们用来在.net应用程序中存储字符串的相同格式.

C#中的结果是: eg0wgTeR3noWYgvdmpzTKijkdtTsdvnvKzh + uhyN3Lo =

SQL2k8中的相同结果是: AI0zI7D77EmqgTQrdgMBHAEAAACyACXb + P3HvctA0yBduAuwPS4Ah3AB4Dbdj2KBGC1Dk4b8GEbtXs5fINzvusp8FRBknF15Br2xI1CqP0Qb/M4w

我只是没有得到我做错了什么.

你有什么想法?

编辑:我认为有一点至关重要:我的C#代码有一个初始化向量,16个字节.这个IV没有设置在SQL对称密钥上,我可以这样做吗?

但即使没有在C#中填充IV,我的内容和长度也会得到非常不同的结果.

Tho*_*mas 6

我要看几件事:

  1. 确保明文的内容和编码完全相同.IIRC,流默认为UTF-8,而如果你的VarBinaryToBase64函数采用nvarchar参数,它将是Unicode.

  2. 确保两种加密算法使用相同的块大小.在SQL中,您可以在调用时确定算法CREATE SYMMETRIC KEY.如果未指定算法,则使用AES256.在.NET中使用RijndaelManaged,我相信默认的块大小是128,但你可以将它设置为256(如果使用Aes该类,则不能).

  3. 我要查找的最后一件事是SQL Server如何处理您在修订后的文章中提到的初始化向量.我想说它使用了这个authenticator参数,但这是一个疯狂的猜测.

编辑

我离开了.鉴于我发现的内容,您不能使用.NET类来解密由SQL Server的内置加密加密的文本,因为SQL Server会为加密的内容添加一堆goo,包括随机初始化向量.来自Michael Cole的书"Pro T-SQL 2005程序员指南"(尽管2008年也是这样):

当SQL Server通过对称密钥加密时,它会将元数据添加到加密结果以及填充,从而使加密结果比未加密的纯文本更大(有时更大).带元数据的加密结果的格式遵循以下格式:

  • 加密结果的前16个字节表示用于加密数据的对称密钥的GUID
  • 接下来的4个字节代表版本号,目前硬编码为"01000000".
  • DES加密的下一个8字节(AES加密为16字节)表示随机生成的初始化向量.
  • 接下来的8个字节是表示用于加密数据的选项的标题信息.如果使用authenticator选项,则此头信息包括验证器的20字节SHA1散列,使得头信息的长度为28个字节.
  • 加密数据的最后一部分是实际数据和填充本身.对于DES算法,此加密数据的长度将是8个字节的倍数.对于AES算法,长度将是16个字节的倍数.