9

Can anyone recommend a cryptographically-secure pseudo random number generator library for Delphi (Win32)?

Can be free or commercial, but will ideally be an active project. I'd like it to include source code.

dommer
  • 19,610
  • 14
  • 75
  • 137
  • Check out http://blog.synopse.info/post/AES-CSPRNG - it is a strong AES-256 based Cryptographically Secure Pseudo-Random Number Generator, with higher security than the CryptoAPI black box (it uses CryptGenRandom only as entropy source). – Arnaud Bouchez Apr 09 '16 at 09:48

6 Answers6

10

You can use Windows CryptoAPI:

uses Wcrypt2;

function GenerateRandom(Len: Cardinal): TBytes;
var
  hProv : HCRYPTPROV;
begin
  if not CryptAcquireContext(@hProv,
                             nil,
                             MS_ENHANCED_PROV,
                             PROV_RSA_FULL,
                             CRYPT_VERIFYCONTEXT) then
    CryptAcquireContext(@hProv,
                        nil,
                        MS_ENHANCED_PROV,
                        PROV_RSA_FULL,
                        CRYPT_NEWKEYSET + CRYPT_VERIFYCONTEXT);

  if hProv > 0 then
  try
    SetLength(Result,Len);
    CryptGenRandom(hProv,Len,@Result[0]);
  finally
    CryptReleaseContext(hProv,0);
  end;
end;

Example of using the above code:

function BytesToHex(const Bytes: TBytes): string;
var
  i : integer;
begin
  for i := 0 to Length(Bytes)-1 do
    Result := Result + IntToHex(Bytes[i],2);
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  ShowMessage(BytesToHex(GenerateRandom(16)));
end;
vcldeveloper
  • 7,399
  • 2
  • 33
  • 39
  • 2
    The second CryptAcquireContext should be executed only if GetLastError = NTE_BAD_KEYSET. Else the code should raise exception (RaiseLastOSError) or return empty array. MSDN source: http://msdn.microsoft.com/en-us/library/windows/desktop/aa379886(v=vs.85).aspx – iPath ツ Apr 18 '14 at 23:26
  • The CryptGenRandom has known weaknesses. See http://eprint.iacr.org/2007/419.pdf Consider using it only as a source of entropy of a proven CSPRNG, e.g. as http://blog.synopse.info/post/AES-CSPRNG – Arnaud Bouchez Apr 09 '16 at 09:49
6

The Delphi Encryption Compendium (which is famous-ish in the German speaking Delphi community, but nowhere else - presumably since it isn't officially promoted) contains a cryptographically secure Yarrow RNG.

Just include the unit DECRandom (and maybe DECUtils) and use it like this (this example uses IInteger but that isn't mandatory):

function generateRandomNumber: IInteger; 
var 
  A: IInteger;  
begin 
  NRnd(A, 512);  // generate 512 Bit random number, 2^512 <= A < 2^513 
  Result := A;
end; 

initialization 
  // Method 1: uses system timer to initialize the RNG (seed)
  RandomSeed;   
  // Method 2: use own seed
  randomSeed(Data, SizeOf(Data));
lluca
  • 181
  • 2
  • 15
Leo
  • 37,640
  • 8
  • 75
  • 100
  • That skimps over the random seed generation, which is a big problem in itself. One can use CryptoAPI (as shown in other answers) to generate seed and then DEC to generate the random. – gabr Apr 12 '10 at 14:30
  • @gabr: Seed generation is of course a problem - but dommer didn't ask for it. If you feed the Delphi PRNG with a good seed, it is still not considered cryptographically secure http://en.wikipedia.org/wiki/Cryptographically_secure_pseudorandom_number_generator... – Leo Apr 12 '10 at 14:48
  • Agree, but still it has to be pointed out - especially as your code shows two not-very-good examples of initializing the seed. – gabr Apr 12 '10 at 18:33
2

Check out ISAAC (Indirection, Shift, Accumulate, Add, and Count), a fast PRNG and also cryptographically secure. Probably ISAAC is as fast as the famous Mersenne Twister PRNG.

Wolfgang Ehrhardt has done the Pascal/Delphi port for ISAAC (free and source available). There is also a link to another Delphi port provided on the author's site, but I would go with the "Wolfgang Ehrhardt" version. I know his site for many years, and he has been updating with the Pascal/Delphi routines since then. Surely should be an expert on this!

AmigoJack
  • 5,234
  • 1
  • 15
  • 31
user387963
  • 21
  • 1
1

You could use the existing Win32 CryptGenRandom() API.

Alex K.
  • 171,639
  • 30
  • 264
  • 288
0

OpenSSL would be a possibility. Source is available although I am not aware if a Delphi version is available. It includes a cryptographically secure prng. It is an active project, but it may be overkill for what you are looking for.

Mark Wilkins
  • 40,729
  • 5
  • 57
  • 110
0

I was also going to suggest the OpenSSL libraries. And you also get encryption, SSL, hashing etc included.
Indy has converted a lot of the headers and includes RAND_screen - but that can't/shouldn't be used, apparently, on programs without a UI. Unfortunately it misses out most of the RAND_* ones - but they're very easy to import and use.
eg:

function RAND_load_file(const filename: PAnsiChar; max_bytes: longint): integer; cdecl; external 'libeay32.dll';
function RAND_bytes(buf: PByte; num: integer): integer; cdecl; external 'libeay32.dll';
function RAND_pseudo_bytes(buf: PByte; num: integer): integer; cdecl; external 'libeay32.dll';

then in the code:

  RAND_load_file(PAnsiChar(AnsiString('name-of-seed-file')), 512);
  //or
  //RAND_screen;
  ...
  ...
  const
    PKCS5_SALT_LEN = 8;
  var
    salt: TBytes;
  begin
    SetLength(salt, PKCS5_SALT_LEN);
    RAND_pseudo_bytes(@salt[0], PKCS5_SALT_LEN);
    ...
  end;

The same seed issues as discussed still apply, of course.

shunty
  • 3,699
  • 1
  • 22
  • 27