Page 1 of 1

QRandom - custom random number generator

Posted: Sun Mar 10, 2013 11:20 am
by codeprof
Hi,
I created a custom number generator, mainly because the PureBasic default Random() command is much too insecure and the result should be reproduceable (so I could not use CryptRandom() either). The following code should be relative secure (at least I tried my best to make it secure), however I am not an cryptography expert.
Maybe a cryptography expert here in the forums could check it and give me feedback?
As shown in the short example at the bottom I use the code to generate multiple keys based on one master key (So I have to remember only one password :D ).
Feel free to use it for whatever you want.

Feedback is welcome.

Code: Select all

;================================================================================================================================
;SUBJECT: Generating random numbers with a string as seed
;         This should fill the gap between Random() and CryptRandom()
;AUTHOR:  codeprof
;LICENSE: PUBLIC DOMAIN (can be used without any restriction)
;         This software is provided 'as-is', without any express or implied warranty.
;         In the author cannot be held liable for any damages arising from the use of this software.
;         Use this software at your own risk.
;DATE:    2013-03-23
;================================================================================================================================

;Advantages:
; - String can be used as seed!
; - more secure than Random()
; - configurable whether it should be fast or more secure
; - supports Unicode (and returns the same values like in ANSI mode)
; - support for quad random numbers (up to 63 bits instead of 31 bits with Random())
; - works for Windows, Linux and MacOSX

;Disadvantages:
; - probably not as secure as CryptRandom()
; - not thread safe  ( as the "Threaded" keyword of PureBasic cannot be used inside procedures
;                      To make it thread safe move the "Static" variables outside of the procedure as
;                      global variables and use the "Threaded" keyword)



;================================================================================================================================
;Initializes the random number generator with an seed string.
;Parameters:
; seed                      : string with which the random number generator is initialized (max 128 chars)
; num_iterations [optional] : Number of times the result should be hashed with MD5
;                             The result should be at least hashed once for security reason (prevents known plaintext attacks...)
;                             If security is not important "num_iterations" can be set to 0 to improve performace.
;                             A high number will result in very slow number generation.
;                             This could be used to prevent timing attacks (make brute force attacks harder).
;================================================================================================================================
Procedure.q QRandomSeed(seed.s, num_iterations.i = 1)
  Static Dim key.q(1)
  Static Dim current.q(1)   
  Static Dim tmp.q(1)
  Static num_md5_iterations = 0
  Protected md5.s, i.i
  If seed <> ""
    ;Initalize random number generator
    Protected Dim seed_string.UNICODE(127 + 1)
    PokeS(@seed_string(0), Left(seed,128), 128, #PB_Unicode)   
    ;We use the MD5 of "seed.s" to generate a 128 bit key.
    md5.s = MD5Fingerprint(@seed_string(0), SizeOf(UNICODE) * 128)     
    key(0) = Val("$" + Left(md5, 16))
    key(1) = Val("$" + Right(md5, 16))   
    ;The MD5 of the MD5 is used here so it is not possible to restore the key out of it (as reverting the MD5 is not possible).
    ;MD5(seed)+seed is used to reduce the chance for a collision, because it is much harder to find a string
    ;which returns a correct result for MD5(seed) and MD5(MD5(seed)+seed).
    PokeS(@seed_string(0), Left(md5 + seed, 128), 128, #PB_Unicode)      
    md5.s = MD5Fingerprint(@seed_string(0), SizeOf(UNICODE) * 128)      
    current(0) = Val("$" + Left(md5, 16))
    current(1) = Val("$" + Right(md5, 16))
    num_md5_iterations = num_iterations
  Else
    ;generate the next random number
    AESEncoder(@current(0), @tmp(0), 128 / 8, @key(0), 128, #Null, #PB_Cipher_ECB)
    CopyMemory(@tmp(0), @current(0), 128 / 8)     
    ;To prevent short cycles we increment the 128 bit key by 1.
    key(0) + 1
    If key(0) = 0:key(1) + 1:EndIf
    ;hash the result with MD5
    For i = 1 To num_md5_iterations
      md5.s = MD5Fingerprint(@tmp(0), 16)     
      tmp(0) = Val("$" + Left(md5, 16))
      tmp(1) = Val("$" + Right(md5, 16))     
    Next 
  EndIf 
  ProcedureReturn tmp(0) ! tmp(1)   
EndProcedure 


;================================================================================================================================
;Random number between "min" and "max" (including "min" and "max")
;The functions supports random numbers up to 63 bits.
; max                       : maximum number (must be greater than "min")
; min                       : minimum number (must be less than "max")
;================================================================================================================================
Procedure.q QRandom(max.q, min.q = 0)
  Protected val.q = QRandomSeed("") & $7FFFFFFFFFFFFFFF
  val = val % ( max - min + 1)
  ProcedureReturn val + min
EndProcedure 







;Example

QRandomSeed("MY TOP SECRET MASTER PASSWORD", 100)
For j = 1 To 10
 
  passwd$ = ""
  For i = 0 To 30
    passwd$ + Chr(QRandom(126,33))
  Next 
 
  Debug "Password("+Str(j)+"): " + passwd$
Next   
//edit: 2013-03-23: small optimisation which does not change the results
//edit: 2013-05-03: improvement which changes the results

Re: QRandom - custom random number generator

Posted: Sun Mar 10, 2013 2:11 pm
by Inf0Byt3
Interesting code. I have been working on something like this as well. Your current function could be modified to be used as a KDF (key derivation function) for encryption, starting from the user's password. One other use would be for creating random initialization vectors. You could test the randomness of the output with this freeware tool (ENT):

http://www.fourmilab.ch/random/

By the way, I think CryptRandom should be secure and the output (in theory) should not be reproduceable. From what I know it gathers entropy from the system (handles, timers, etc.) and uses that data as a seed.

Re: QRandom - custom random number generator

Posted: Sat Mar 23, 2013 7:26 pm
by codeprof
Thanks for the tip. Really cool tool.
for "QRandomSeed("MY TOP SECRET MASTER PASSWORD", 1)" with 400 MB of random data it returns:
Entropy = 8.000000 bits per byte.

Optimum compression would reduce the size
of this 400000000 byte file by 0 percent.

Chi square distribution for 400000000 samples is 245.46, and randomly
would exceed this value 65.47 percent of the times.

Arithmetic mean value of data bytes is 127.4937 (127.5 = random).
Monte Carlo value for Pi is 3.141616531 (error 0.00 percent).
Serial correlation coefficient is -0.000043 (totally uncorrelated = 0.0).
So the results should be ok, right?

With 400 MB of CryptRandom() data I get:
Entropy = 8.000000 bits per byte.

Optimum compression would reduce the size
of this 400000000 byte file by 0 percent.

Chi square distribution for 400000000 samples is 234.88, and randomly
would exceed this value 81.22 percent of the times.

Arithmetic mean value of data bytes is 127.4997 (127.5 = random).
Monte Carlo value for Pi is 3.141387931 (error 0.01 percent).
Serial correlation coefficient is -0.000031 (totally uncorrelated = 0.0).
With Random() I get
Entropy = 8.000000 bits per byte.

Optimum compression would reduce the size
of this 400000000 byte file by 0 percent.

Chi square distribution for 400000000 samples is 227.53, and randomly
would exceed this value 89.13 percent of the times.

Arithmetic mean value of data bytes is 127.4973 (127.5 = random).
Monte Carlo value for Pi is 3.141808051 (error 0.01 percent).
Serial correlation coefficient is -0.000111 (totally uncorrelated = 0.0).
So at least for Random() the Chi square test says it is "almost suspect"...

Re: QRandom - custom random number generator

Posted: Sat Mar 23, 2013 8:03 pm
by codeprof
here a slightly modified version which uses AES to create a nonreversible result and different initialisation to reduce the chance for MD5 collisions:

Code: Select all

;================================================================================================================================
;SUBJECT: Generating random numbers with a string as seed
;         This should fill the gap between Random() and CryptRandom()
;AUTHOR:  codeprof
;LICENSE: PUBLIC DOMAIN (can be used without any restriction)
;         This software is provided 'as-is', without any express or implied warranty.
;         In the author cannot be held liable for any damages arising from the use of this software.
;         Use this software at your own risk. 
;DATE:    2013-03-23
;================================================================================================================================

;Advantages:
; - String can be used as seed!
; - more secure than Random()
; - configurable whether it should be fast or more secure
; - supports Unicode (and returns the same values like in ANSI mode)
; - support for quad random numbers (up to 63 bits instead of 31 bits with Random())
; - works for Windows, Linux and MacOSX

;Disadvantages:
; - probably not as secure as CryptRandom()
; - not thread safe  ( as the "Threaded" keyword of PureBasic cannot be used inside procedures
;                      To make it thread safe move the "Static" variables outside of the procedure as
;                      global variables and use the "Threaded" keyword)



;================================================================================================================================
;Initializes the random number generator with an seed string.
;Parameters:
; seed                      : string with which the random number generator is initialized (max 128 chars)
; num_iterations [optional] : Number of times the result s encrypted with AES on a nonreversible way
;                             The result should be at least hashed once for security reason (prevents known plaintext attacks...)
;                             If security is not important "num_iterations" can be set to 0 to improve performace.
;                             A high number will result in very slow number generation.
;                             This could be used to prevent timing attacks (make brute force attacks harder).
;================================================================================================================================
Procedure.q QRandomSeed(seed.s, num_iterations.i = 16)
  Static Dim key.q(1)
  Static Dim current.q(1)    
  Static Dim result.q(1)
  Static Dim tmp.q(1)
  Static num_aes_iterations = 0
  Protected md5.s, i.i, *key
  If seed <> ""
    ;Initalize random number generator
    Protected Dim seed_string.UNICODE(127 + 1)
    PokeS(@seed_string(0), Left(seed, 128), 128, #PB_Unicode)    
    ;We use the MD5 of "seed.s" to generate a 128 bit key.
    md5.s = MD5Fingerprint(@seed_string(0), SizeOf(UNICODE) * 128)      
    key(0) = Val("$" + Left(md5, 16))
    key(1) = Val("$" + Right(md5, 16))   
    ;We use MD5(MD5(seed)+seed) as initialisation value.
    ;The MD5 of the MD5 is used here so it is not possible to restore the key out of it (as reverting the MD5 is not possible).
    ;MD5(seed)+seed is used to reduce the chance for a collision, because it is much harder to find a string
    ;which returns a correct result for MD5(seed) and MD5(MD5(seed)+seed).
    PokeS(@seed_string(0), Left(md5 + seed, 128), 128, #PB_Unicode)      
    md5.s = MD5Fingerprint(@seed_string(0), SizeOf(UNICODE) * 128)      
    current(0) = Val("$" + Left(md5, 16))
    current(1) = Val("$" + Right(md5, 16))
    num_aes_iterations = num_iterations
  Else
    ;generate the next random number
    AESEncoder(@current(0), @result(0), 128 / 8, @key(0), 128, #Null, #PB_Cipher_ECB)
    CopyMemory(@result(0), @current(0), 128 / 8)     
    ;To prevent short cycles we increment the 128 bit key by 1.
    key(0) + 1
    If key(0) = 0:key(1) + 1:EndIf
    ;Despite it seems not very useful the next part is relevant for security.
    ;Of course we could encrypt our "result" buffer just with the key. The result would be also
    ;equally distributed random numbers, but a known plaintext attack would be easier.
    ;The attacker would know half of "result", so it would be easier to him to predict the next random number.
    ;Therefore we add this nonreversible part to calculate the final result.
    ;AES itself is reversible. However, here it is not because the key selection is based on intermediate values, which cannot be restored (just by trying out all possibilites).
    For i = 1 To num_aes_iterations
      *key = ?QRANDOM_RANDOM_AES_KEYS + (result(0) & 255) * (128 / 8)
      CopyMemory(@result(0), @tmp(0), 128 / 8)   
      AESEncoder(@tmp(0), @result(0), 128 / 8, *key, 128, #Null, #PB_Cipher_ECB)              
    Next  
  EndIf  
  ProcedureReturn result(0) ! result(1)   
  DataSection
    QRANDOM_RANDOM_AES_KEYS:
    Data.q $56925DA264FD4DE2,$B90230394D9E4C09,$F148E6F393B5345A,$86BAA4AFAC0BD66B,$9EE5F0320041D959,$AF40EBC1D48ED2F3,$4C136BEDDE6B2972,$AE3E86F172E01244
    Data.q $7A23C4B1800E3A02,$ADC52DA72A1C5DC5,$6F346B5F5F5B66DC,$94C0BAE326EEBD49,$28F6923F50B00CB5,$5D9AF464E0678E3,$382BA9357A1F028D,$B1E357D2384EF571
    Data.q $4C6862BA6CE6ABD3,$1E2D71EEB8FE866A,$AB5CDF3D14613DC,$7188ECC96EA66C94,$913E76A782E63112,$14B075C78D75D6FA,$39088E41B3CC6F57,$E67DBCAAE004A7EE
    Data.q $5C8669B2CDF96DDB,$E40D67CDD9B62C6F,$70D13A3F684A0E3,$AA2F6FB5F9755B4D,$25225CFBD17E3BA9,$4A7D35BF5C9A5D9B,$B733511B26C9FF45,$15DF406F74BB3EC1
    Data.q $CF44858AD6E405C0,$8EBFF1048B85353C,$4C77FEFF474DC82D,$43B1FEC3AAEAEEAA,$E9DD6B6E34902354,$9AD9DB5B4AC985DA,$275C12DA289271D,$CF2D6B4E4BAAD466
    Data.q $63F145609D9119B5,$E7CB07E1972A9169,$6CBF479570D4B1B4,$38A274473C72503D,$9B034557BCC80186,$D340DE87E0178ED9,$57A74946065FA8E4,$A062A242303AD0E9
    Data.q $93E67D76AE37FCB1,$263209EE68FE122,$67CDAA2AF11FB15D,$3233E03B77184F19,$64F4A36DD72543D9,$C2BDBF273A764271,$4226B8DDE5DAD94D,$38C17659BB725CDA
    Data.q $F0EDC1E4391E2E02,$EE0E56D2D092841C,$6412D1AFDBE21C3E,$AA6810A2EE4AEE50,$DE41D5E06C0DA59C,$63B7679D41247D92,$424360D65FA69A4D,$D1C6EA12A19DE6F9
    Data.q $1973BD4E0B3719F6,$8D33ECAF55B8CFD0,$4A5B3BDED278E7F8,$6C6A0C28B077456F,$8789437E8D4C624E,$1AA550C42117D7B4,$A0A25A6498076AD5,$F3CABE4D6ED84A47
    Data.q $196CE3F6B9BD8AB9,$FA89196A5997CB44,$B0D75770C8F93661,$31770EDBD5E14591,$908346DEB51EE7A7,$F83A4A2111ACF2F,$BF1AB48895219528,$4D7D6C74D629150B
    Data.q $3C16AB42DFC8774E,$BA77F10C8E106C,$FA91EAC12706C60E,$3FD28E3C92522B7D,$79F8EC7049F21A98,$7F3F65E753F038AD,$69DC9F82EB818304,$1F7FE007E916CFD
    Data.q $D32FCE2241FD6309,$2DADAD60657C370C,$E1E327C69F626222,$1BCD588FE26CC2C1,$CEC030DCB86E933A,$9760406E2923AEAC,$EAF872423B45DA34,$F741DD4918168377
    Data.q $6AA57A7FD2336E5C,$2BEDB29E6A90632C,$5B23E4E47345C318,$FE369B7E29D485DC,$183D2C349F874CF3,$E8608033C9F31410,$2FE9B09BF04DB4C,$7350811E8B5E2266
    Data.q $FB61418C3567AC6E,$9738E6FD75377200,$D8E405B3E24201B5,$97A79CB326D628BE,$84217FCABD5A57D,$E6752370C0D2EBAB,$2FF160D2D10652BC,$6FBC4AD86EF7E709
    Data.q $20C89D0A1728F88D,$33B5545E43AC5884,$6D3478E25F852F1C,$BC824338595BD588,$80B99060E96333D,$A1C433301B91D931,$EF997D68F3AD4530,$17FEEE23CEC879C8
    Data.q $CE1AD285A66A997B,$BE3F1FA65FCC808A,$52C340DDC988675A,$C69756FAB53E63DD,$97B4BA69558E2FEE,$BF76DED8E987FF9,$3669C9D555E7CE25,$320CBAA8F8D38221
    Data.q $9634517161ECC14C,$FD4CEF5D623C15FE,$94EEF8AD43F2FB78,$827BCE8BD03B1858,$3B587A1EE530FBBF,$CEE74063D4AE41F0,$DA5D4C3536C498EE,$4FC36CD8ACF6D1E1
    Data.q $573484F07D8EFD51,$6E4627750DDF7EB,$828512641265D518,$95133C5752870CAE,$5B8F03F85C613263,$B96D5A159D6F464,$8A8ACEF38BD86C18,$4EAF8B485E6E3B4B
    Data.q $F3F7DC21CFD24F3,$4F5AD47EF9B00D03,$89EF7560CF43F6F6,$E7A50E3FE0BD772B,$52E9E46EE416115,$22A7DA166A38CD6F,$59A17EAE8FF57E53,$68EF8A17D1742B26
    Data.q $34C90892C5E44450,$C06EDE1FB27E63BC,$1089C0C661EAA7C3,$A60AA3DB869696C7,$C5BCC23D86CB50E7,$F2A5F34C734E0AB,$D14963A785F3E426,$C63852FD0C0A1DA1
    Data.q $19B3F8C18ACFC954,$7758E09008DA71F0,$FF7037B8F928CFD6,$36B8F4745886F52,$FBE9A80E29C76BF9,$84B6EBA20D7E8B3C,$918E6AD8E3190789,$82953D049C86A0E7
    Data.q $A35A35E938E4A59F,$6CEB5143F083BC3F,$B2735C8D052FB0E,$68998879091D0603,$F87C24F2ADA46483,$C9E7678CDA227D0,$85BC9793A6728690,$51B7D14CBFFD3971
    Data.q $5CF314972B8954EE,$57A094C50E1DD661,$991EA8CCBA51BD4C,$F95DD9BB53507F0B,$6FBA25A8DC04E30A,$3AD08575567298F9,$440DF63AF36C5F7A,$CABF8EC94788C76F
    Data.q $8746FED39869CDC3,$8C5CF05C9B784955,$4CB21746BC3DA641,$BEC72950C465E35F,$22AF87AC1235197A,$7CF47C499F6D046,$A3FC02EA6F58DDDD,$5C60269388FD6F1D
    Data.q $94CC8F5A4FD9DECB,$B7010D951B642DE3,$81E455DE1ABD07DB,$A50E9310AC0FED07,$B4A6D6ECAE80C787,$B68FB0F470BDE967,$F6BD5F469151CE11,$AB2DDE8490158EF3
    Data.q $B3B240B1452A29BD,$6E1308166FE917CC,$BBE60EAAB9FD0550,$C09FA63F0835B619,$C00942B033E8DAE9,$A3D0CBF5EC3A5E2D,$F162E3368F8B9F7E,$23A515ACC04818AB
    Data.q $7A4A8D873080EF1,$570AE960C7DDE005,$11DD70CFFB9301AF,$545281D622DE08A5,$2C6E2CED2B2F7D90,$46F7827B73F4DF8D,$9A9D46A7401DB2A9,$36B8C4F9A8232C12
    Data.q $A5168DAFFC03FA06,$DC1E101E92B35D5A,$AAF2DA2CB0AB6C6E,$9466FB4860D03CA0,$FDE20D681CAD4A8C,$EBF1A82934B3A83F,$D417CE5876E5E302,$1AEEADE7606A1E63
    Data.q $D3F427E74A873960,$CE8912C5441975AF,$6BE4446A5C4478DF,$41F2056329845F92,$70055F6166144C43,$7F41B582B12032CC,$41630771C027025A,$E4934B2C90352527
    Data.q $8264D5546A2F94AC,$3ECD63E723090C27,$5EEC88981AA10F66,$92DD2DFFDA9A754,$1740048B164ECDED,$75B4B965C6915103,$E213378E806C3C2B,$1BEE8EFF35668EBB
    Data.q $37DCE7231BEF603B,$F95E01BCA74A9C01,$AFC89440B74CEFAE,$5B291B2C8E497856,$730D7E26160DF867,$3D8B9D368CAED9F5,$10CBA51860F97EE5,$7065EC769F880456
    Data.q $95E888E75193899A,$F9B86EAB9C297301,$68CB85117EA74CE4,$361220DE24250982,$4C1A0EB5D2B4D579,$43BCF471686386CE,$CF80EAD42A0409DF,$D5757F5B019EA974  
    Data.q $38D77241492C41FF,$680D1A4B8D5E549B,$AB39E19720AA1FF1,$9CB4AF79EEAC8CD6,$206447A6AEEA5EB5,$CD6100231DFC502D,$9A6E23B329C6D1C9,$D16360CED435261
    Data.q $5A36DF256B843326,$A90D7D2423B30C26,$876231841877BD,$D3BF957242AFF313,$C7F41783868E1069,$1BDDA0D34C0A1BFF,$5317D6A96DE00432,$995D6B4F8225A78
    Data.q $1D1117B914CAD59E,$3290F3B229E8BD7C,$C78F777676406EED,$34F9DD87C0C697F1,$C0625A74C657A369,$D87E6120DAB5CED3,$492ACD83D7A5108A,$815C6DFE33ADCB0
    Data.q $7010AAA14BAF974D,$65BB51D37DB5A996,$DCC7FE4045B96FFA,$AF9FAE13CB56ADB4,$DD573ED9A1364DCA,$63EA3FD57A9A22A0,$4664EBE7CF4DC9D2,$95F23898A0BB022
    Data.q $9906DB957B8B4224,$18C472E1151E4BD1,$BC05105858EE9841,$111708612EC47DD8,$883AFBE8EF4CC14C,$BE71050B7CDE4848,$8D88B422F2600332,$FA5FABA6DAFDCE5
    Data.q $3B38748C2F109A28,$520890A68A69BF69,$490CFE76D9A9BEDD,$CCFB524B4E2D7A14,$93F953D64D2E7D56,$A0F8AB531BE85F2A,$91745B732F5410AD,$C6F3674B2177B35
    Data.q $7A5E26F6E6A04ABE,$208AC27EEC163720,$C21FFF700CA8415A,$BC748631FF6655C6,$551B159966C93A90,$B3062C8037E27085,$F0F05E7BB78CA447,$E3D15C2C9C4ECE1
    Data.q $19CC57A883E7B173,$4F18EEA3A042A31C,$5168DD323C54F4E9,$455EACF7FEF2A22,$A8001A49448490D4,$929DEB73252D61B,$5748603B3C195A93,$FECA7E8FDCBB2B1
    Data.q $160A8C2A008F2286,$19E69781CA07E421,$1B5AD949E7B53231,$CF430A969977B,$D0F620EBA61481D9,$897BDE8348876DE4,$DC6D6E090D2786E1,$CB31D4CDFD1CE3F
    Data.q $9E140CCE53C00CEE,$5382AF3A3D523E34,$D9E2C77DDED1E631,$BA4372D24D3F3AA3,$4B8788702ABDE6BC,$DAA32BC53E3172F,$C3C892FDC244359A,$E424F4AF6783386
    Data.q $E167744719BA08C9,$E1D2CD44CFD61F8C,$2A33F97FB51A7932,$A46B09245E74BE92,$89F1ADC7FCB8C0,$6BF560982BC7F927,$7633C879310A359,$8BBC6B5E23C5B21
    Data.q $BE3E2E31356BFFB2,$AE31E0510FA7F81B,$28F4CB637F1DE609,$2544DC34E2DD2657,$62652CC78EAEF6D5,$4AC932FF5A8EDB99,$33A06CEB8661D6BD,$75904721A898025
    Data.q $3C89277F2BE46132,$F351FCF7BE85C744,$ED2C57D0C0005027,$B257EE9C3D1607FA,$7B8CFC03C19A6981,$416F7ED2C05825DD,$D43C3181F2D36A7B,$B67074512AD3ADA
    Data.q $9CE391191789172E,$E157F3C0B6425035,$6312EF1C1270F118,$51D5DB8FC47BE92C,$D36DD0DF9A774D0E,$DD0B094CD70D3B35,$91F273C0AA850276,$E722BECCD746683
    Data.q $DB741026D009D493,$D9526DA149AD7787,$47BEA9AD53DDAAC1,$186DB654D8788D55,$A6FC38CD22A5C5D7,$A1B2D34EA1879085,$27350CA239AA9AF1,$4380B2302FDED0B
    Data.q $2A03D5AF40482376,$A0CF8D9762F57314,$69215EA7A127E530,$6347C715FA298C06,$4AE1799FA47BEAE6,$D923F6E610D1F57C,$74DDEDC19E6B6E79,$18160D19699704F
    Data.q $71C07B45D2084927,$DAA23DB03366BDEE,$BF05280EC4E21BDB,$2B3C01AA802E36AF,$2456174C0C83A6FA,$72722245C4282B10,$B4AA20BF55C961EB,$1EACCB347E6076B
    Data.q $429C76D1489A5ED8,$906B9BF5921986F4,$9E76DE69BD351703,$D86A451D0B671F25,$47681B42664A9917,$81259366FC2043D3,$D6DA4C57516527B3,$4E7D7BCCD9206D8
    Data.q $CB05698C9B70CDC4,$C9CF466EEB9CA043,$ADD9533A3087B40A,$6E387A6A4D21601E,$DBDACC32CC5E1278,$C9724EAF63F3ACDB,$48BE2C5826EB359D,$49E8FE5B097E145
    Data.q $D96FF933C01D932A,$4395B13C20AB6BCF,$3DB9E797637EA969,$4E4D53B7DB0B0246,$1273F2E14115FAA9,$A6FE328AABFDC53A,$F6537B797DEB302C,$6F47E5FE4676C06
    Data.q $366055EF2D4B5A68,$163981DF741208F5,$3B799E9BCD51A631,$C85F8BF9ACECC739,$D13F0D6E1001CBFC,$33288A9D92B052A0,$A41F301BCAEFA166,$2CB59BC50FA020C
    Data.q $C72BAD0528DF317E,$29D9114E987FC11E,$7E007E88AE674F60,$FFF0CF79668B2CCF,$E01B02FD3E1CDE29,$6216AA694B247FAD,$AEE1028D92A02528,$CEFE4539A349FCA
    Data.q $89B286BA88E7CEA6,$5F5FAF9B9F5D97B8,$BE393D9620C390C2,$A08E98A6E9F55D3F,$20EC5856361FCDE2,$3BBB4902CE27B37B,$4CD1829B74801CEF,$65592FEAEF0C11E
    Data.q $60B2BB0EB594515B,$27AA68C366FE0AFB,$74832D014E1F3B98,$F67057131EEB882,$642179C24DA6F097,$15F4D99DA3F215BA,$660146DAE4F11310,$505AC2B1C4B6E80
    Data.q $7CA3ADDC8CA5AB34,$B5B67FD5AC15D7A3,$2118FD8D779F99E1,$DCB2F3FED513343A,$2100DE48F0F6933,$6E5E5D08B69B4D0A,$C2A833A9D86398D5,$3A071892689AEB5
    Data.q $320B18EB9FF82DBF,$DB1167D123C7D5AB,$91E429470E54FBBB,$66AFC84AD7CDCB53,$26D4BE4909265B3D,$7257C21B7686FD80,$43AB276CC71AFBF2,$8EBD9F046D00B26
    Data.q $F812A1A93DDAE031,$19D07A966EB09C57,$ED339969D1C9D91C,$C5A01A87D7E4F18E,$654C238B8390DE1C,$24DAF15170D78348,$6F3AC78B98881E5D,$1DEAB11D55CFD9
    Data.q $989EE52C999AB969,$999D63A249C04667,$5840989A13C6409F,$182DA800947FFE0D,$F4D77B16313AC67E,$A62AF6BA5B90BD00,$CE06A209B852557B,$DE73A3756BE169A
    Data.q $E18254F41356831E,$DFCF201D9F166007,$C1FA653913BE9BB1,$926211EBA0FD769E,$DAEE70A12EEB8B10,$E63EE0C041422DAE,$A716D9A78149F1EE,$9C1E4AF26088AB5
    Data.q $F92FE5ABA3AEC085,$EB56B15423149015,$C81B167E43199416,$78315333D0C65D5,$65A81BC84102883B,$8185188E7EC5713E,$3161A88922C34CF6,$F565A5C1708A97A
    Data.q $EBF540293B35AC5B,$F74571A64CC718B5,$9F223B3D49F507AB,$ABD43C220BFF07FF,$C45CC0CF111C1644,$48A035273EB44D59,$F584310AD9E32182,$32BEC7C9300A838
    Data.q $D4FE0597EAF45046,$B13A297D234AA959,$4C03F71B4BA9A878,$1342607A07F4F892,$6BD03BEFCD866F01,$D5DDE4979536D1A9,$1B89AF18CB0F519B,$2B16DB1D045C301          
  EndDataSection
EndProcedure  


;================================================================================================================================
;Random number between "min" and "max" (including "min" and "max")
;The functions supports random numbers up to 63 bits.
; max                       : maximum number (must be greater than "min")
; min                       : minimum number (must be less than "max")
;================================================================================================================================
Procedure.q QRandom(max.q, min.q = 0)
  Protected val.q = QRandomSeed("") & $7FFFFFFFFFFFFFFF
  val = val % ( max - min + 1)
  ProcedureReturn val + min
EndProcedure  







;Example

QRandomSeed("MY TOP SECRET MASTER PASSWORD", 100000)
For j = 1 To 10
  
  passwd$ = ""
  For i = 0 To 30
    passwd$ + Chr(QRandom(126,33))
  Next  
  
  Debug "Password("+Str(j)+"): " + passwd$
Next  
Entropy = 8.000000 bits per byte.

Optimum compression would reduce the size
of this 400000000 byte file by 0 percent.

Chi square distribution for 400000000 samples is 270.24, and randomly
would exceed this value 24.47 percent of the times.

Arithmetic mean value of data bytes is 127.5050 (127.5 = random).
Monte Carlo value for Pi is 3.141425971 (error 0.01 percent).
Serial correlation coefficient is -0.000002 (totally uncorrelated = 0.0).
//edit: corrected bug
//edit: 2013-04-23 improved