【问题标题】:Generate cryptographic-secure random numbers within a natively-compiled procedure在本机编译的过程中生成加密安全随机数
【发布时间】:2019-10-10 20:25:12
【问题描述】:

我需要为哈希运算生成盐值。

在数据库中生成这些盐值非常适合我的情况 - 在其他地方(例如客户端)生成这些盐值会更加复杂(并且容易出错/安全风险)

为了方便我自己,我编写了一些程序来生成各种类型的随机数。 (BIGINTINT等)

显然,可以轻松修改这些过程以生成任意大小的随机字节块,但 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

【问题讨论】:

  • 您能否详细说明all need to be secure 的含义。
  • @Alex 我有多个 T-SQL 操作,一些是本机的,一些是非本机的,每个都有多组过程,需要生成随机数,并且它们都需要随机数来保证密码安全。常规的伪随机数(例如NEWID)会导致安全问题(例如在对哈希进行加盐时)。
  • 除非您是密码学专业人士,否则您想出的任何东西都不会是密码学安全的。鉴于您在这里问这个问题,那么您不是密码学专业人士。很抱歉给您带来坏消息。你能做的最好的可能是@Shnugo 建议的那样,尽可能多地组合不同的伪随机源。
  • @rossum 编写我自己的存储过程来实现 AES/SHA3 操作的原始加密算法算不算是加密专家?半职业选手?大声笑这不是我的第一个牛仔竞技表演,如果我必须编写自己的自定义本地编译的加密 rng,我可以 - 我真的不想(实际上我认为我已经在某处写了大部分代码,我应该搜索我的图书馆)。 (如果可以避免的话,滚动自己的加密货币通常也是一种不好的做法——我相信你知道。)
  • 我对 MS 产品一无所知,但NEWID 似乎是一个 GUID。从密码学的角度来看,使用如此确定的东西似乎很糟糕(给定来自同一台机器的时间和盐值,只有大约 30 位的随机状态)。我会尝试拥有 128 或 256 位的随机性,因此这永远不是系统中的“最薄弱环节”。我有类似的经历,我会称自己为业余爱好者,我想说专业人士是设计加密系统并让他们经受住几年坚决攻击的人

标签: sql sql-server tsql random sql-server-2017


【解决方案1】:

任何伪随机数都不是真正随机的——你显然知道......

一个想法可能是将几乎随机(伪随机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));

【讨论】:

  • 看起来NEWIDNEWID ^ timestamp 一样好。根据RFC4122,(NEWID 遵守)生成的uniqueidentifier 已经嵌入了当前时间戳。因此,事后手动将时间戳异或到值中实际上可能没有任何用处,只会增加徒劳的复杂性。看起来我可能不得不从内存优化表中提取相关数据以保持更高的级别或安全性。 (除非有另一个可用的良好熵来源,我可以异或……这可能很有趣。)
  • @Giffyguy 好的,我从来不用处理如此高级别的安全要求。 NEWID() 对我来说已经足够了。所以我没有阅读细节......相当随机的东西可能是一个简单动作所消耗的时间。这在很大程度上取决于机器当前的职责。 DATETIME2 下降到 100 ns...
  • time consumed by a simple action 这是个好主意。我会调查的。
猜你喜欢
  • 1970-01-01
  • 2015-09-09
  • 1970-01-01
  • 1970-01-01
  • 2021-06-18
  • 1970-01-01
  • 2016-02-08
  • 2016-06-23
  • 1970-01-01
相关资源
最近更新 更多