基于Key和Initial Vector在SQL Server中创建对称AES128密钥

时间:2014-07-02 09:25:12

标签: sql-server sql-server-2008 aes ef-migrations encryption

我有一些Key和Initial Vector,我在.NET应用程序中用于加密。我们说它们是:

Key = 0x0102030405060708090A0B0C0D0E
IV  = 0xA1A2A3A4A5A6A7A8A9AAABACADAE

在某些情况下,我想对SQL Server(不在应用程序中)执行加密,但在应用程序中解密数据。我以为我可以在数据库中创建临时对称密钥并执行加密:

CREATE SYMMETRIC KEY #TempKey
    WITH ALGORITHM   = AES_128
    , IDENTITY_VALUE = ???
    , KEY_SOURCE     = ???
    ENCRYPTION BY PASSWORD = 'Pa$$w0rd';

OPEN SYMMETRIC KEY #TempKey
    DECRYPTION BY PASSWORD = 'Pa$$w0rd';

SELECT EncryptByKey(Key_Guid('#TempKey'), 'Secret Data');

CLOSE SYMMETRIC KEY #TempKey;
DROP SYMMETRIC KEY #TempKey;

但是我不知道我应该提供什么作为IDENTITY_VALUE和KEY_SOURCE才能拥有"共享"数据库与我的应用之间的关键。



更新2014-07-07

我想提供一些问题的背景知识。

  1. 首先,我使用EF Code First方法,当我需要执行一些数据库更新时,我使用Code First Migrations,我想进一步使用这种基于纯迁移的方法。不幸的是,正如问题Use custom logic in EF Code First migration中找到的那样,无法在UpDown方法中获取当前的SqlConnection和SqlTransaction。我唯一的方法 - 使用Sql方法执行自定义SQL查询。

  2. 在下一次数据库更新中,我想在一列中加密数据。加密应该满足两个条件:(1)数据应该在客户端应用程序中解密(不在SQL Server端),(2)对称密钥应该以加密形式存储在客户端应用程序中,描述应该是使用密钥容器中的非对称密钥完成。不幸的是,这使得CRL UDF在这里无用 - 当我尝试在UDF中获取基于密钥容器的密钥时,我得到了一个权限异常:System.Security.SecurityException: Request for the permission of type System.Security.Permissions.KeyContainerPermission

  3. 在我和1.和2.期间所做的所有尝试之后。我最终了解到我可以尝试使用CREATE SYMMETRIC KEY查询在数据库中创建临时对称密钥,但我所做的所有尝试都是它最终没有任何成功。

  4. 希望这一切都有助于理解问题并找到正确的解决方案。

2 个答案:

答案 0 :(得分:0)

首先,我建议您阅读本文,这是一篇非常好的文章,介绍对称加密的含义以及如何使用它。 http://benjii.me/2010/05/how-to-use-sql-server-encryption-with-symmetric-keys/

关于如何解密.Net中的数据,请阅读: http://msdn.microsoft.com/en-us/library/te15te69%28v=vs.110%29.aspx?cs-save-lang=1&cs-lang=csharp#code-snippet-1

然后,用几句话就是这样的:在服务器上创建一个对称密钥,指定一个硬编码的identity_value和一个key_source。在应用程序端,使用identity_value(IV)和key_source(KEY)的相同值创建对称密钥。

以下是有关如何在sql server和vb.net中加密/解密值的示例。希望能帮助到你。 vb.net示例基于另一个线程here

=============================================== ======================

SQL SERVER:

declare @value varchar(max) = 'I am a very secret value', @encripted_value varchar(max)

--encription on server side
CREATE SYMMETRIC KEY #TempKey
    WITH ALGORITHM   = AES_128
    , IDENTITY_VALUE = 'abcdefgh'
    , KEY_SOURCE     = 'zxcvzxcv'
    ENCRYPTION BY PASSWORD = 'Pa$$w0rd1234';

OPEN SYMMETRIC KEY #TempKey
    DECRYPTION BY PASSWORD = 'Pa$$w0rd1234';

SELECT @encripted_value = cast( EncryptByKey(Key_Guid('#TempKey') , @value) as varchar(max));

select @encripted_value

CLOSE SYMMETRIC KEY #TempKey;
DROP SYMMETRIC KEY #TempKey;


--decription in server side, I put it here only for example
CREATE SYMMETRIC KEY #TempKey1
    WITH ALGORITHM   = AES_128
    , IDENTITY_VALUE = 'abcdefgh'
    , KEY_SOURCE     = 'zxcvzxcv'
    ENCRYPTION BY PASSWORD = 'Pa$$w0rd1234';

OPEN SYMMETRIC KEY #TempKey1
    DECRYPTION BY PASSWORD = 'Pa$$w0rd1234';

SELECT cast(DecryptByKey(@encripted_value) as varchar(max)) ;

CLOSE SYMMETRIC KEY #TempKey1;
DROP SYMMETRIC KEY #TempKey1;

=============================================== ===============================

VB.NET

Imports System
Imports System.IO
Imports System.Xml
Imports System.Text
Imports System.Security.Cryptography

Module Module1

Private key() As Byte = {}
Private IV() As Byte = {}

Private Const EncryptionKey As String = "abcdefgh"
Private Const IdentityValue As String = "zxcvzxcv"


Public Function Decrypt(ByVal stringToDecrypt As String) As String
    Try
        Dim inputByteArray(stringToDecrypt.Length) As Byte
        key = System.Text.Encoding.UTF8.GetBytes(EncryptionKey)
        IV = System.Text.Encoding.UTF8.GetBytes(IdentityValue)
        Dim des As New DESCryptoServiceProvider
        inputByteArray = Convert.FromBase64String(stringToDecrypt)
        Dim ms As New MemoryStream
        Dim cs As New CryptoStream(ms, des.CreateDecryptor(key, IV), CryptoStreamMode.Write)
        cs.Write(inputByteArray, 0, inputByteArray.Length)
        cs.FlushFinalBlock()
        Dim encoding As System.Text.Encoding = System.Text.Encoding.UTF8
        Return Convert.ToBase64String(ms.ToArray())
    Catch ex As Exception
        Return vbNull
    End Try
End Function


Public Function Encrypt(ByVal stringToEncrypt As String) As String
    Try
        key = System.Text.Encoding.UTF8.GetBytes(EncryptionKey)
        IV = System.Text.Encoding.UTF8.GetBytes(IdentityValue)
        Dim des As New DESCryptoServiceProvider
        Dim inputByteArray() As Byte = Encoding.UTF8.GetBytes(stringToEncrypt)
        Dim ms As New MemoryStream
        Dim cs As New CryptoStream(ms, des.CreateEncryptor(key, IV), CryptoStreamMode.Write)
        cs.Write(inputByteArray, 0, inputByteArray.Length)
        cs.FlushFinalBlock()
        Return Convert.ToBase64String(ms.ToArray())
    Catch ex As Exception
        Return vbNull
    End Try
End Function

End Module

答案 1 :(得分:0)

您的代码和nelucon的答案存在问题,就是将SQL Server中的IDENTITY_VALUE和.NET中的初始化矢量(IV)视为相同。他们不是。

初始化矢量是一个附加的随机值,被“抽取”到加密函数中,以使密文难以预测。每次加密任何值时都应生成该密钥,因此它不是加密密钥的一部分。

IDENTITY_VALUE (来自CREATE SYMMETRIC KEY文档)

生成一个GUID,用于标记用新的对称密钥加密的数据。该标记可用于将密钥与加密数据进行匹配。

因此,基本上,IV是用于随机化密文的标准参数,而IDENTITY_VALUE是SQL Server特定的密钥标识符。

如果使用SQL Server加密某些纯文本,则所得密文将包含一些元数据,而不仅仅是加密的文本。它的确切结构取决于SQL Server版本和所使用的加密算法,但是它可能包含一个版本块,所使用的加密密钥的guid(这是从IDENTITY_VALUE派生的),Initialization Vector(初始化向量)(由SQL Server随机生成)和加密的文本。您的.NET应用需要加密的文本,加密密钥和IV,它们均作为单独的值提供。

我的建议是坚持使用应用程序或SQL Server来管理加密。 如果确实需要在应用程序中解密在SQL Server中解密的内容,那么我认为您需要找出密文的确切结构,并从中检索IV和加密的文本。

有关SQL Server herehere中的密文结构的更多信息。