0

i need to generate a 12 bytes random data for cryptographic purpose. My first idea was to use something like

random(maxint) * random(maxint) * random(maxint)

but i see that this will be not very efficient on multithread because random use a global var RandSeed (in fact random is not multithread). Also random look like to be very easy to guess :

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;

so if you know one of the generated random number you can easily guess the next generated random number...

is their any alternative to random to generate my 12 bytes random bytes ?

zeus
  • 12,173
  • 9
  • 63
  • 184
  • Should it matter what the next random number is? B.t.w, three 32 bit numbers are not going to fit in one 64 bit number. maxint*maxint ≈ maxint64 – GolezTrol Oct 22 '16 at 23:28
  • yes because if one know one number that was randomly generated, he can guess all the next generated number that is not good. it's not to fit in 64 bit, but to fit in 96 bits (12 bytes) – zeus Oct 22 '16 at 23:33
  • Not good why? For instance, when you add a salt for hashing, who cares where the salt comes from or what the next one will be, as long as you apply it in that specific hash, and there are plenty of different salts. I'm curious for what situation it is important that the next number is not known. – GolezTrol Oct 22 '16 at 23:36
  • when the random number is use as a key. you give a key to someone, so this guy can guess the next key you will give to someone else. i need a random of the random number – zeus Oct 23 '16 at 00:25
  • 3
    [Cryptographically secure random numbers](https://en.wikipedia.org/wiki/Cryptographically_secure_pseudorandom_number_generator) are rather different from just everyday random numbers. If you're trying to write a cryptographic library, forget about it - if you're getting stuck here then you have no hope of building anything useful. If you need to use cryptography, however, then just use a library. That's why they exist - because trying to roll your own end in pain. – J... Oct 23 '16 at 01:59
  • This is a complex topic and it's good that you are aware of some of the issues. But you are out of your depth a little. Thinking about using Random is a bad sign. 12 bytes is nothing. Parallel won't help and it won't be your bottleneck. Use a good crypto library and get it to generate your keys. But do a lot of reading and learn how to use the library. – David Heffernan Oct 23 '16 at 09:20
  • @David: thanks! no 12 bytes is enalf because the key can be use only via internet, so it's really easy to block any bruteforce Attack. in fact the key will be like a pasword you use in any website. but you understand now that this key (ie: password) must be absolutely random with no possibility how to guess it – zeus Oct 23 '16 at 09:47
  • Of course I understand that. I didn't say that 12 bytes wasn't enough. What I said was that performance of generating a 12 byte key is not your bottleneck and there's no place for parallel execution in that. Why do you think performance matters here? And why are you trying to invent a solution to this when solutions exist already. Created by experts. – David Heffernan Oct 23 '16 at 09:49
  • @david.. yes performance is not the bottleneck, but if i use random inside a criticalsection the problem will be that if someone have one key he can guess the next key that will be generated :( do you know a good library to use instead of random ? – zeus Oct 23 '16 at 09:51
  • Only if you do it wrong. You aren't going to use an algorithm that allows that are you? – David Heffernan Oct 23 '16 at 09:52
  • @david ... :) that the question in fact :) with algorithm to use :) – zeus Oct 23 '16 at 09:54
  • I don't think you are allowed to ask that question here, it is off topic. Read up on the subject, from a good book, and use a trusted crypto library. – David Heffernan Oct 23 '16 at 09:58
  • You know it is off topic to ask for recommendations. I guess I have to close vote now. – David Heffernan Oct 24 '16 at 13:58
  • you should generate a long buffer of cryptographically good randoms and put it into TThreadQueue or something, The generation should be single-thread and done with blocks above dozens or hundreds KB, then your worker threads would just fetch ready-made randoms form the queue and run a refiller every time the remaining Queue content falls below some threshold. PS. @DavidHeffernan funny, but this approach actually is very easy to implement in OTL's Pipeline, though it would be a huge case of over-engineering and the efficiency would be not very good – Arioch 'The Oct 24 '16 at 16:02

2 Answers2

4

I see three alternatives.

We published an Open Source AES-256 based Cryptographically Secure Pseudo-Random Number Generator (CSPRNG). It has a proven entropy generator, and you can have several generators (e.g. one per thread). It uses AES-NI hardware acceleration, so is very fast.

Or, if you want to generate unique IDs, you can use code similar to this, for generating one 32-bit random value at a time:

{$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;

It will use HW-based PRNG available on latest Intel CPUs, or fast a gsl_rng_taus2 generator by P. L'Ecuyer (with a period=2^88, i.e. about 10^26), which is a much better pattern than the one in Random(). For multi-thread, use threadvar instead of var for rs1, rs2 and rs3. And do not forget to XOR the initial values, e.g. with some minimal entropy, at least QueryPerformanceCounter().

Last but not least, if you want some unique values, not perfectly random, you may use simply:

var g: TGUID;
...
CreateGUID(g);

Here the generated TGUID is known to be unique, by the OS. You can easily use the 128-bit of the TGUID content, which could be used as keys in a better way than 332-bit, even over the Internet. A lot of systems just rely on this API call, if what you need is unicity, not randomness. You may use either the string representation, or the 128-bit = 432-bit binary content.

Sebastian Z
  • 4,520
  • 1
  • 15
  • 30
Arnaud Bouchez
  • 42,305
  • 3
  • 71
  • 159
  • He doesn't want uniqueness. From a language viewpoint there can only be two alternatives. That's what alternate means. To flip between two options. That this has been accepted turns this into a recommendation question. Arnaud, do you understand question closing here? – David Heffernan Oct 24 '16 at 13:55
  • The question was not clear, this is why I ended with 3 proposals. Of course, the first seems to fit the best, and directly answer the need of a stand-alone Delphi PRNG class. If he doesn't want uniqueness, so only our AES-PRNG and RdRand32 function do return true randomness - the later only if the CPU supports it. gsl_rng_taus2() is not cryptographic, just good fast random values. – Arnaud Bouchez Oct 24 '16 at 18:06
  • Arnaud, thanks for your answer .. i start to work on your algo, but unfortunatly my computer not support cfRAND in CpuFeatures. so i fall in the need to use rs1, rs2, rs3. The problem is that if a user know one generated key, then he can guess the next key that will be generated :( any idea how i can avoid this ? – zeus Oct 27 '16 at 21:31
  • 1
    @loki Then you need to seed the generator. And in such case, I do not see much possibilities for getting right entropy. You may use `QueryPerformanceCounter` and xor the rs1,rs2,rs3 with the returned value, and xor with some CreateGUID values. But for good entropy, you may need something stronger, like we use for our TAESPRNG.GetEntropy. But gsl_rng_taus2 is a deterministic generator, so any user may be able to guess the next value. In this case, TAESPRNG will be the best option for cryptographic randomness. Or call the Windows API. – Arnaud Bouchez Oct 28 '16 at 11:25
  • @Arnaud thanks! i read your code and i think i will use the windows API in case the processor don't support random – zeus Oct 28 '16 at 13:11
2

For sure Delphi's linear congruential generator is not suitable for generating cryptographically secure random data. You absolutely cannot rely on it for this task. It's not designed for that purpose, it is intended for use in other scenarios.

Don't try to implement this yourself. It's hard to do correctly and requires a great deal of knowledge and expertise. One of the most common reasons for people creating insecure code is when they try to write their own crypto without sufficient knowledge. Don't fall in to that trap. Use a trusted cryptography library.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • thanks David! i absolutely agree with you, but i didn't find yet a good library that do this ... i will try to look on the internet – zeus Oct 23 '16 at 10:17
  • Search for CSPRNG – David Heffernan Oct 23 '16 at 10:20
  • thanks david .. it's very hard to find a good and proven library, even the WRNG (The most frequently used PRNG) made by windows is not good (ie: http://eprint.iacr.org/2007/419.pdf - see the bottom conclusion) – zeus Oct 23 '16 at 10:29
  • http://stackoverflow.com/questions/2621897/are-there-any-cryptographically-secure-prng-libraries-for-delphi – David Heffernan Oct 23 '16 at 10:31
  • the windows advapi32.dll contains a the windows built in random number generator used by the win built in crypto libs... (check out CryptGenRandom). You can also use intel's asm command RDRAND (actually the Linux guys do not use it for their random generator since they have a bad feeling about it - may be a backdor for the NSA ;) – mrabat Oct 23 '16 at 19:18
  • @mrabat RDRAND is actually used in the Linux kernel, no directly for /dev/random or /dev/urandom, but as a source of entropy. Even the upcoming rewritten LRNG will use RDRAND - see http://www.chronox.de/lrng.html - but only as noise source, assuming only a very small amount of entropy, since they do not have enough confidence in this not auditable seed. CryptGenRandom suffers from the very same "black box" syndrome... so may be used only as entropy source, in addition with other information. – Arnaud Bouchez Oct 24 '16 at 18:13