Using my previous function as a base I've come up the following:create function dbo.Pbkdf2 (    @password varbinary(8000)  , @salt varbinary(7996)  , @iterations int = 1000  , @derivedKeyLength int = 32)returns varbinary(max)asbegin;        declare @hmacLength int = 32;        declare @i int = 1;    declare @l int = (@derivedKeyLength + @hmacLength - 1) / @hmacLength;    declare @r int = @derivedKeyLength - (@l - 1) * @hmacLength;                declare @derivedKey varbinary(max) = Cast('' as varbinary(max));    declare @u varbinary(8000);    declare @uA binary(32);    declare @uB binary(32);            while(@i <= @l)    begin;        declare @j int = 1;        select @u = @salt + Cast(@i as binary(4));          select @uA = uA.[Hash]             , @uB = uA.[Hash]        from dbo.Hmac(@password, @u) as uA;        while @j < @iterations        begin;            select @uA = tA.[Hash] from dbo.Hmac(@password, @uA) as tA;            select @uB = tB.[Hash]            from (values(              -- unrolled loop to XOR uA and uB                Cast(Substring(@uA, 1, 8) ^ Cast(Substring(@uB, 1, 8)  as bigint) as binary(8))              + Cast(Substring(@uA, 9, 8) ^ Cast(Substring(@uB, 9, 8)  as bigint) as binary(8))              + Cast(Substring(@uA, 17, 8) ^ Cast(Substring(@uB, 17, 8)  as bigint) as binary(8))              + Cast(Substring(@uA, 25, 8) ^ Cast(Substring(@uB, 25, 8)  as bigint) as binary(8))            )) tB ([Hash]);            select @j = @j + 1;        end;        select @derivedKey = @derivedKey + Cast(case when @i = @l then Left(@uB, @r) else @uB end as varbinary(32));        select @i = @i + 1;    end;    return @derivedKey;end;I'd really like to replace the loops with something set-based so that I can turn this into an inline-TVF but just can't seem to wrap my head around it...
T-SQL Pbdfk2 (Rfc2898 SHA2_256) Implementation
sql;sql server;cryptography;t sql;stored procedure