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
I am writing a .NET application that interact with MySQL database using ODBC connection. My application will create the database schema and tables on the database upon start up. However, I encountered a weird unexplainable case below:
First my application will create the following table
CREATE TABLE IF NOT EXISTS `sample` (
`item_ID` varchar(20) NOT NULL,
`item_No` int(11) NOT NULL,
`sample_col1` varchar(20) NOT NULL,
`sample_col2` varchar(20) NOT NULL,
PRIMARY KEY (`item_ID`, `item_No`)
) ENGINE=InnoDB;
Populate the table with
INSERT INTO sample SET item_ID='abc', item_No=1, sample_col1='', sample_col2='';
INSERT INTO sample SET item_ID='abc', item_No=2, sample_col1='', sample_col2='';
Then I execute a SELECT query from within the .NET application using the following code:
Dim query As String
query = "SELECT item_ID, item_No, sample_col1, sample_col2 FROM sample"
Dim conn As New OdbcConnection("Driver={MySQL ODBC 5.1 Driver};Server=localhost; port=3306;Database=test; User=dbuser;Password=dbpassword;Option=3;")
Dim cmd As New OdbcDataAdapter(query, conn)
Dim dt As New DataTable
cmd.FillSchema(dt, SchemaType.Source)
cmd.Fill(dt)
conn.Close()
The cmd.Fill(dt) line will throw an Exception: "Failed to enable constraints. One or more rows contain values violating non-null, unique, or foreign-key constraints".
However if I modify the table creation query to:
CREATE TABLE IF NOT EXISTS `sample` (
`item_ID` varchar(20) NOT NULL,
`item_No` int(11) NOT NULL,
`sample_col1` varchar(20) NOT NULL,
`sample_col2` varchar(20) NOT NULL,
PRIMARY KEY (`item_No`,`item_ID`) '--> Here Primary Key order is inverted
) ENGINE=InnoDB;
The vb.net code works perfectly. Notice on the second creation query I inverted the order of the PRIMARY KEY creation. On the first example I put item_ID first while on the second example I put item_No first.
Does anyone has any clue why this is happening? Also is there any difference from the point of view of MySQL database between the first and second create query?
Any input will be appreciated. Thank you !
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.
I am using C# and .Net 4.0 with MS SQL 2008.
I am running an integration test to verify that data is getting correctly stored and retrieved. It fails more often than not. When I look into it I see that I am getting the wrong value back from the linq-to-sql call. I have profiled the linq-to-sql statement and discovered that in Server Management Studio, the profiled SQL returns the wrong value, while a hand typed query with the same parameters works correctly.
The linq-to-sql query and result:
exec sp_executesql N'SELECT TOP (1) [t0].[ID], [t0].[UserName], [t0].TCID
FROM [dbo].[Users] AS [t0]
WHERE ([t0].[TCID] = #p0) AND ([t0].[UserName] = #p1)',N'#p0 int,#p1
nvarchar(4000)',#p0=8,#p1=N'ҭРӱґѻ'
Results in
ID UserName TCID
2535 ҭРґѻӱ 8
As you can see, UserName does not match what was in the equality check.
If I do this, I get the expected result:
SELECT TOP 1000 [ID]
,[UserName]
,[TCID]
FROM [dbo].[Users]
where TCID=8 and username = 'ҭРӱґѻ'
I get back:
ID UserName TCID
Which is correct.
UserName is nvarchar(50), ID and TCID are int.
Any ideas why the first query gets the wrong result?
You're not getting results on the second query because you forgot to prefix the parameter with N. I bet you get a result just like with the dynamic SQL if you use:
SELECT TOP 1000 [ID]
,[UserName]
,[TCID]
FROM [dbo].[Users]
where TCID=8 and username = N'ҭРӱґѻ'; -- note the N prefix here
Now, I'm not saying you should get a result, but that should make the behavior consistent between your two testing methods. What is the collation of the column? You can "fix" this in a way by specifying a binary collation. For example, this should yield proper behavior:
SELECT COUNT(*)
FROM [dbo].[Users]
WHERE [UserName] = N'ҭРӱґѻ' COLLATE Latin1_General_BIN;
-- 0
SELECT COUNT(*)
FROM [dbo].[Users]
WHERE [UserName] = N'ҭРґѻӱ' COLLATE Latin1_General_BIN;
-- 1
With the collation you are using (probably a SQL Server-specific collation), some Unicode code points are not defined. Thus SQL Server treats them as if they were an empty string:
SELECT CASE WHEN N'ӱ' COLLATE SQL_Latin1_General_CP1_CI_AS = N'' THEN 'YES' ELSE 'NO' END
If we use a newer Windows collation such as Cyrillic_General_100_CI_AS, we see that these strings do not match:
SELECT CASE WHEN N'ӱ' COLLATE Cyrillic_General_100_CI_AS = N'' THEN 'YES' ELSE 'NO' END
Here's a blog post on MSDN that should explain more.
I'm new to developing stored procedures so in my attempt I got a bit mind-boggled. I understand basically what they are conceptually, but having issues when implementing. For reference, I'm hand-coding, but intend to use SQL Server, ASP.NET, and C# technologies.
The basic idea is for a user to create their own user account, update their information as they see fit, delete their account, and authenticate the information as necessary (usernames&passwords, account information, etc). I presume this must be done with 4 different stored procedures: createAccount, modAccount, delAccount, authentAccount.
My understanding is that the C#/ASP should be doing the actual data collection and then transferring the data to SQL for insertion into the database. Please correct me if I'm wrong or if there's a more efficient method (speed is extremely important for this).
Getting started with the first stored procedure (create), I coded this:
CREATE PROC createAccount
AS
INSERT INTO Customer (cssn, first_name, middle_name, last_name, company, address, phone_number, email, account, occupation, nationality, social, successful_invites)
VALUES ()
GO
What do I put in for values? The variable that's used on the C# side?
I'm also not sure how I should incorporate security in this space and security is going to be important as well.
If you could provide examples with your explanation, that would be EXTREMELY helpful.
Here's the basic form of your SP (first 3 columns shown):
create procedure createAccount
(
#cssn varchar(100),
#first_name varchar(100),
#last_name varchar(100),
... -- remaining columns
)
as
begin
insert into Customer (cssn, first_name, last_name, ... )
values (#cssn, #first_name, #last_name, ... )
end
One side note, ASP has user accounts built in and set up automatically if you want to just use those (SqlMembershipProvider).
CREATE PROCEDURE createAccount
#cssn VARCHAR(100)
, #first_name VARCHAR(100)
, #middle_name VARCHAR(100)
, #last_name VARCHAR(100)
, #company VARCHAR(100)
, #address VARCHAR(150)
, #phone_number VARCHAR(20)
, #email VARCHAR(100)
, #account VARCHAR(100)
, #occupation VARCHAR(100)
, #nationality VARCHAR(100)
, #social VARCHAR(100)
, #successful_invites INT
AS
BEGIN
INSERT INTO Customer ( cssn, first_name, middle_name, last_name, company, address, phone_number, email, account, occupation, nationality, social, successful_invites )
VALUES ( #cssn, #first_name, #middle_name, #last_name, #company, #address, #phone_number, #email, #account, #occupation, #nationality, #social, #successful_invites )
END
I just guessed at the data types. As for security, the only thing you need to add is re-validation rules (i.e. blocking of HTML tags and stuff in your VARCHAR fields). Otherwise, security is built-in automatically because you are using parameters and variables (and not using dynamic sql).
If you want to use SqlMembershipProvider, you have already in asp.net a set of controls that will help you. You may have to use their tables and not your Customer table, but that is ok since the membership provider will take care of everything. Just google for more info about membership provider and the login controls.
You have in other answers examples of stored procedures, but why using stored procedures? An ORM is a much easier and more productive way of doing things. My favorite is NHiberntate. LINQ to SQL, Entity Framework are from Microsoft. Just google for a "linq to sql hello world" to see how it's done.
In 99.99% of the cases an ORM is just fine.There are rare cases when you need to replace the ORM with a sql query or sp.
Stored procedures are nice ways to store SQL scripts in a central location among other things. That's the basic, most simplest concept. If you have a script in your code with (update TABLE set EMAIL = '"+email+"'), you're better off putting into a stored procedure. You can even do additions and updates in the same procedure returning the ID of the existing/updated or newly created record. You can get VERY creative with them.
You can do updates and additions in the same procedure if it's secure of course.
create usp_AddEmail(
#email varchar(50)
)
AS
DECLARE #EMAILID INT;
SET #EMAILID = (SELECT ID FROM TABLE WHERE EMAIL = #EMAIL);
IF ISNULL(#EMAILID,0) = 0
BEGIN
INSERT INTO TABLE(EMAIL) VALUES(#email);
SET #EMAILID = (SELECT ID FROM TABLE WHERE EMAIL = #EMAIL);
END
SELECT #EMAILID AS EMAILID
In C#, you use CommandType = CommandType.StoredProcedure to let it know it's a stored procedure. Then you use .Parameters.AddWithValue(sqlParameter, value) to pass the value. (You can wrap it into a method):
SqlConnection connLoc = new SqlConnection(YourConnectionSring);
SqlCommand commLoc = new SqlCommand();
SqlDataReader drLoc;
commLoc.Connection = connLoc;
commLoc.CommandType = CommandType.StoredProcedure;
commLoc.CommandText = "usp_AddEmail";
commLoc.Parameters.AddWithValue(#email, emailString);
connLoc.Open();
drLoc = commLoc.ExecuteReader(CommandBehavior.CloseConnection);