dbo.VDO3_CRYPT_SP

Description

Properties

Name Value
ANSI Nulls ON

True

Quoted Identifier ON

True

Encrypted

False

Execute As
Assembly

Parameters

5
Name Data Type Length Description
@PasswordStr varchar -1
@SaltStr varchar -1
@IterationCount int 4
@Outputbytes int 4
@VDO3_PWD varchar -1

SQL Script

Copy
SET QUOTED_IDENTIFIER, ANSI_NULLS ON
GO

CREATE OR ALTER PROCEDURE dbo.VDO3_CRYPT_SP
  (
  @PasswordStr VARCHAR(MAX), -- HASHBYTES is limited, and HMAC concatenation limits this more, though 4000 is a guess
  @SaltStr VARCHAR(MAX), -- HASHBYTES is limited, and HMAC concatenation limits this more, though 4000 is a guess
  @IterationCount INT,
  @Outputbytes INT, -- For password hashing, should "naturally" be the digest size (or less) - more than the digest size allows the first <digest size> to remain identical, so someone cracking the PBKDF2'd passwords only needs to generate and check the first <digest size>
  @VDO3_PWD VARCHAR(MAX) OUTPUT
  )


AS
BEGIN


declare @Password varbinary(max)
select @Password = cast(@PasswordStr as varbinary(max))

declare @Salt varbinary(max)
select @Salt = cast(@SaltStr as varbinary(max))

-- WARNING - if you are using SQL 2012 or better, DO NOT USE Yourfn_CRYPT_PBKDF2_VARBINARY_SHA1 UNLESS YOU NEED BACKWARDS COMPATIBILITY!!!  The 64-bit math required by SHA-512 (and SHA-384) is proportionally faster on CPUs vs. GPU's as of 2013, which reduces a GPU based attacker's advantage.
-- SEE PKCS #5, RFC2898, as well as PBKDF2, i.e. http://tools.ietf.org/rfc/rfc2898.txt
-- WARNING - SQL is NOT a good language for this type of math; results are fairly slow, and are generally better off being implemented by another language.
-- This is a dedicated HMAC-SHA-512 version, with a moderate amount of performance tuning.


  DECLARE @NumDigestSizesRequiredToEncompassOutputbytes INT
  DECLARE @RemainderOutputbytesAfterNumDigestSizesMinusOne INT
  DECLARE @Working BINARY(64) -- digest size
  DECLARE @ThisIterationResult BINARY(64) -- digest size
  DECLARE @FirstIterationDefinedResult VARBINARY(4004) -- Salt size + INT size per HMAC definition
  DECLARE @output VARBINARY(8000)
  DECLARE @CurrentDigestSizeChunk INT
  DECLARE @CurrentIteration INT
  -- Start Inlined HMAC-SHA-512 variables
  DECLARE @ipadRFC2104 BIGINT
  DECLARE @opadRFC2104 BIGINT
  DECLARE @k_ipadRFC2104 BINARY(128) -- BLOCKSIZE in bytes per HMAC definition
  DECLARE @k_opadRFC2104 BINARY(128) -- BLOCKSIZE in bytes per HMAC definition
  --SQL fails to allow binary operations on two binary data types!!!  We use bigint and iterate 8 times for 512 bits = 64 byte blocksize for better performance.
  SET @ipadRFC2104 = CAST(0x3636363636363636 AS BIGINT)
  SET @opadRFC2104 = CAST(0x5C5C5C5C5C5C5C5C AS BIGINT)
  -- End Inlined HMAC-SHA-512 variables  

  SET @NumDigestSizesRequiredToEncompassOutputbytes = (@Outputbytes + 63)/64 -- number > 1 is digest size/digest size minus 1
  SET @RemainderOutputbytesAfterNumDigestSizesMinusOne = @Outputbytes - (@NumDigestSizesRequiredToEncompassOutputbytes - 1) * 64 -- the number in here that's > 1 is the digest size


  SET @output = 0x
  SET @CurrentDigestSizeChunk = 1

  WHILE @CurrentDigestSizeChunk <= @NumDigestSizesRequiredToEncompassOutputbytes
  BEGIN
    SET @FirstIterationDefinedResult = @Salt + CAST(@CurrentDigestSizeChunk AS VARBINARY(4))
    --SET @ThisIterationResult = YourDB.dbo.Yourfn_CRYPT_HMAC_SHA512(@Password,@FirstIterationDefinedResult)

    -- NOTE: Inlining HMAC-SHA-512 appears to improve performance by a factor of six or so.  Setting the HMAC as an Inlined Table Valued Function instead of a Scalar function would reduce this disparity, of course.
    -- START INLINED HMAC-SHA-512 for performance improvement
    -- B = BLOCKSIZE (64 bytes for MD5, SHA-224, SHA-256, and 128 bytes for SHA-384 and SHA-512, per RFC2104 and RFC4868)
    IF LEN(@Password) > 128 -- Applications that use keys longer than B bytes will first hash the key using H and then use the resultant L byte string as the actual key to HMAC 
      SET @Password = CAST(HASHBYTES('SHA2_512', @Password) AS BINARY (128))
    ELSE
      SET @Password = CAST(@Password AS BINARY (128)) -- append zeros to the end of K to create a B byte string

    -- Loop unrolled for definite performance benefit
    -- Must XOR BLOCKSIZE bytes
    SET @k_ipadRFC2104 = CONVERT(BINARY(8),(SUBSTRING(@Password, 1, 8) ^ @ipadRFC2104))
      + CONVERT(BINARY(8),(SUBSTRING(@Password, 9, 8) ^ @ipadRFC2104))
      + CONVERT(BINARY(8),(SUBSTRING(@Password, 17, 8) ^ @ipadRFC2104))
      + CONVERT(BINARY(8),(SUBSTRING(@Password, 25, 8) ^ @ipadRFC2104))
      + CONVERT(BINARY(8),(SUBSTRING(@Password, 33, 8) ^ @ipadRFC2104))
      + CONVERT(BINARY(8),(SUBSTRING(@Password, 41, 8) ^ @ipadRFC2104))
      + CONVERT(BINARY(8),(SUBSTRING(@Password, 49, 8) ^ @ipadRFC2104))
      + CONVERT(BINARY(8),(SUBSTRING(@Password, 57, 8) ^ @ipadRFC2104))
      + CONVERT(BINARY(8),(SUBSTRING(@Password, 65, 8) ^ @ipadRFC2104))
      + CONVERT(BINARY(8),(SUBSTRING(@Password, 73, 8) ^ @ipadRFC2104))
      + CONVERT(BINARY(8),(SUBSTRING(@Password, 81, 8) ^ @ipadRFC2104))
      + CONVERT(BINARY(8),(SUBSTRING(@Password, 89, 8) ^ @ipadRFC2104))
      + CONVERT(BINARY(8),(SUBSTRING(@Password, 97, 8) ^ @ipadRFC2104))
      + CONVERT(BINARY(8),(SUBSTRING(@Password, 105, 8) ^ @ipadRFC2104))
      + CONVERT(BINARY(8),(SUBSTRING(@Password, 113, 8) ^ @ipadRFC2104))
      + CONVERT(BINARY(8),(SUBSTRING(@Password, 121, 8) ^ @ipadRFC2104))

    -- Loop unrolled for definite performance benefit
    -- Must XOR BLOCKSIZE bytes
    SET @k_opadRFC2104 = CONVERT(BINARY(8),(SUBSTRING(@Password, 1, 8) ^ @opadRFC2104))
      + CONVERT(BINARY(8),(SUBSTRING(@Password, 9, 8) ^ @opadRFC2104))
      + CONVERT(BINARY(8),(SUBSTRING(@Password, 17, 8) ^ @opadRFC2104))
      + CONVERT(BINARY(8),(SUBSTRING(@Password, 25, 8) ^ @opadRFC2104))
      + CONVERT(BINARY(8),(SUBSTRING(@Password, 33, 8) ^ @opadRFC2104))
      + CONVERT(BINARY(8),(SUBSTRING(@Password, 41, 8) ^ @opadRFC2104))
      + CONVERT(BINARY(8),(SUBSTRING(@Password, 49, 8) ^ @opadRFC2104))
      + CONVERT(BINARY(8),(SUBSTRING(@Password, 57, 8) ^ @opadRFC2104))
      + CONVERT(BINARY(8),(SUBSTRING(@Password, 65, 8) ^ @opadRFC2104))
      + CONVERT(BINARY(8),(SUBSTRING(@Password, 73, 8) ^ @opadRFC2104))
      + CONVERT(BINARY(8),(SUBSTRING(@Password, 81, 8) ^ @opadRFC2104))
      + CONVERT(BINARY(8),(SUBSTRING(@Password, 89, 8) ^ @opadRFC2104))
      + CONVERT(BINARY(8),(SUBSTRING(@Password, 97, 8) ^ @opadRFC2104))
      + CONVERT(BINARY(8),(SUBSTRING(@Password, 105, 8) ^ @opadRFC2104))
      + CONVERT(BINARY(8),(SUBSTRING(@Password, 113, 8) ^ @opadRFC2104))
      + CONVERT(BINARY(8),(SUBSTRING(@Password, 121, 8) ^ @opadRFC2104))

    SET @ThisIterationResult = HASHBYTES('SHA2_512', @k_opadRFC2104 + HASHBYTES('SHA2_512', @k_ipadRFC2104 + @FirstIterationDefinedResult))
    -- END   INLINED HMAC-SHA-512 for performance improvement

    SET @Working = @ThisIterationResult

    SET @CurrentIteration = 1
    WHILE @CurrentIteration < @IterationCount
    BEGIN
      --SET @ThisIterationResult = YourDB.dbo.Yourfn_CRYPT_HMAC_SHA512(@Password,@ThisIterationResult)

      -- NOTE: Inlining HMAC-SHA-512 appears to improve performance by a factor of six or so.  Setting the HMAC as an Inlined Table Valued Function instead of a Scalar function would reduce this disparity, of course.
      -- START INLINED HMAC-SHA-512 for performance improvement
      -- B = BLOCKSIZE (64 bytes for MD5, SHA-224, SHA-256, and 128 bytes for SHA-384 and SHA-512, per RFC2104 and RFC4868)

      -- We've already hashed the password if we needed to!
      -- We've already generated @k_ipadRFC2104 and @k_opadRFC2104 both!

      SET @ThisIterationResult =  HASHBYTES('SHA2_512', @k_opadRFC2104 + HASHBYTES('SHA2_512', @k_ipadRFC2104 + @ThisIterationResult))
      -- END   INLINED HMAC-SHA-512 for performance improvement

      -- Loop unrolled for possible performance benefit
      -- Stupid conversion required because SQL Server can't do binary operations on two binary variables!!!
      -- Must XOR digest size bytes
      SET @Working = CONVERT(BINARY(8),(CONVERT(BIGINT,(SUBSTRING(@ThisIterationResult,1,8)))^SUBSTRING(@Working,1,8)))
        + CONVERT(BINARY(8),(CONVERT(BIGINT,(SUBSTRING(@ThisIterationResult,9,8)))^SUBSTRING(@Working,9,8)))
        + CONVERT(BINARY(8),(CONVERT(BIGINT,(SUBSTRING(@ThisIterationResult,17,8)))^SUBSTRING(@Working,17,8)))
        + CONVERT(BINARY(8),(CONVERT(BIGINT,(SUBSTRING(@ThisIterationResult,25,8)))^SUBSTRING(@Working,25,8)))
        + CONVERT(BINARY(8),(CONVERT(BIGINT,(SUBSTRING(@ThisIterationResult,33,8)))^SUBSTRING(@Working,33,8)))
        + CONVERT(BINARY(8),(CONVERT(BIGINT,(SUBSTRING(@ThisIterationResult,41,8)))^SUBSTRING(@Working,41,8)))
        + CONVERT(BINARY(8),(CONVERT(BIGINT,(SUBSTRING(@ThisIterationResult,49,8)))^SUBSTRING(@Working,49,8)))
        + CONVERT(BINARY(8),(CONVERT(BIGINT,(SUBSTRING(@ThisIterationResult,57,8)))^SUBSTRING(@Working,57,8)))

      SET @CurrentIteration += 1 -- SHA-512 is a SQL 2012 only function, so SQL 2008 only syntax doesn't limit compatibility any further.
    END -- WHILE @CurrentIteration rounds

    SELECT @output = @output +
      CASE
        WHEN @CurrentDigestSizeChunk = @NumDigestSizesRequiredToEncompassOutputbytes THEN CONVERT(BINARY(64),LEFT(@Working,@RemainderOutputbytesAfterNumDigestSizesMinusOne)) -- digest size in bytes
        ELSE CONVERT(BINARY(64),@Working) -- digest size in bytes
        END 
    SET @CurrentDigestSizeChunk += 1 -- SHA-512 is a SQL 2012 only function, so SQL 2008 only syntax doesn't limit compatibility any further.
  END

/*
  RETURN @output
  */


  SET @VDO3_PWD = CONVERT(varchar(max),@OUTPUT)

END

GO

Depends On

No items found