在本机编译的过程中生成加密安全随机数
Generate cryptographic-secure random numbers within a natively-compiled procedure
我需要为哈希操作生成加盐值。
在数据库中生成这些盐值非常适合我的情况 - 在其他地方(例如客户端)生成这些盐值会复杂得多(并且 bug-prone/security 风险)
为了方便自己,我写了一些程序来生成各种类型的随机数。 (BIGINT
、INT
等)
显然,可以轻松修改这些过程以生成任意大小的随机字节块,但 BIGINT
是我现在的重点。
我 运行 遇到的问题是 CRYPT_GEN_RANDOM
只能在非本地环境中使用。
我有需要使用随机数的本机和非本机操作,它们都需要安全。
我现在的解决方法是在本机版本中使用 NEWID
(请参阅下面的代码),但众所周知这是不安全的,我想尽可能避免使用它。
有没有办法在本机程序中生成加密随机数?
--non-native, cryptographic
CREATE PROCEDURE [dbo].[RandomBigInt]
@result BIGINT OUTPUT
AS BEGIN
SET @result = CAST ( CRYPT_GEN_RANDOM ( 8 ) AS BIGINT ) ;
END
GO
--native, non-cryptographic
CREATE PROCEDURE [dbo].[NativeRandomBigInt]
@result BIGINT OUTPUT
WITH NATIVE_COMPILATION ,
SCHEMABINDING
AS BEGIN ATOMIC WITH ( TRANSACTION ISOLATION LEVEL = SNAPSHOT ,
LANGUAGE = N'English' )
SET @result = CAST ( CAST ( NEWID ( ) AS BINARY ( 8 ) ) AS BIGINT ) ;
END
GO
任何伪随机数都不是真正随机的——你显然知道……
一个想法可能是,将几乎随机(伪随机NEWID()
)与真正随机的东西结合起来(实际时间戳)。第一个不满足您的需求,第二个是 - 至少在某些数字上 - 可以预测。但这可能是一个解决方案:
DECLARE @dt DATETIME2(7)=SYSUTCDATETIME(); --9 Bytes in memory, the first byte (the precision) will be cut off later
DECLARE @guid UNIQUEIDENTIFIER=NEWID(); --pseudo random
--We can cast the time value to a 9-byte-binary, take the right-most 8 byte and treat it as a BIGINT
DECLARE @dtCasted BIGINT = CAST(RIGHT(CAST(@dt AS BINARY(9)),8) AS BINARY(8));
--And we take the first 8 byte of the GUID
DECLARE @guidCasted BIGINT = CAST(@guid AS BINARY(8));
--The combination is XORed and returned as a BIGINT
SELECT @dtCasted ^ @guidCasted
--这和单行一样:
SELECT CAST(CAST(RIGHT(CAST(SYSUTCDATETIME() AS BINARY(9)),8) AS BINARY(8)) AS BIGINT) ^ CAST(NEWID() AS BINARY(8));
我需要为哈希操作生成加盐值。
在数据库中生成这些盐值非常适合我的情况 - 在其他地方(例如客户端)生成这些盐值会复杂得多(并且 bug-prone/security 风险)
为了方便自己,我写了一些程序来生成各种类型的随机数。 (BIGINT
、INT
等)
显然,可以轻松修改这些过程以生成任意大小的随机字节块,但 BIGINT
是我现在的重点。
我 运行 遇到的问题是 CRYPT_GEN_RANDOM
只能在非本地环境中使用。
我有需要使用随机数的本机和非本机操作,它们都需要安全。
我现在的解决方法是在本机版本中使用 NEWID
(请参阅下面的代码),但众所周知这是不安全的,我想尽可能避免使用它。
有没有办法在本机程序中生成加密随机数?
--non-native, cryptographic
CREATE PROCEDURE [dbo].[RandomBigInt]
@result BIGINT OUTPUT
AS BEGIN
SET @result = CAST ( CRYPT_GEN_RANDOM ( 8 ) AS BIGINT ) ;
END
GO
--native, non-cryptographic
CREATE PROCEDURE [dbo].[NativeRandomBigInt]
@result BIGINT OUTPUT
WITH NATIVE_COMPILATION ,
SCHEMABINDING
AS BEGIN ATOMIC WITH ( TRANSACTION ISOLATION LEVEL = SNAPSHOT ,
LANGUAGE = N'English' )
SET @result = CAST ( CAST ( NEWID ( ) AS BINARY ( 8 ) ) AS BIGINT ) ;
END
GO
任何伪随机数都不是真正随机的——你显然知道……
一个想法可能是,将几乎随机(伪随机NEWID()
)与真正随机的东西结合起来(实际时间戳)。第一个不满足您的需求,第二个是 - 至少在某些数字上 - 可以预测。但这可能是一个解决方案:
DECLARE @dt DATETIME2(7)=SYSUTCDATETIME(); --9 Bytes in memory, the first byte (the precision) will be cut off later
DECLARE @guid UNIQUEIDENTIFIER=NEWID(); --pseudo random
--We can cast the time value to a 9-byte-binary, take the right-most 8 byte and treat it as a BIGINT
DECLARE @dtCasted BIGINT = CAST(RIGHT(CAST(@dt AS BINARY(9)),8) AS BINARY(8));
--And we take the first 8 byte of the GUID
DECLARE @guidCasted BIGINT = CAST(@guid AS BINARY(8));
--The combination is XORed and returned as a BIGINT
SELECT @dtCasted ^ @guidCasted
--这和单行一样:
SELECT CAST(CAST(RIGHT(CAST(SYSUTCDATETIME() AS BINARY(9)),8) AS BINARY(8)) AS BIGINT) ^ CAST(NEWID() AS BINARY(8));