私は現在guid NEWID()
を使用していますが、暗号的に安全でないことがわかります。SQL Serverで暗号で安全な番号を生成するにはどうすればよいですか?
SQL Serverで暗号で安全な番号を生成する方法はありますか?
私は現在guid NEWID()
を使用していますが、暗号的に安全でないことがわかります。SQL Serverで暗号で安全な番号を生成するにはどうすればよいですか?
SQL Serverで暗号で安全な番号を生成する方法はありますか?
興味深い質問:)
私はこれがうまくいくと思う:CRYPT_GEN_RANDOM
ああ、これは乱数源としても使える! SQL Serverでは乱数が面倒です。 – usr
私はそれもユニークである必要があります。 'Convert(int、CRYPT_GEN_RANDOM(9、Convert(varbinary、NEWID()))')を使うことはできますか? –
@ user1761123 - おそらくあなたの質問のすべての*あなたの要件の*を置くことができた場合、人々はそれに答える機会があります。今のところ、それは一意で、 'int'サイズである必要があるようです。さて、「暗号的に安全」という定義は、私たちが使いたいと思っているものですか?これは例えばですか?ノンス? –
CRYPT_GEN_RANDOM
は、 "暗号の乱数" を返すように文書化されています。
1
と8000
の間の長さパラメータを返します。これはバイト単位で返される数値の長さです。
長さは< = 8バイトです。これは直接SQL Server integer typesの1つにキャストすることができます。
+-----------+------------------+---------+
| Data type | Range | Storage |
+-----------+------------------+---------+
| bigint | -2^63 to 2^63-1 | 8 Bytes |
| int | -2^31 to 2^31-1 | 4 Bytes |
| smallint | -2^15 to 2^15-1 | 2 Bytes |
| tinyint | 0 to 255 | 1 Byte |
+-----------+------------------+---------+
3つは符号付き整数であり、1つは符号なし整数です。以下はそれぞれ、それぞれのデータ型の全範囲を使用します。
SELECT
CAST(CRYPT_GEN_RANDOM(1) AS TINYINT),
CAST(CRYPT_GEN_RANDOM(2) AS SMALLINT),
CAST(CRYPT_GEN_RANDOM(4) AS INT),
CAST(CRYPT_GEN_RANDOM(8) AS BIGINT)
データ型の記憶域よりも短い値を指定することもできます。
SELECT CAST(CRYPT_GEN_RANDOM(3) AS INT)
この場合、正の数だけを返すことができます。最後のバイトが0x00
として扱われるので、符号ビットは常に0になります。上記によって返される可能な数値の範囲は、0
とPOWER(2, 24) - 1
の間です。
1 and 250
の間に乱数を生成する必要があるとします。それを行うための1つの可能な方法は
SELECT (1 + CAST(CRYPT_GEN_RANDOM(1) AS TINYINT) % 250) AS X
INTO #T
FROM master..spt_values V1, master..spt_values
だろう
しかし、この方法では問題があります。生成することができるモジュラス関数への2つの可能な入力があるため、結果の
SELECT COUNT(*),X
FROM #T
GROUP BY X
ORDER BY X
最初の10行は、他のものとして、定期的に2回発生している(この場合1 -6
に)
+-------+----+
| Count | X |
+-------+----+
| 49437 | 1 |
| 49488 | 2 |
| 49659 | 3 |
| 49381 | 4 |
| 49430 | 5 |
| 49356 | 6 |
| 24914 | 7 |
| 24765 | 8 |
| 24513 | 9 |
| 24732 | 10 |
+-------+----+
低い数値でありますそれぞれの結果
一つの可能な解決策は、すべての数字を破棄するだろう> = 250
UPDATE #T
SET X = CASE
WHEN Random >= 250 THEN NULL
ELSE (1 + Random % 250)
END
FROM #T
CROSS APPLY (SELECT CAST(CRYPT_GEN_RANDOM(1) AS TINYINT)) CA (Random)
これは私のマシン上で動作しているように見えますが、おそらく、SQL Serverが唯一Random
に両方の参照を越え一度機能を評価することを保証するものではありませんCASE
の式にあります。さらに、ランダム値が破棄された行NULL
を修正するために、2番目以降のパスが必要になるという問題が残っています。
スカラーUDFを宣言すると、両方の問題を解決できます。
/*Work around as can't call CRYPT_GEN_RANDOM from a UDF directly*/
CREATE VIEW dbo.CRYPT_GEN_RANDOM1
AS
SELECT CAST(CRYPT_GEN_RANDOM(1) AS TINYINT) AS Random
go
CREATE FUNCTION GET_CRYPT_GEN_RANDOM1()
RETURNS TINYINT
AS
BEGIN
DECLARE @Result TINYINT
WHILE (@Result IS NULL OR @Result >= 250)
/*Not initialised or result to be discarded*/
SELECT @Result = Random FROM dbo.CRYPT_GEN_RANDOM1
RETURN @Result
END
そして
UPDATE #T
SET X = dbo.GET_CRYPT_GEN_RANDOM1()
あるいはより真っ直ぐ前方一つは単にbigint
の範囲は、任意のバイアスはおそらく無意味になるように巨大であるという理由で
CAST(CRYPT_GEN_RANDOM(8) AS BIGINT) % 250
を使用でき。 1
が生成できる73,786,976,294,838,208の方法があり、上記のクエリから73,786,976,294,838,206,249
を得ることができます。
バイアスを小さくしても許されない場合は、前述のように値NOT BETWEEN -9223372036854775750 AND 9223372036854775749
を破棄することができます。
@Endriあなたは欠けていることを明確にすることはできますか? 'CRYPT_GEN_RANDOM'は完全に良い答えのようです。 – CodesInChaos
@CodesInChaos 'CRYPT_GEN_RANDOM'は正確な数値を生成しません。もちろん、それらをIntに変換できますが、長さは必要なものになりますか?たとえば、8桁の暗号で安全な番号を生成する必要がある場合は、どのように 'CRYPT_GEN_RANDOM'を使用できますか?また、彼らはユニークですか? –
また、私は 'SQL'で安全な数値を生成する他の方法についても興味があります。 –