DECRYPTBYASYMKEY() Not Returning Expected Value - sql-server

I'm playing around with Asymmetric Encryption and Decryption, but I don't understand the results I'm getting when I try to decrypt values.
Why does this:
CREATE ASYMMETRIC KEY myasymkey
WITH ALGORITHM = RSA_2048
ENCRYPTION BY PASSWORD = '123pass!';
GO
SELECT DECRYPTBYASYMKEY(ASYMKEY_ID('myasymkey'),
EncryptByAsymKey(AsymKey_ID('myasymkey'), 'Greg'),
N'123pass!');
GO
Produce 0x47726567? I was expecting it to be Greg.
UPDATE: I'm dumb, 0x47726567 is Greg when converted from varbinary.

It's right - when you encrypt something it's treated as a byte array and is returned as such. 0x47 is G, 72 is r etc.
If you examine the documentation for DecryptByAsmKey you'll notice the return type is varbinary with a maximum size of 8,000 bytes. You'll also notice the convert in the example.
So if you are encrypting and decrypting strings you must convert like so
SELECT CONVERT(varchar(max),DECRYPTBYASYMKEY(ASYMKEY_ID('myasymkey'),
EncryptByAsymKey(AsymKey_ID('myasymkey'),
'Greg'),
N'123pass!'));
Also note you need to make sure you're converting to varchar(max) or nvarchar(max) depending on your input. If you tried
SELECT CONVERT(nvarchar(max),DECRYPTBYASYMKEY(ASYMKEY_ID('myasymkey'),
EncryptByAsymKey(AsymKey_ID('myasymkey'),
'Greg'),
N'123pass!'));
it would be wrong, as your input of 'Greg' is a varchar.

I think 0x47726567 is Greg (in ASCII).

All the encryption functions return varbinary values. You will have to cast the result as varchar.

Related

Why does ISNUMERIC() state a Zip Code, which is a varchar data type, as numeric in SQL server?

From my understanding, and I am probably wrong here, but doesn't the ISNUMERIC() return a 1 if whatever we are looking at is a numeric data type? And since most zip codes are saved as varchar data types, shouldn't it then return a 0? I looked up the documentation and that's what it says there to me, what am I missing here? I get zip codes are numbers, but because they are saved as a string shouldn't that make a difference? Thanks in advance.
ISNUMERIC() is specifically to look at strings, not at things already stored as numbers.
However, I don't recommend using it. For instance, '3.1e5' is considered numeric.
Instead, use try_convert():
try_convert(int, zip)
This returns NULL if the column cannot be converted.

Encrypt And Decrypt Hash sha256 in Postgresql

I am trying to hash a string in postgresql using sha256 as follow:
select digest('This is a test','sha256');
this returns below hashed value:
\xc7be1ed902fb8dd4d48997c6452f5d7e509fbcdbe2808b16bcf4edce4c07d14e
Now i want to retrieve my initial string using this hashed value but unable to find anything in the postgres docs regarding it, Any help regarding it will be appreciable.
There is a difference between hashing and encryption:
an encrypted value can be descrypted to get the original back, so encryption is loss-free and two different clear text values will always result in different encrypted values
a hash cannot be decrypted, because information is lost; different values can result in the same hash, although it is desirable that these "collisions" do not happen too often
Hashing is irreversible, while encryption is reversible.
Now digest is a hashing function:
digest(data text, type text) returns bytea
digest(data bytea, type text) returns bytea
Computes a binary hash of the given data.
So you won't be able to recover the original string.
You can use pgcrypto extension in Postgresql to save data after encryption.
For insertion,
INSERT INTO tablename (columnname1, columnname2) VALUES (PGP_SYM_ENCRYPT('value1', 'aes_key'), PGP_SYM_ENCRYPT('value2', 'aes_key'));
For fetching,
SELECT PGP_SYM_DECRYPT(columnname1::bytea, 'aes_key') as columnname1, PGP_SYM_DECRYPT(columnname2::bytea, 'aes_key') as columnname2 from tablename;

Error converting data type nvarchar to real

I need to subtract two nvarchar values and store the result in another column. I understand that first I need to convert nvarchar to numeric values, but I always get this error
Error converting data type nvarchar to real
Just to mention in varchar values are stored only numeric values but I can't seem to get this conversion right.
This looks like a SQL Server error. If so, use try_convert():
select try_convert(real, string_col)
This returns NULL instead of an error if there are conversion issues.
You can find the offending values using:
select string_col
from t
where try_convert(real, string_col) is null and
string_col is not null;
use a case statement. It should be something like (t-sql pseudo code inside a SELECT)
case when IsNumeric(column1) AND IsNumeric(column2)
then cast(column1 as decimal) - cast(column2 as decimal)
else NULL end as column3
This is a classical example of why you shouldn't mix types (nvarchar and decimal in this case), there are all sorts of shananigans - like ('abc' - 5) or (NULL - NULL) or ('five' - '3 '). If this works, it might be a good idea to look at the "NULL" results, as this might give you valuable insights as to what kind of garbage is being collected in your system.
You said that...
Just to mention in varchar values are stored only numeric values but I
can't seem to get this conversion right.
If that is absolutely true, then there's a very high probability that there are 1 or 2 trailing control characters (Tab, Carriage Return, Line Feed, whatever) in the items causing the errors.
Try converting the NVARCHAR values to the MONEY datatype first. It won't work for leading control characters but it will for trailing control characters. Obvioussly your original original value doesn't haven more than 4 decimal places, of course.

cast to NVARCHAR(MAX) causes "chinese"/UTF encoded characters

I am using code like this in my SELECT statement:
CAST(HASHBYTES(N'SHA1', Bla) AS NVARCHAR(MAX)) AS hashed_bla
and end-up with "chinese"/UTF encoded characters in the ssms grid but also in upstream apps. Is there a way to change this? Does this have to do with the collation? Thanks!
What you have is working as expected. Take the following example:
SELECT HASHBYTES('SHA1','B8187F0D-5DBA-4D43-95FC-CD5A009DB98C');
This returns the varbinary value 0xA04B9CB18A2DC4BC08B83FCCE48A0AF1A1390756. You are then converting that value to an nvarchar, so get a result like N'䮠놜ⶊ별레찿諤㦡嘇' (on my collation). For an varbinary each 4 characters represents a single character. So, for the above A04B is the first character (which is N'䮠').
It appears what you are after is an varchar representing a varbinary value (you don't need an nvarchar here, as there will be no unicode characters). To do so, you need to use CONVERT and a style code. For the example I gave above that would be:
SELECT CONVERT(varchar(100),HASHBYTES('SHA1','B8187F0D-5DBA-4D43-95FC-CD5A009DB98C'),1);
Which returns the varchar value '0xA04B9CB18A2DC4BC08B83FCCE48A0AF1A1390756'. If you don't want the '0x' at the start, use style code 2, rather than 1.

SHA256 base 64 hash generation in SQL Server

I need to generate a SHA256 base 64 hash from a table in SQL server but I can't find that algorithm in the list HASHBYTES arguments.
Is there a way to generate it directly in SQL Server?
Duplicate disclamer:
My question is not duplicate of SHA256 in T-sql stored procedure as I am looking for the SHA256 base 64 version of the algorithm which is not listed in the page.
Numeric Example
I have this query result in SQL Server
Start date,End date,POD,Amount,Currency
2016-01-01,2016-12-31,1234567890,12000,EUR
this give me the following string (using concatenate function)
2016-01-012016-12-31123456789012000EUR
whit this convertion tool I get the following hash
GMRzFNmm90KLVtO1kwTf7EcSeImq+96QTHgnWFFmZ0U
that I need to send to a customer.
First, the generator link you provided outputs the base64 representation in not exactly correct format. Namely, it omits the padding sequence. Though theoretically optional, padding is mandatory in MS SQL Server (tested on 2012 and 2016 versions).
With this in mind, the following code gives you what you need:
declare #s varchar(max), #hb varbinary(128), #h64 varchar(128);
select #s = '2016-01-012016-12-31123456789012000EUR';
set #hb = hashbytes('sha2_256', #s);
set #h64 = cast(N'' as xml).value('xs:base64Binary(sql:variable("#hb"))', 'varchar(128)');
select #hb as [BinaryHash], #h64 as [64Hash];
Apart from the aforementioned padding, there is another caveat for you to look for. Make sure that the input string is always of the same type, that is, either always varchar or always nvarchar. If some of your hashes will be calculated from ASCII strings and some from UTF-16, results will be completely different. Depending on which languages are used in your system, it might make sense to always convert the plain text to nvarchar before hashing.

Resources