Генерация криптографически безопасных случайных чисел в изначально скомпилированной процедуре - PullRequest
0 голосов
/ 10 октября 2019

Мне нужно сгенерировать значения соли для операции хеширования.

Генерация этих солей в базе данных идеально подходит для моей ситуации - было бы гораздо сложнее (и подвержено ошибкам / угрозе безопасности) генерировать этизначения соли в другом месте (например, на стороне клиента)

Чтобы упростить для себя задачу, я написал несколько процедур для генерации случайных чисел различных типов. (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

1 Ответ

1 голос
/ 11 октября 2019

Любое псевдослучайное число на самом деле не случайно - как вы, очевидно, знаете ...

Одна идея может состоять в том, чтобы объединить что-то почти случайно (псевдослучайный 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));
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...