CONVERT(NVARCHAR(100), HASHBYTES(N'SHA1', #PasswordWithSalt ),2) equivalent in c# - c#

I'm trying to move authentication from the stored procedure to EF. The SQL itself is returning 2 results. How should I validate them?
The value is to be checked against the value stored in the table
ECC2065575DCBF977CD923996C598C3DC481404E
SQL syntax:
Declare #Password AS NVARCHAR(256) = 'Quest_2016'
DECLARE #PasswordSalt AS NVARCHAR(5) = 'LCY''n'
DECLARE #PasswordWithSalt AS NVARCHAR(261) = #Password + #PasswordSalt
print #PasswordWithSalt
result:1 Quest_2016LCY'n
print HASHBYTES(N'SHA1', #PasswordWithSalt )
result 2: 0xECC2065575DCBF977CD923996C598C3DC481404E-----
print HASHBYTES(N'SHA1', 'Quest_2016LCY''n')
result 3: 0x5E85AB2ED11CDB696BC0544131D7C8571F4F8FA8-----
Also just what how this can be implemented in C#
sql hashbytes

The problem with those two queries is that the string values are the same but the bytes are not.
The first query
print HASHBYTES(N'SHA1', #PasswordWithSalt )
uses unicode encoding to get the bytes so every character is 2 bytes (0x510075006500730074005F0032003000310036004C004300590027006E00).
The second query
print HASHBYTES(N'SHA1', 'Quest_2016LCY''n')
uses ASCII so that every character is one byte.
To have the same result in the second example prefix the String with N'. It will tell SQL server that this is a unicode string
print HASHBYTES(N'SHA1', N'Quest_2016LCY''n')
produces the hash 0xECC2065575DCBF977CD923996C598C3DC481404E
In C# you can also use SHA1 to get the hash of the string and here also you need to be specific about the byte encoding
byte[] data = Encoding.Unicode.GetBytes(#"Quest_2016LCY'n");
byte[] hash = SHA1.Create().ComputeHash(data);
Console.Write(hash.Select(x=>x.ToString("X2")).Aggregate((x,y)=>x+y));
prints ECC2065575DCBF977CD923996C598C3DC481404E but if you change Encoding.Unicode to Encoding.ASCII it gives the 5E85AB2ED11CDB696BC0544131D7C8571F4F8FA8.

Related

Dapper trimming string result even if less than 4000 chars [duplicate]

DECLARE #result NVARCHAR(max);
SET #result = (SELECT * FROM table
FOR JSON AUTO, ROOT('Data'))
SELECT #result;
This returns a json string of ~43000 characters, with some results truncated.
SET #result = (SELECT * FROM table
FOR JSON AUTO, ROOT('Data'))
This returns a json string of ~2000 characters. Is there any way to prevent any truncation? Even when dealing with some bigdata and the string is millions and millions of characters?
I didn't find and 'official' answer, but it seems that this is an error with the new 'FOR JSON' statement which is splitting the result in lines 2033 characters long.
As recommended here the best option so far is to iterate through the results concatenating the returned rows:
string result = "";
while (reader.Read())
{
result += Convert.ToString(reader[0]);
}
BTW, it seems that the latest versions of SSMS are already applying some kind of workaround like this to present the result in a single row.
I was able to get the full, non-truncated string by using print instead of select in SQL Server 2017 (version 14.0.2027):
DECLARE #result NVARCHAR(max);
SET #result = (SELECT * FROM table
FOR JSON AUTO, ROOT('Data'))
PRINT #result;
Another option would be to download and use Azure Data Studio which I think is a multi-platform re-write of SSMS (similar to how Visual Studio was re-written as VS Code). It seems to spit out the entire, non-truncated json string as expected out of the box!
This will also work if you insert into a temp table - not presenting does not apply the truncate of SSMS.
Might be usefull if you need to calculate several values.
declare #json table (j nvarchar(max));
insert into #json select * from(select* from Table where Criteria1 for json auto)a(j)
insert into #json select * from(select* from Table where Criteria2 for json auto)a(j)
select * from #json
I know this is an old thread but I have had success with this issue by sending the result to an XML variable. The advantage of using an XML variable is that the size is not stated as character length but by size of the string in memory, which can be changed in the options. Therefore Brad C's response would now look like...
DECLARE #result XML
SET #result = (SELECT * FROM table
FOR JSON AUTO, ROOT('Data'))
SELECT #result
or...
PRINT #result;
Here is the answer to JSON truncation:
SQL divides the JSON result into chunks 2k in size (at least my SQL 2016 installation does), one chunk in the first column of each row in the result set. To get the entire result, your client code has to loop through the result set and concatenate the first column of each record. When you've gotten to the end of the rows, voila, your entire JSON result is retrieved, uncut.
When I first encountered the truncation problem I was baffled, and wrote off FOR JSON for several years as an unserious feature suited only to the smallest of datasets. I learned that I need to read the entire recordset only from the FOR XML documentation, and never actually saw it mentioned in the FOR JSON docs.
The easiest workaround to avoid the truncation is to wrap the query in another select:
select (
<your query> FOR JSON PATH [or FOR JSON AUTO]
) as json
We've seen similar issues in SSMS, without using a variable SSMS truncates at 2033.
With a variable the query actually works OK when you use an nvarcahr(max) variable, but it truncates the output in the query results view at 43697.
A possible solution I've tested is outputting Query results to a file, using BCP:
bcp "DECLARE #result NVARCHAR(max); SET #result = (SELECT * FROM table FOR JSON AUTO, ROOT('Data')); SELECT #result as Result;" queryout "D:\tmp\exportOutput.txt" -S SQL_SERVER_NAME -T -w
See BCP docs for specifying server name\instance and authentication options
It's difficult to determine exactly what the problem you're having without posting the data, but I had a similar problem when I was attempting to export a query in JSON format. The solution that worked for me was to go to Query/Query Options/Results/Text/Set "Maximum number of characters displayed in each column:" to 8192 (max value AFAIK).
This probably won't help much with your first query, but that potentially could be broken into smaller queries and executed successfully. I would anticipate that you could effectively run your second query after changing that setting.
If your datalength is less than 65535 then you should use the suggestion of #dfundako who commented in the first post:
Try going to Tools, Options, Query Results, SQL Server, Results to Grid, and set Non-XML data to the max amount (I think 65535)
In my case the datalength was 21k characters so after exporting to grid I copied the value and it was fine, not truncated. Still it doesn't solve the the issue for those with bigger amount of data.
Try Visual Studio Code with Microsoft SQL extension. I got 6800 characters of JSON without truncation. It seems SSMS truncates results.

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

How can I pass sp parameter with N prefix

I want to pass a parameter to sp with N prefix to solve an issue with foreign languages characters recognized as ???, I can't put N#test, directly, tried different ways without luck.
I have aspx.cs code file where I call to an sp, I want to do something like the following:
DECLARE #test NVARCHAR = 'N"★ "'
create table test (abc nvarchar)
insert into test values (#test)
select * from test
the code above is just an example, I will pass value to the parameter from .NET, How can I do it?
You don't need N prefix. You can specify parameter type as SqlDbType.NVarChar along with size. .Net will take care of preserving text encoding.
var foo = new SqlParameter("#test ", SqlDbType.NVarChar, 30)
N prefix means that your string is in UNICODE.
When you declare your variable as NVARCHAR it is already UNICODE.
So you don't need this N lineral at the begin of your variable.

Insert Unicode characters through a SQL Server stored procedure

I have a code like below which calls to a SQL Server stored procedure
First name will be passed a value like 电子邮箱
sCmd.Parameters.Add("#FName", SqlDbType.NVarChar);
sCmd.Parameters.Add("#LName", SqlDbType.NVarChar);
sCmd.Parameters["#FName"].Value = firstname;
sCmd.Parameters["#LName"].Value = lastname;
In stored procedure:
#FName nvarchar(200),
#LName nvarchar(200)
INSERT INTO [dbo].[testunicode]
([col1]
,[col2])
VALUES
(#FName
,#LName);
But data is inserted as ???? even the table columns are NVarchar(max);
I tried with adding 'N' before passing to stored procedure, and also the below. But still the same. What is the best way of doing so?
Encoding tc = Encoding.GetEncoding("BIG5");
byte[] bytes = tc.GetBytes(firstname);
firstname = Encoding.Unicode.GetString(bytes)
I tried with adding 'N' before passing to Sp
no need because the .NET String supports Unicode and it will take care of Unicode. If you see the request that is passed on to the database you will notice that N' will be affixed automatically.
What is the best way of doing so.
You are doing it right. No need for passing in anything else.
But data is inserted as ????
Check the datatype in your table. Is it really NVarChar?

MSQL Query Get the Int value of a Hex value of an Integer

Background
Just to give you come context I have included a little background as to why I'm trying to do this:
I have a table 'cp' which has an [id] field which is the identifier for each registration I have come realize that this is to be moved from a deployed solution to a cloud based as a result multiple accounts will be accessing the same objects and it would be best if they all start at 1 so rather than use the id field I have created an int field called label which will be used in conjunction with the account id to find the unique record per account.
field | type
________________________
id | int
label | int
account_id | int
When the registrations are printed out on the screen I want them to be displayed as a 5 digit HEX number and I can simply do the following in the c# code
value.ToString("X")
However My problem exists with the existing entries int he database before I added the new label field.
I have found several questions with a similar but do not answer my question
Converting a paragraph to hex notatation, then back to string
Converting a String to HEX in SQL
Convert integer to hex and hex to integer
The Problem
i have the fields with ids (1,2,3,----,11,12,13,---etc) values 1-9 can simply be copied over as the value.ToString("X") will simply do nothing with those values however if I simply copied value 11 would return "B" which correctly is the HEX value of 11 however I want it to return "11" so I need an SQL script which will convert 11 => 17 (which is the hex value of 0x11) so that when the application reads it it will output the value 11 to the screen.
This is only to occur once to convert the exiting id's which is why I'm wanting an SQL script to do it all in one batch rather than build it into the application.
What I would Like would be something like below so that it assumes the value in would be a hex value and convert it back to an Int.
SELECT CONVERT(INT, '0x' + id) FROM cp;
I can get the correct effect in C# by doing the following
int.Parse(value.ToString(),System.Globalization.NumberStyles.HexNumber).ToString()
UPDATE: I have found the solution to this problem for my use-case but some confusion has been raised that I am going to be doing all of my conversion in the database, I assume by the SELECT statement above. To clarify that this is a one-time event to convert existing records. Note the below statement does not work but stackoverflow will not let me edit the original statement as the change is less than 15 characters.
UPDATE [dbname].[dbo].[cp] set [Label] = CONVERT(INT, '0x' + id);
Found the Answer, it's not pretty but it solves my problem so I thought I would share it with you. If anyone has a simpler solution that would be great but in the mean time here we go.
Create a MSQL Function
CREATE FUNCTION ConvertFromBase
(
#value AS VARCHAR(MAX),
#base AS BIGINT
) RETURNS BIGINT AS BEGIN
-- just some variables
DECLARE #characters CHAR(36),
#result BIGINT,
#index SMALLINT;
-- initialize our charater set, our result, and the index
SELECT #characters = '0123456789abcdefghijklmnopqrstuvwxyz',
#result = 0,
#index = 0;
-- make sure we can make the base conversion. there can't
-- be a base 1, but you could support greater than base 36
-- if you add characters to the #charater string
IF #base < 2 OR #base > 36 RETURN NULL;
-- while we have characters to convert, convert them and
-- prepend them to the result. we start on the far right
-- and move to the left until we run out of digits. the
-- conversion is the standard (base ^ index) * digit
WHILE #index < LEN(#value)
SELECT #result = #result + POWER(#base, #index) *
(CHARINDEX
(SUBSTRING(#value, LEN(#value) - #index, 1)
, #characters) - 1
),
#index = #index + 1;
-- return the result
RETURN #result;
END
Then simply execute the following query
UPDATE [cp] SET label = dbo.ConvertFromBase(id,16);
This solution was discovered in http://dpatrickcaldwell.blogspot.com/2009/05/converting-hexadecimal-or-binary-to.html
You should NOT be doing your number formatting in SQL. Let the ints come out of the database as ints, and format them in your presentation layer. You completely haven't mentioned what that presentation layer is, so it's impossible to say more, but if you do this, you're DOOMED when your boss comes over and says that some users want to see the hexadecimal, and some want to see base-10.

Categories

Resources