Creating a Symmetric AES128 Key in SQL Server based on Key and Initial Vector

两盒软妹~` 提交于 2020-03-18 16:40:28

问题


I have some Key and Initial Vector, which I'm using for encryption purposes in my .NET app. Let's say they are:

Key = 0x0102030405060708090A0B0C0D0E
IV  = 0xA1A2A3A4A5A6A7A8A9AAABACADAE

In some cases I would like to perform encryption on the SQL Server (not in the app), but decrypt the data in the app. I thought that I'll might be able to create a temporary symmetric key in the DB and perform encryption:

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;

But I have no idea what should I provide as IDENTITY_VALUE and KEY_SOURCE to have a "shared" key between DB and my app.



UPDATE 2014-07-07

I want to provide some background of my problem.

  1. First of all, I'm using EF Code First approach and when I need to perform some DB update I use Code First Migrations and I want to use further this pure migrations based approach. Unfortunately, as found during the question Use custom logic in EF Code First migration, there is no way to get current SqlConnection and SqlTransaction within Up or Down methods. The only way I have - execute custom SQL queries using the Sql method.

  2. In the next DB update I want to encrypt a data in one column. The encryption should satisfy two conditions: (1) the data should be decryptable in the client app (not on the SQL Server side), (2) the symmetrical key should be stored in the client app in an encrypted form and the description should be done using asymmetrical key from a key container. Unfortunately, this makes CRL UDF useless here - when I try to get key container based key in the UDF, I get an permission exception: System.Security.SecurityException: Request for the permission of type System.Security.Permissions.KeyContainerPermission

  3. After all tries that I made during 1. and 2. I ended up with understanding that I can try to create the temporary symmetric key in the DB using CREATE SYMMETRIC KEY query, but all my tries of doing it are ended up without any success.

Hope all this will help to understand the problem and find the right solution.


回答1:


First I suggest you read this, it is a really good article about what means symmetric encryption and how you can use it. http://benjii.me/2010/05/how-to-use-sql-server-encryption-with-symmetric-keys/

About how to decrypt data in .Net, read here: http://msdn.microsoft.com/en-us/library/te15te69%28v=vs.110%29.aspx?cs-save-lang=1&cs-lang=csharp#code-snippet-1

Then, in a few words is something like this: create a symmetric key on the server specifying a hardcoded identity_value and a key_source. In the application side, create a symmetric key using the same values for identity_value (IV) and key_source (KEY).

Here is an example about how to encrypt/decrypt a value in sql server and vb.net. Hope it helps. The vb.net example is based on another thread 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



回答2:


The problem with your code and nelucon's answer is treating IDENTITY_VALUE in SQL Server and Initialization Vector (IV) in .NET as if they were the same things. They are not.

Initialization Vector is an additional, random value which is 'pumped' into the encryption function to make the ciphertext less predictable. It should be generated each time you encrypt any value and so it is not a part of the encryption key.

IDENTITY_VALUE (from CREATE SYMMETRIC KEY docs)

generates a GUID with which to tag data that is encrypted with the new symmetric key. This tagging can be used to match keys to encrypted data.

So, basically, IV is a standard parameter used to randomize the ciphertext and IDENTITY_VALUE is a SQL Server specific key identifier.

If you use SQL Server to encrypt some plain text the resulting ciphertext will contain some metadata, not just the encrypted text. The exact structure of it depends on SQL Server version and encryption algorithm used, but it will likely contain a version block, guid of encryption key used (this is derived from the IDENTITY_VALUE), the Initialization Vector (randomly generated by SQL Server) and the encrypted text. Your .NET app expects the encrypted text, encryption key and IV, all provided as separate values.

My suggestion is to stick to either application or SQL Server to manage encryption. If you really, really need to decrypt in your app something that was decrypted in SQL Server, I think you'll need to find out the exact structure of your ciphertext and retrieve the IV and encrypted text from it.

More info about cyphertext structure in SQL Server here and here.



来源:https://stackoverflow.com/questions/24527430/creating-a-symmetric-aes128-key-in-sql-server-based-on-key-and-initial-vector

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!