Why generated MD5 hash in sql server are not equal? [duplicate] - c#

This question already has answers here:
TSQL md5 hash different to C# .NET md5
(4 answers)
Closed 8 years ago.
I have a table in SQL Server 2008 R2 that contain two field (WordHash, Word). This Hash field generated in C# and I need regenerate hash code for Word field in sql server.
But my problem is that generated MD5 hash in sql server and C# are different. I found below code to resolve this problem but still I have same problem.
SQL code:
CONVERT(NVARCHAR(32),HASHBYTES('MD5', 'some word'), 2)
After putting this code block to my query, I saw some wired result! This is my result:
My Query:
SELECT
[WordHash],
convert(nvarchar(32),HASHBYTES('MD5', 'Analytics'),2) AS TestHash,
convert(nvarchar(32),HASHBYTES('MD5', [Word]),2) AS SqlHash
FROM myTable
Result:
WordHash: A768CAA988605A2846599CF7E2D0C26A
TestHash: A768CAA988605A2846599CF7E2D0C26A
SqlHash F4AFA5FEF805F7F5163EC6402BAF61FF
Note that the 'Analytics' is one of records data in database.
Why TestHash & SqlHash are different while they generated from same code!?

The issue is NVARCHAR and VARCHAR get hashed to different values. Both HASHBYTES('MD5', 'Analytics'), and [WordHash] are hashes of VARCHAR values but [Word] is a NVARCHAR.
select HASHBYTES('MD5', 'Analytics'), 'varchar'
union
select HASHBYTES('MD5', N'Analytics'), 'nvarchar'
--outputs
------------------------------------- --------
0xA768CAA988605A2846599CF7E2D0C26A varchar
0xF4AFA5FEF805F7F5163EC6402BAF61FF nvarchar
To fix this you must either change [Word] to be VARCHAR or re-compute [WordHash] using NVARCHAR values.
Some useful further reading: Comparing SQL Server HASHBYTES function and .Net hashing

Related

Transport float with huge precision from Oracle to SQL Server via .Net and SqlBulkCopy

Working with ODP.Net I connect to Oracle database and transfer data to SQL Server using SqlBulkCopy.
As most of us already have noticed - Oracle float can hold values with precision higher than the .Net variables can hold.
.Net can hold precision up to 28 and Oracle can have e.g. 30.
In that case, the ODP.Net crashes with "Specified cast is invalid".
Oracle won't adjust their code and Microsoft won't create a new variable with higher precision, which leaves us to do workarounds.
In my case I couldn't find another way, but to convert the Oracle floats to nvarchar and then save them to SQL Server temp table that has a type nvarchar and then with a stored procedure to convert that nvarchar to SQL Server float.
Like that I can keep the original value and don't loose part of it's precision.
ORACLE:
For SqlBulkCopy I use this sql to get data from Oracle:
SELECT TO_CHAR(the_float) FROM the_table;
bulkCopy.WriteToServer(reader);
Then on the SQL Server I see the value, like this:
-,00000000000000088817841970012
This is the default formatting that Oracle does (the leading 0 is missed).
Convert that using
T-SQL
SELECT Try_convert(float,'-,00000000000000088817841970012') FloatValue
(I had to replace the , with . so my SQL Server would recognize it as float and the convert works!)
Try_convert(float,REPLACE('-,00000000000000088817841970012', ',', '.')) FloatValue
Is this the way to go around the Oracle Float and .Net variables ( ODP.Net and .Net ) inconsistency that I described?
Out of all tags you used, I know a little bit of Oracle. Perhaps you're missing the format mask with the TO_CHAR function. Here's an example:
SQL> create table the_table (the_float number);
Table created.
SQL> insert into the_table values (-0.00000000000000088817841970012);
1 row created.
SQL>
SQL> select to_char(the_float) your_result,
2 to_char(the_float, '0D9999999999999999999999999999999999') my_result
3 From the_table;
YOUR_RESULT MY_RESULT
---------------------------------------- -------------------------------------
-,00000000000000088817841970012 -0,0000000000000008881784197001200000
SQL>
See if it helps (hopefully, it does).
More about format models here: https://docs.oracle.com/en/database/oracle/oracle-database/12.2/sqlrf/Format-Models.html#GUID-EAB212CF-C525-4ED8-9D3F-C76D08EEBC7A

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.

Update/Insert rows in SQL table with encrypted columns using LinqToSQL - Always Encrypt

I am trying to get a hands-on on Always Encrypt feature of SQL Server 2016. I am using an existing application and database to do this.
I have a table [User], where i have encrypted the 'Password' column with 'Deterministic' type. I have made the connection string changes and I am able to retrieve all the rows. I have created the repository for this table.
I am trying to insert and update rows in this table with LinqToSQL using InsertOnSubmit() and SubmitChanges().
But whenever I try to insert new rows or update existing rows, I get the error:
Msg 206, Level 16, State 2, Line 7 Operand type clash: varchar is
incompatible with varchar(20) 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 = 'BRO_UAT')
collation_name = 'Latin1_General_BIN2'
I have read articles where using Stored Procs and parameterization has solved the issue. But, as I mentioned earlier, this is an existing project, and I have used LinqToSql and do not want to change the code. Insertion/Update works fine if the column is not encrypted!
Am I missing some setting?Please point me towards the right direction.
Change your column to nvarchar and check.
Also now even storing the password is not the best approach, store a signature instead and validate that signature when validating the password.
Check the link for the same.
https://social.msdn.microsoft.com/Forums/en-US/77bb69f0-590e-40f5-b5e9-714bf590e008/how-to-handle-encrypted-column?forum=linqtosql

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))

GUIDs in SQL Server

I have an ASP.NET application that generates GUIDs in the code-behind via C#. These GUIDs are generated via the following:
Guid id = Guid.NewGuid();
This GUID is later stored in a SQL Server 2008 database. I also have a stored procedure that will update that record. I would like to generate a GUID in the stored procedure that is in the same format as the one generated in ASP.NET.
Can somebody please tell me how to do this?
Thank you!
Use NEWID() method
DECLARE #ID uniqueidentifier
SET #ID = NEWID()
If this is for a clustered index (most often a primary key), I highly recommend NEWSEQUENTIALID() (SQL Server 2005 on up) since, NEWID() will create a fragmented index in that case, being truly random.
This will generate a GUID for you: SELECT NEWID()
Examples may be found here: http://msdn.microsoft.com/en-us/library/ms190348.aspx
My guess from the way that you have worded your question is that you are storing the GUIDs in a text (e.g. VARCHAR) field in the database - if this is the case then you should instead be using the uniqueidentifier type in which case you can use the NEWID() SQL function to generate a new GUID.
See C# guid and SQL uniqueidentifier for more detail on how to store GUIDs in an SQL Server database.
You could use NEWID().
But, there are issues with indexing guids generated like this. Instead, you should use the comb algorithm:
CAST(CAST(NEWID() AS BINARY(10)) +
CAST(GETDATE() AS BINARY(6)) AS UNIQUEIDENTIFIER)
Make sure you are storing these in a column of type UNIQUEIDENTIFIER and not converting them to NVARCHAR or anything of the sort.
You can use the NEWSEQUENTIALID for better indexing support, but the downside is that you can use this function only as a default value expression for your column.
You can use something like:
INSERT INTO MyTABLE (...) OUTPUT inserted.GUIDCOLUMN INTO #tableVar VALUES (...)
to access the newly generated sequential id.

Categories

Resources