Skip to content

Instantly share code, notes, and snippets.

@rmalayter
Last active October 11, 2023 07:55
Show Gist options
  • Star 10 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rmalayter/3130462 to your computer and use it in GitHub Desktop.
Save rmalayter/3130462 to your computer and use it in GitHub Desktop.
HMAC function in Microsoft T-SQL
CREATE FUNCTION dbo.HMAC (
@algo VARCHAR(20)
,@key VARBINARY(MAX)
,@data VARBINARY(MAX)
)
/* This function only takes VARBINARY parameters instead of VARCHAR
to prevent problems with implicit conversion from NVARCHAR to VARCHAR
which result in incorrect hashes for inputs including non-ASCII characters.
Always cast @key and @data parameters to VARBINARY when using this function.
Tested against HMAC vectors for MD5 and SHA1 from RFC 2202 */
/*
List of secure hash algorithms (parameter @algo) supported by MSSQL
version. This is what is passed to the HASHBYTES system function.
Omit insecure hash algorithms such as MD2 through MD5
2005-2008R2: SHA1
2012-2016: SHA1 | SHA2_256 | SHA2_512
*/
RETURNS VARBINARY(64)
AS
BEGIN
DECLARE @ipad BIGINT
DECLARE @opad BIGINT
DECLARE @i VARBINARY(64)
DECLARE @o VARBINARY(64)
DECLARE @pos INTEGER
--SQL 2005 only allows XOR operations on integer types, so use bigint and interate 8 times
SET @ipad = cast(0x3636363636363636 AS BIGINT) --constants from HMAC definition
SET @opad = cast(0x5C5C5C5C5C5C5C5C AS BIGINT)
IF len(@key) > 64 --if the key is grater than 512 bits we hash it first per HMAC definition
SET @key = cast(hashbytes(@algo, @key) AS BINARY (64))
ELSE
SET @key = cast(@key AS BINARY (64)) --otherwise pad it out to 512 bits with zeros
SET @pos = 1
SET @i = cast('' AS VARBINARY(64)) --initialize as empty binary value
WHILE @pos <= 57
BEGIN
SET @i = @i + cast((substring(@key, @pos, 8) ^ @ipad) AS VARBINARY(64))
SET @pos = @pos + 8
END
SET @pos = 1
SET @o = cast('' AS VARBINARY(64)) --initialize as empty binary value
WHILE @pos <= 57
BEGIN
SET @o = @o + cast((substring(@key, @pos, 8) ^ @opad) AS VARBINARY(64))
SET @pos = @pos + 8
END
RETURN hashbytes(@algo, @o + hashbytes(@algo, @i + @data))
END
GO
GRANT EXECUTE
ON dbo.HMAC
TO PUBLIC
GO
/*
Copyright © 2012 Ryan Malayter. All Rights Reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY Ryan Malayter "AS IS" AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
@rmalayter
Copy link
Author

It works correctly with a lot of hash, like SHA1, SHA2_256, MD5.
But with SHA2_512 I have a problem.
For example I send
SELECT dbo.HMAC ('SHA2_512', CAST('key' as VARBINARY(MAX)), CAST('mess' as VARBINARY(MAX)));
and have result
C2D19170351753D62345A60079F544AFF30C33E2AEF6B33C716814420DE3D3CE97B4E302C9203D7CDF07ACAD192328B88D16F361FA3CC4742ED19886DB6F15AB

But! If I use http://www.freeformatter.com/hmac-generator.html#ad-output
I get
abd1d3be0cc4a178ee43380f7f6d386f6aff97e769e88f756db81cda9c7af0fc706ba3632c134443b50b8ed77c267565b495e88fed41396dfdbe8a68aa3785cc

Something wrong with 'SHA2_512'.

Can you help to fix the mistake?

I use SQL Server 2012

@Brooho HMAC pads to the the "internal block size" of the hash function. SHA2_512 has an internal block size of1024 bits, not 512 as it is for the other hashes.

So I think the padding needs to be done to VARBINARY(128) instead of VARBINARY(64). You'd have to make a special-case for SHA2_512 with different-sized variables to be RFC-compliant for SHA2-512. Some loop constants would have to be adusted or made into CASE statments as well. I can't get to that any time soon, but if you send a pull request to the gist I can incorporate

@JSKuipers
Copy link

JSKuipers commented Dec 18, 2018

rewritten to HMAC-SHA512:

CREATE FUNCTION [dbo].[HMACSHA2_512] (
	@key VARBINARY(MAX),
	@data VARBINARY(MAX)
)
RETURNS VARBINARY(128)
AS
BEGIN
	DECLARE @ipad BIGINT;
	DECLARE @opad BIGINT;
	DECLARE @i VARBINARY(128);
	DECLARE @o VARBINARY(128);
	DECLARE @pos INTEGER;

	--SQL 2005 only allows XOR operations on integer types, so use bigint and interate 8 times
	SET @ipad = CAST(0x3636363636363636 AS BIGINT);
	SET @opad = CAST(0x5C5C5C5C5C5C5C5C AS BIGINT);

	IF LEN(@key) > 128
		SET @key = cast(hashbytes('SHA2_512', @key) AS BINARY (128))
	ELSE
		SET @key = cast(@key AS BINARY (128));

	SET @pos = 1;
	SET @i = cast('' AS VARBINARY(128));

	WHILE @pos <= 121
	BEGIN
		SET @i = @i + cast((substring(@key, @pos, 8) ^ @ipad) AS VARBINARY(128));
		SET @pos = @pos + 8;
	END;

	SET @pos = 1;
	SET @o = CAST('' AS VARBINARY(128));

	WHILE @pos <= 121
	BEGIN
		SET @o = @o + cast((substring(@key, @pos, 8) ^ @opad) AS VARBINARY(128));
		SET @pos = @pos + 8;
	END;

	RETURN hashbytes('SHA2_512', @o + hashbytes('SHA2_512', @i + @data));
END

@EJocys
Copy link

EJocys commented Jul 25, 2019

This is my take on it:

Updated: 2021-06-09 - Key fix suggestion by NReilingh.

HMAC Implementation for Microsoft SQL Server.

  • Security.HMAC - Implements HMAC algorithm. Supported and tested algorithms: MD2, MD4, MD5, SHA, SHA1, SHA2_256, SHA2_512.
  • Security.HashPassword - Returns base64 string which contains random salt and password hash inside. Use HMAC-SHA2_256/512.
  • Security.IsValidPassword - Returns 1 if base64 string and password match. Use HMAC-SHA2_256/512.

Source: https://github.com/JocysCom/ShellScripts/tree/master/Tester/Scripts/HMAC_for_SQL

Example:

-- Use Unicode, because ASCII doesn't work worldwide.
DECLARE @password nvarchar(max) = N'Password'
-- Get base64 string which contains random salt and password hash inside.
-- Limit security to 128-bit to make sure that result will fit into old password field.
DECLARE @base64 varchar(max) = [Security].[HashPassword](@password, 128)
-- Validate password against base64 string.
DECLARE @isValid bit = [Security].IsValidPassword(@password, @base64)
-- Print results.
PRINT '@password: ' + @password
PRINT '@base64:   ' + @base64
PRINT '@isValid:  ' + CAST(@isValid as varchar(1))

Prints Results:

@password: Password
@base64:   QJYy7JRIwEmyicMYUi3DhqD8yPfmBwzDI+2dk6VYcYw=
@isValid:  1

-- Create [Security] Schema.
CREATE SCHEMA [Security]
    AUTHORIZATION [dbo];

CREATE FUNCTION [Security].[HMAC] (
       @algorithm sysname,
       @key varbinary(max),
       @message varbinary(max)
)
RETURNS varbinary(max)
AS
BEGIN
	-- Author: Evaldas Jocys, https://www.jocys.com
	-- Created: 2019-07-25
	-- Updated: 2021-06-09 - Key fix suggestion by NReilingh.
	/*

	-- Use Unicode, because ASCII doesn't work worldwide.
	
	-- Example 1:
	DECLARE @key  varbinary(max) = CAST(N'Password' AS varbinary(max))
	DECLARE @message varbinary(max) = CAST(N'Message' AS varbinary(max))
	SELECT @key AS [Key], @message AS [Message]
	-- Return hash.
	SELECT [Security].HMAC('SHA2_256', @key, @message) AS [Hash]

	-- Example 2:
	DECLARE @key  varbinary(max) = 0x63727970746969
	DECLARE @message varbinary(max) = 0x68656c6c6f21
	SELECT @key AS [Key], @message AS [Message]
	-- Return hash.
	SELECT [Security].HMAC('SHA2_256', @key, @message) AS [Hash]

	*/
	-- Set correct block size for the @algorithm: MD2, MD4, MD5, SHA, SHA1, SHA2_256, SHA2_512.
	DECLARE @blockSize int = 64
	IF @algorithm IN ('MD2')
		SET @blockSize = 16
	IF @algorithm IN ('SHA2_512')
		SET @blockSize = 128
	-- If key is longer than block size then...
	IF LEN(@key) > @blockSize 
		-- hash key to make it block size.
		SET @key = CAST(HASHBYTES(@algorithm, @key) AS varbinary(max))
	-- If key is shorter than block size then...
	IF LEN(@key) < @blockSize 
		-- pad it with zeroes on the right.
		SET @key = SUBSTRING(CAST(@key AS binary(128)), 0, @blockSize);
	-- Create inner padding.
	DECLARE
		@i int = 1,
		-- Block-sized inner padding.
		@ipad bigint = CAST(0x3636363636363636 AS bigint),
		-- Inner padded key.
		@i_key_pad varbinary(max) = CAST('' AS varbinary(max))
	WHILE @i < @blockSize
	BEGIN
		SET @i_key_pad = @i_key_pad + CAST((SUBSTRING(@key, @i, 8) ^ @ipad) AS varbinary(max))
		SET @i = @i + 8
	END
	-- Create outer padding.
	DECLARE
		@o int = 1,
		-- Block-sized outer padding
		@opad bigint = CAST(0x5C5C5C5C5C5C5C5C AS bigint),
		-- Outer padded key.
		@o_key_pad varbinary(max) = CAST('' AS varbinary(max))
	WHILE @o < @blockSize
	BEGIN
		SET @o_key_pad = @o_key_pad + CAST((SUBSTRING(@key, @o, 8) ^ @opad) AS varbinary(max))
		SET @o = @o + 8
	END
	-- Return keyed hash.
	RETURN HASHBYTES(@algorithm, @o_key_pad + HASHBYTES(@algorithm, @i_key_pad + @message))
END

View required for Security_HashPassword function in order to generate random salt.

CREATE VIEW [Security].[HashPasswordNewID]
AS
SELECT NEWID() AS uniqueidentifier

CREATE FUNCTION [Security].[HashPassword] (
	@password nvarchar(max),
	@security int
)
RETURNS varchar(max)
AS
BEGIN
	-- Author: Evaldas Jocys, https://www.jocys.com
	-- Created: 2019-07-25
	/* Example:

	-- Note: @password is Unicode (nvarchar) type, because ASCII doesn't work worldwide.
	
	-- Base64 string which will be used to store salt and hash bytes.
	DECLARE @base64 nvarchar(max)

	-- 512-bit security:
	-- Return 128 bytes (64 salt bytes + 64 hash bytes) as base64 string, which will fit into a varchar(176) field.
	SET @base64 = [Security].HashPassword(N'Password', 512)
	-- Returns 1 if supplied plain password match salt and hash inside base64 string.
	SELECT [Security].IsValidPassword(N'Password', @base64) as [valid], @base64 as [base]

	-- 256-bit security (default):
	-- Return 64 bytes (32 salt bytes + 32 hash bytes) as base64 string, which will fit into a varchar(88) field.
	SET @base64 = [Security].HashPassword(N'Password', 256)
	-- Returns 1 if supplied plain password match salt and hash inside base64 string.
	SELECT [Security].IsValidPassword(N'Password', @base64) as [valid], @base64 as [base]

	-- 128-bit security:
	-- Return 32 bytes (16 salt bytes + 16 hash bytes) as base64 string, which will fit into a varchar(44) field.
	SET @base64 = [Security].HashPassword(N'Password', 128)
	-- Returns 1 if supplied plain password match salt and hash inside base64 string.
	SELECT [Security].IsValidPassword(N'Password', @base64) as [valid], @base64 as [base]

	*/
	
	IF @security IS NULL
		SET @security = 256
	DECLARE @size int = @security / 8
	DECLARE @algorithm sysname = CASE WHEN @security > 256 THEN 'SHA2_512' ELSE 'SHA2_256' END
	-- Convert string to bytes.
	DECLARE @password_data varbinary(max) = CAST(@password  AS varbinary(max))
	DECLARE @password_salt varbinary(max) = CAST('' as varbinary(max))
	-- Generate random salt.
	WHILE LEN(@password_salt) < @size
		SET @password_salt = @password_salt + CAST((SELECT * FROM [Security].HashPasswordNewID) AS varbinary(16))
	SET @password_salt = SUBSTRING(@password_salt, 1, @size);
	DECLARE @password_hash varbinary(max) = SUBSTRING([Security].HMAC(@algorithm, @password_salt, @password_data), 1, @size)
	-- Combine salt and hash and convert to HEX.
	DECLARE @salt_hash_bin varbinary(max) = @password_salt + @password_hash
	--DECLARE @salt_hash_hex varchar(max) = CONVERT(varchar(max), @salt_hash_bin, 2)
	-- Convert salt and hash to Base64 string.
	DECLARE @base64 varchar(max) = (SELECT @salt_hash_bin FOR XML PATH(''), BINARY BASE64)
	RETURN @base64
END

CREATE FUNCTION [Security].[IsValidPassword] (
	@password nvarchar(max),
	@base64 varchar(max)
)
RETURNS bit
AS
BEGIN
	-- Author: Evaldas Jocys, https://www.jocys.com
	-- Created: 2019-07-25
	/* Example:
	-- Use Unicode, because ASCII doesn't work worldwide.
	DECLARE @base64 nvarchar(max) = dbo.Security_HashPassword(N'Password', 128)
	SELECT dbo.Security_IsValidPassword(N'Password', @base64) as [valid], @base64 as [base]
	*/
	-- Convert base64 string to binary.
	DECLARE @salt_hash_bin varbinary(max) = CAST(N'' as xml).value('xs:base64Binary(sql:variable("@base64"))', 'varbinary(max)');
	-- Get size of salt and hash.
	DECLARE @size int = LEN(@salt_hash_bin) / 2
	DECLARE @algorithm sysname = CASE WHEN @size * 8  > 256 THEN 'SHA2_512' ELSE 'SHA2_256' END
	-- Salt and Hash size.
	DECLARE @password_data varbinary(max) = CAST(@password AS varbinary(max))
	DECLARE @salt varbinary(max) = SUBSTRING(@salt_hash_bin, 1, @size)
	DECLARE @hash varbinary(max) = SUBSTRING(@salt_hash_bin, 1+ @size, @size + @size)
	DECLARE @password_hash varbinary(max) = SUBSTRING([Security].HMAC(@algorithm, @salt, @password_data), 1, @size)
	-- If @base64 string, which contains salt and hash, match with supplied password then...
	IF @password_hash = @hash
		RETURN 1
	RETURN 0
END

@rmalayter
Copy link
Author

rmalayter commented Oct 14, 2019

@EJocys that is indeed a nice "abstracted" approach, however, I disagree on a few points:

  1. Support for anything but SHA2_256 and SHA2_512 should really be removed. You don't want to encourage the use of broken cryptography by developers (and SHA-1 and the older algorithms are most definitely broken).
  2. Password hashing should be very slow. You should be using >10000 iterations of HMAC-SHA256 (this is basically PBKDF2-HMAC-SHA256).
    The only way a single iteration of HMAC would be appropriate for password hashing is if you were passing in an actual secret key for the HMAC, and that secret key were stored only in a hardware security module (HSM) or another secure mechanism separate from your database and application code. I do have an implementation of PBKDF2-HMAC-SHA256 in T-SQL, but that code was written for my employer and can't be easily open sourced unfortunately.
    A an even better alternative than PBKDF2 is a memory-hard password-hashing function done at the application layer (or even on the client via JavaScript!) See Cryptographic Right Answers

@EJocys
Copy link

EJocys commented Oct 14, 2019

@rmalayter:

  1. Agree about the minimum of SHA2_256 for security, but other hashing algorithms can still be used for non-security purposes i.e file, image or other data hashing where speed is priority.
  2. Agree. Something for later to add. I guess it also depends on the number of authentications and how powerful server is. It can be offloaded onto users by forcing them to add 4 extra letters to the password instead :). Of course it will increase the chance of password ending up on the paper note :).

Note: When creating this solution I was trying to provide backwards compatibility option too i.e. ability to secure/hash passwords on a database when adding new columns or changing its schema in any way can't be easily done due to technical restrictions or limited developing resources. This is why optional "@security int" property is present on [Security_HashPassword] procedure. It allows to re-use old password column for the hash+salt storage and allows to mix secured and unsecured data during transition process (you can easily tell if column contains base64 string just by its fixed size).

@NReilingh
Copy link

@EJocys You may be interested to know that your implementation does not appear to be a correct implementation of the standard, at least for SHA2_256. Here is an example:

SELECT dbo.Security_HMAC('SHA2_256', 0x63727970746969, 0x68656c6c6f21);
-- Outputs
0xAFC84D55FD2C9E2E294C24188EA2015E6695E365B79D2071DB6D0A44959200D7

Equivalent demonstration in CyberChef and Cryptii, (as well as the other implementations in this thread) show an output of

0xd6cbb383c40418c408740af2727bf8c08231609a3827dba31538e0d11ab4b1d4

@NReilingh
Copy link

@EJocys Your "Padding with zeros on the right" is the problem. Casting to varbinary doesn't pad anything. Changing that line to this works for my test case:

  IF LEN(@key) < @blockSize
    SET @key = SUBSTRING(CAST(@key AS binary(128)), 0, @blockSize);

@EJocys
Copy link

EJocys commented Jun 9, 2021

@NReilingh:

Thank you. Excellent finding and fix. Tested to make sure that C# implementation returns same result as CyberChef and Cryptii.
Updated original code: https://github.com/JocysCom/ShellScripts/tree/master/Tester/Scripts/HMAC_for_SQL/Data/Functions
I will update Internet example with the Note.

Also added example inside HMAC.sql:

-- Example 1:
DECLARE @key  varbinary(max) = CAST(N'Password' AS varbinary(max))
DECLARE @message varbinary(max) = CAST(N'Message' AS varbinary(max))
SELECT @key AS [Key], @message AS [Message]
-- Return hash: 0xD28A366CDA742EB767AB56B7B11893EE73BA2CD54792D5ACF9189D54F36E60EE
SELECT [Security].HMAC('SHA2_256', @key, @message) AS [Hash]

-- Example 2:
DECLARE @key  varbinary(max) = 0x63727970746969
DECLARE @message varbinary(max) = 0x68656c6c6f21
SELECT @key AS [Key], @message AS [Message]
-- Return hash: 0xD6CBB383C40418C408740AF2727BF8C08231609A3827DBA31538E0D11AB4B1D4
SELECT [Security].HMAC('SHA2_256', @key, @message) AS [Hash]

C# Test Example:

var key = StringToByteArray("0x63727970746969");
var data = StringToByteArray("0x68656C6C6F21");
var algorithm = new System.Security.Cryptography.HMACSHA256();
algorithm.Key = key;
var hash = algorithm.ComputeHash(data);
Console.WriteLine("  Hash: {0}", string.Join("", hash.Select(x => x.ToString("X2"))));
public static byte[] StringToByteArray(string hex)
{
	if (hex.StartsWith("0x"))
		hex = hex.Substring(2);
	hex = hex.Replace(":", "").Replace("-", "");
	var chars = hex.Length;
	var bytes = new byte[chars / 2];
	for (int i = 0; i < chars; i += 2)
		bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16);
	return bytes;
}

@bet365mj
Copy link

bet365mj commented Aug 20, 2021

Hi,

Why Function is returning different result when doing a cross check with Online tool "HMAC-SHA256",

here what i am running

DECLARE @key  varbinary(max) = CAST(N'd666f18176df4e29a64c7e40519a1751' AS varbinary(max))
DECLARE @message varbinary(max) = CAST(N'1e0950435dc94529cffdb67b1b679f3320082021' AS varbinary(max))
SELECT @key AS [Key], @message AS [Message]
-- Return hash.
SELECT [dbo].HMAC('SHA2_256', @key, @message) AS [Hash]

Return Hash Value: 0xD4367202498312F068300882B0EFDA582137A9DB6D98ADB14E2B6BA2DCE60A09

BUT online tool Return base64: CgM3WVX9eTHtJggajqlBoeJuEHLGEUJYidHgKTxuUn0=

I know i must be doing something wrong but can you tell me where i am making a mistake?

Thanks

@NReilingh
Copy link

@bet365mj You're either misusing your online tool or you're misunderstanding your CASTs.

Here is what you are calculating with SQL Server: CyberChef Example

The inputs shown are what is output by your first SELECT statement.

If you want SQL Server to calculate ac9454b759103d77f8ad0ba7d43a3bd5c006f77e297a42c7e31d590f3bed13ad, as shown here, then you should not be converting your key and message from SQL Server unicode text -- use the literal binary values as follows:

DECLARE @key  varbinary(max) = 0xd666f18176df4e29a64c7e40519a1751;
DECLARE @message varbinary(max) = 0x1e0950435dc94529cffdb67b1b679f3320082021;
SELECT @key AS [Key], @message AS [Message]
-- Return hash.
SELECT [dbo].HMAC('SHA2_256', @key, @message) AS [Hash]
-- Returns 0xAC9454B759103D77F8AD0BA7D43A3BD5C006F77E297A42C7E31D590F3BED13AD

However, the output of your online tool (converted from Base64) is 0a03375955fd7931ed26081a8ea941a1e26e1072c611425889d1e0293c6e527d. This is what you get when converting your key and message from ASCII or UTF-8, which suggests that your online tool is expecting text input and not a hexadecimal representation of binary. In other words, your key is being interpreted as binary literal 0x6436363666313831373664663465323961363463376534303531396131373531, and the message goes through a similar conversion from ASCII/UTF-8, shown here.

To replicate this in SQL Server, you need the following:

DECLARE @key  varbinary(max) = CAST('d666f18176df4e29a64c7e40519a1751' AS varbinary(max))
DECLARE @message varbinary(max) = CAST('1e0950435dc94529cffdb67b1b679f3320082021' AS varbinary(max))
SELECT @key AS [Key], @message AS [Message]
-- Return hash.
SELECT [dbo].HMAC('SHA2_256', @key, @message) AS [Hash]
-- Returns 0x0A03375955FD7931ED26081A8EA941A1E26E1072C611425889D1E0293C6E527D

@bet365mj
Copy link

@NReilingh
Thanks for the prompt rely, I was using HMAC-SHA256 when encoding key.
I am calling my API server from SQL Server and server needs HMAC-SHA256 coded key. When i came across your script, i thought it is returning value in base64 but in fact it is returning in plain text.
`
DECLARE @b64 varbinary(max)
DECLARE @key varbinary(max) = CAST('d666f18176df4e29a64c7e40519a1751' AS varbinary(max))
DECLARE @message varbinary(max) = CAST('1e0950435dc94529cffdb67b1b679f3320082021' AS varbinary(max))

-- Return hash.
SELECT [dbo].HMAC('SHA2_256', @key, @message)
-- Returns 0a03375955fd7931ed26081a8ea941a1e26e1072c611425889d1e0293c6e527d

--Convert to base64
SELECT @b64 = [dbo].HMAC('SHA2_256', @key, @message)
SELECT cast(N'' as xml).value('xs:base64Binary(sql:variable("@b64"))', 'varchar(128)');

--Return: CgM3WVX9eTHtJggajqlBoeJuEHLGEUJYidHgKTxuUn0= "This is what i wanted"

`
Thanks again
MJ

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment