【问题标题】:Creating a Symmetric AES128 Key in SQL Server based on Key and Initial Vector基于密钥和初始向量在 SQL Server 中创建对称 AES128 密钥
【发布时间】:2014-08-23 00:38:21
【问题描述】:

我有一些密钥和初始向量,用于在我的 .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 查询在数据库中创建临时对称密钥,但我所做的所有尝试都是以失败告终。

希望所有这些都有助于理解问题并找到正确的解决方案。

【问题讨论】:

    标签: sql-server sql-server-2008 aes entity-framework-migrations encryption


    【解决方案1】:

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

    初始化向量是一个附加的随机值,它被“注入”到加密函数中,使密文的可预测性降低。它应该在您每次加密任何值时生成,因此它不是加密密钥的一部分。

    IDENTITY_VALUE(来自CREATE SYMMETRIC KEY docs)

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

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

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

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

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

    【讨论】:

      【解决方案2】:

      首先我建议你阅读这篇文章,这是一篇关于什么是对称加密以及如何使用它的非常好的文章。 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 服务器:

      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
      

      【讨论】:

      • 不幸的是,它根本没有回答我的问题。我知道如何创建 SQL Server 加密密钥,我知道如何使用它。我知道如何在我的应用程序中加密/解密数据。我唯一不知道的是 - 如何在 SQL Server 和客户端应用程序之间创建 shared 键。
      • shared 表示服务器和应用程序共享相同的加密密钥,因此应用程序已经知道解密密钥。因此,在服务器和应用程序中使用相同的 key_source。它应该是一个强密码或类似的东西。
      • 没错!这就是共享的意思!我的问题是如何在双方使用相同的密钥源。你有什么想法吗?
      • 嗯,有 2 种方式,简单方式(双方硬编码)和 STS 方式(提供双方加密密钥的安全令牌服务)。我不知道你正在为什么样的项目工作,但我会采取简单的方法。至少目前,直到我有足够的时间学习 STS。
      • 硬编码对我来说完全没问题,那么我应该在我的问题示例中提供什么作为 IDENTITY_VALUE 和 KEY_SOURCE?
      猜你喜欢
      • 1970-01-01
      • 2017-12-26
      • 2015-04-11
      • 2011-07-03
      • 2015-12-07
      • 2017-04-23
      • 2011-10-01
      • 1970-01-01
      • 2010-10-30
      相关资源
      最近更新 更多