Encrypt in SQL server and read/decrpyt client-side - c#

Ive written in sql :
CREATE SYMMETRIC KEY SecureSymmetricKey
WITH ALGORITHM = TRIPLE_DES
ENCRYPTION BY PASSWORD = 'StrongPassword';
DECLARE #str NVARCHAR(1000)
SET #str = 'lala';
OPEN SYMMETRIC KEY SecureSymmetricKey
DECRYPTION BY PASSWORD = 'StrongPassword';
DECLARE #encrypted_str VARBINARY(MAX)
SET #encrypted_str =
EncryptByKey(Key_GUID('SecureSymmetricKey'), #str);
the encrypted_str value is in a table now.
how can i read it in c# ? ( and decrypt in c# )

You don't "decrypt" it in C#. Decrypt it in the select statement on the way back out.

You need to encrypt and decrypt at the same layer of your application stack; if you encrypt at the SQL Server layer, you need to decrypt before returning the data to your application.
If you want to decrypt it in the C# application, you need to encrypt it there first, and store the encrypted values in the database.

Related

How to query data when columns are encrypted in SQL Server 2016

I've been trying to find solution in this problem. I encrypted my columns from my database in SQL Server 2016 . In order to read the data I already set the parameters "Column Encryption Setting=Enabled"; I know I don't have problem in my certificate because I was able to query like SELECT * FROM TABLE, but I wasn't able to query using a WHERE condition. For example
"SELECT column FROM Table WHERE column='abc'" something like that.
The Error is:
"Operand type clash: varchar is incompatible with varchar(8000)
encrypted with (encryption_type = 'DETERMINISTIC',... and so on"
I don't know why I can't retrieve the data from the encrypted column.
I assume you have encrypted your column using the Always Encrypted feature of SQL Server.
With Always Encrypted SQL Server does not know the keys for encrypting and decrypting your data. It's the job of your client application to encrypt data before sending it to SQL Server.
When you execute this query:
SELECT column FROM Table WHERE column='abc'
you are asking SQL Server to compare the non-encrypted varchar 'abc' to the encrypted values found in your encrypted column. This will fail - as you've noted yourself.
Your client application must encrypt the value you want to use in your WHERE clause before sending it off to SQL Server.
If you're using SSMS you can do this by enabling parameterization for always encrypted. You can enable this in SSMS under Query>>Query options>>Execution>>Advanced>>Enable Parameterization for Always Encrypted.
Once this is enabled you'll be able to filter your table like this:
DECLARE #MyValue VARCHAR(100) = 'abc';
SELECT [Column] FROM [Table] WHERE [Column] = #MyValue;
What happens behind the scenes is that SSMS encrypts the value of the #MyValue parameter for you before sending it off to SQL Server. It is important that you declare and initialize the parameter at once. Otherwise SSMS is unable to encrypt the value before sending the query to SQL Server.
You can read more about parameterization for always encrypted here. Feel free to comment below if the above explanation is unclear to you.
You need to use DECRYPTBYKEY
SELECT *
FROM Table WHERE convert(varchar,DecryptByKey(column))='abc'
The way you use this function depends on if you are using symmetric keys and a hash, or just a key, etc.

SQL Server Always encrypt collation incompatibility on insert

I have a Windows Forms application that has been working for a long time as is and now I have to encrypt/decrypt some columns in the database. I made all the configurations on my database, configured my columns to be encrypted, changed column's datatype to nvarchar(max) from varchar(max), created a certificate on Windows store, exported the cert for the client and now I am trying to do the job on client side.
I changed windows form application framework to 4.6, added Column Encryption Setting=enabled to my connection string, updated the .dbml designer but I still get the following error when trying to insert a value:
Operand type clash: varchar(8000) encrypted with (encryption_type = 'DETERMINISTIC', encryption_algorithm_name = 'AEAD_AES_256_CBC_HMAC_SHA_256', column_encryption_key_name = 'CEK_Auto1', column_encryption_key_database_name = 'MCM_V2') collation_name = 'Greek_CI_AS' is incompatible with varchar(50) encrypted with (encryption_type = 'DETERMINISTIC', encryption_algorithm_name = 'AEAD_AES_256_CBC_HMAC_SHA_256', column_encryption_key_name = 'CEK_Auto1', column_encryption_key_database_name = 'mydb') collation_name = 'Greek_BIN2'
I am using Linq for queries
You seem to be using non-BIN2 collation. Always Encrypted currently only supports BIN2 collations.
From official documentation:
Always Encrypted is not supported for the columns with the below
characteristics (e.g. the Encrypted WITH clause cannot be used in
CREATE TABLE/ALTER TABLE for a column, if any of the following
conditions apply to the column):
...
String (varchar, char, etc.)
columns with non-bin2 collations

Decrypting the column level SQL encrypted values using C#

I have been started reading and experimenting the encryption and decryption techniques in C#
I have tried Data Encryption and Decryption in SQL Server 2008 using the information available in the following link
http://www.c-sharpcorner.com/UploadFile/chinnasrihari/data-encryption-and-decryption-in-sql-server-2008/
By using following query (from example of link) I can able to decrypt a value using SQL queries
OPEN SYMMETRIC KEY Sym_password
DECRYPTION BY CERTIFICATE Cert_Password WITH PASSWORD = 'Password!2';
SELECT CAST(DECRYPTBYKEY([Password]) as varchar(200))
FROM Security
CLOSE SYMMETRIC KEY Sym_password;
How can I do the same operation from my C# application?
In my MVC application, I'm using email address as my username to login (password is hashed by default using simple membership). Please suggest me the best ways to encrypt the email field in SQL level and decrypt those values in C#(application level)
When a user enters his username (email) in application, How can I encrypt that value in application side and compare it with the encrypted value in the SQL records.
CREATE TABLE [Users] (
UserID int identity(1,1) primary key,
[Login] varchar(32) unique,
[Email] varchar(32) unique,
[Password] varbinary(256) not null,
[BackupCode] varbinary(256) not null,
ModifiedDate datetime default (getdate()));
DECLARE #EncryptionKey nvarchar(32) = '007London' ;
DECLARE #Password varchar(32) = 'LoveDanger&Romance' ;
DECLARE #Code varchar(32) = 'GoNawazGo' ;
Insert Query(encryption):
INSERT [Users] ([Login], [Email], [Password], [BackupCode])
SELECT 'JamesBond', 'test#test.com',
EncryptByPassPhrase(#EncryptionKey, #Password),
EncryptByPassPhrase(#EncryptionKey, #Code),
Select Query(decryption):
SELECT *,
DecryptedPassword = Convert(varchar(32),
DecryptByPassPhrase(#EncryptionKey, [Password])),
[Password],
DecryptedCode = Convert(varchar(32),
DecryptByPassPhrase(#EncryptionKey, [BackupCode])),
[BackupCode],
FROM [Users]
Select Query(decryption):
Convert(varchar(32) should be Convert(nvarchar(32)
In nvarchar the code points for standard ASCII letters are the same as for ASCII but padded out with a 0x00 byte.

SQL encryption only returning first character

I have the following query
UPDATE mytable
SET col1 = ENCRYPTBYPASSPHRASE ('Key', col2)
FROM mytable
when I decrypt it using
SELECT CONVERT(VARCHAR(20), DECRYPTBYPASSPHRASE ('Key', col1))
FROM mytable
The result returned is only the first character, for example if the field contains "Computer" the result is only "C".
col2 is probably nvarchar not varchar. Try
SELECT CONVERT(NVARCHAR(20), DECRYPTBYPASSPHRASE ('Key', col1))
FROM mytable
In nvarchar the code points for standard ASCII letters are the same as for ASCII but padded out with a 0x00 byte.
When you cast that to varchar that it is treated as a null character that terminates the string.
After investigation I had come to many issues so I will post what I came across, so anyone can benefit from it.
If you changed to data type of the SQL column to varbinary then make sure that when you decrypt the data, you use the same old data type. That is if you had a column of varchar that contains data and then you changed it to varbinary, you must decrypt it using varchar, if you use nvarchar ,you will get garbage data.
You must encrypt and decrypt using the same way. That is if you are loading the password from a stored procedure and use it in encrypting,and the SAME EXACT password is loaded using a function for decryption, u will also get garbage data (I tested it but I did not know why is this behaviour!)may be internally there is some difference between how data is returned from SP and functions.
Hope this helps anyone out there !
Use CONVERT with data type and size of the value you are encrypting updating.
Looks like EncryptByKey does not recognize the data properly as per column schema.
Try as below
ENCRYPTBYKEY(KEY_GUID('<Key Name>'), CONVERT(varchar(20),col1))

Encrypt Data in one "slot" in database

I read over a great tutorial on how to encrypt the data using a symmetrical key in one column.
Click here to view it.
This has helped me set up a column for encryption, which is what I need. My problem is that I will constantly be updating rows in my database - so copying over one whole original column to the encrypted columm like the tutorial shows doesn't work. Is there a way that I can insert a value that is given to me (using C#/asp) and direclty encrypt it as I insert it into the database, rather than having to place it in one column and copying it over, and then dropping the other column?
Just call EncryptByKey on your data to encrypt You don't need another column. In this case it has to be included in your SQL which should be a parameterized query or a stored procedure.
Insert into Whatever
YourEncryptedData
Values ( EncryptByKey(...))
You may have top open your key first depending on your implementation.
http://msdn.microsoft.com/en-us/library/ms174361.aspx
You need to have the certificate open do do the encryption. This is from the page you linked to:
OPEN SYMMETRIC KEY TestTableKey
DECRYPTION BY CERTIFICATE EncryptTestCert
UPDATE TestTable
SET EncryptSecondCol = ENCRYPTBYKEY(KEY_GUID('TestTableKey'),SecondCol)
Inserting works the same:
OPEN SYMMETRIC KEY TestTableKey
DECRYPTION BY CERTIFICATE EncryptTestCert
INSERT INTO TestTable (FirstCol, EncryptSecondCol)
VALUES (6, ENCRYPTBYKEY(KEY_GUID('TestTableKey'),'Sixth'))
You can execute the open key command before doing your insert or create a stored procedure to do the insert.

Categories

Resources