我需要为加密目的生成一个12字节的随机数据。我的第一个想法是使用像
这样的东西random(maxint) * random(maxint) * random(maxint)
但我发现这在多线程上效率不高,因为随机使用全局变量RandSeed(事实上随机不是多线程)。随机看起来也很容易猜到:
function Random(const ARange: Integer): Integer;
var
Temp: Integer;
begin
Temp := RandSeed * $08088405 + 1;
RandSeed := Temp;
Result := (UInt64(Cardinal(ARange)) * UInt64(Cardinal(Temp))) shr 32;
end;
所以,如果您知道其中一个生成的随机数,您可以轻松猜出下一个生成的随机数......
是随机产生12字节随机字节的替代方法吗?
答案 0 :(得分:3)
我看到三种选择。
我们发布了一个开源AES-256 based Cryptographically Secure Pseudo-Random Number Generator (CSPRNG)。它有一个经过验证的熵生成器,你可以有几个生成器(例如每个线程一个)。它使用AES-NI硬件加速,因此非常快。
或者,如果要生成唯一ID,可以使用与此类似的代码,一次生成一个32位随机值:
{$ifdef CPUINTEL}
/// get 32-bit value from NIST SP 800-90A compliant RDRAND Intel x86/x64 opcode
function RdRand32: cardinal;
{$ifdef CPU64}
{$ifdef FPC}nostackframe; assembler;
asm
{$else}
asm
.noframe
{$endif FPC}
{$endif CPU64}
{$ifdef CPU32}
asm
{$endif}
// rdrand eax: same opcodes for x86 and x64
db $0f,$c7,$f0
// returns in eax, ignore carry flag (eax=0 won't hurt)
end;
// https://software.intel.com/en-us/articles/intel-digital-random-number-generator-drng-software-implementation-guide
{$endif}
var
rs1: cardinal = 2654435761;
rs2: cardinal = 668265263;
rs3: cardinal = 3266489917;
function Random32: cardinal;
begin
{$ifdef CPUINTEL}
if cfRAND in CpuFeatures then begin
result := RdRand32;
exit;
end;
{$endif}
result := rs1;
rs1 := ((result and -2)shl 12) xor (((result shl 13)xor result)shr 19);
result := rs2;
rs2 := ((result and -8)shl 4) xor (((result shl 2)xor result)shr 25);
result := rs3;
rs3 := ((result and -16)shl 17) xor (((result shl 3)xor result)shr 11);
result := rs1 xor rs2 xor result;
end;
它将在最新的Intel CPU上使用基于硬件的PRNG,或者由P. L'Ecuyer快速使用 gsl_rng_taus2 生成器(周期= 2 ^ 88,即大约10 ^ 26),这是一个比Random()
更好的模式。对于多线程,对rs1,rs2和rs3使用threadvar而不是var。并且不要忘记对初始值进行异或,例如使用一些最小的熵,至少是QueryPerformanceCounter()。
最后但并非最不重要的是,如果你想要一些独特的值,而不是完全随机的,你可以简单地使用:
var g: TGUID;
...
CreateGUID(g);
这里生成的TGUID由OS知道是唯一的。您可以轻松使用128位TGUID
内容,即使在Internet上也可以比3 * 32位更好地用作密钥。很多系统只依赖于这个API调用,如果你需要的是unicity,而不是随机性。您可以使用字符串表示形式,也可以使用128位= 4 * 32位二进制内容。
答案 1 :(得分:2)
当然,Delphi的线性同余生成器不适合生成加密安全的随机数据。你绝对不能依靠它完成这项任务。它不是为此目的而设计的,它旨在用于其他场景。
不要试图自己实现。这很难做到正确,需要大量的知识和专业知识。人们创建不安全代码的最常见原因之一是他们在没有足够知识的情况下尝试编写自己的加密。不要陷入那个陷阱。使用受信任的加密库。