Replace VB6's Rnd function with cryptographically secure alternative
I'm using the Rnd function to generate passwords. However, it's susceptible to brute-force attacks, regardless of the strength of the password itself which becomes (sort of) trivial when the aim of the attacker is not the password but the Rnd seed which generates it.
I use Rnd in many places in my code, and I know it's possible to replace native VB6 functions with our own, so I would like a fully operational replacement for Rnd which requires no code modification elsewhere, and is cryptographically secure. Like the standard Rnd function, it must return a Single value type. Like the standard Rnd function, the replacement can be used with parameter number or without it... the latter returns a value equal or greater than 0 and less than 1 (i.e. >= 0 and < 1).
APIs, as long as they are supported by default from Windows XP/Server 2003 to Windows 10, are welcome.
Why a Rnd replacement instead of a fit-my-mold function? Because there are thousands of Rnd-dependent functions on the net, for n different purposes, many of which have shortcomings due to the inherent weakness in the standard Rnd function.
Re: Replace VB6's Rnd function with cryptographically secure alternative
Originally Posted by veloz
I'm using the Rnd function to generate passwords. However, it's susceptible to brute-force attacks, regardless of the strength of the password itself which becomes (sort of) trivial when the aim of the attacker is not the password but the Rnd seed which generates it.
I use Rnd in many places in my code, and I know it's possible to replace native VB6 functions with our own, so I would like a fully operational replacement for Rnd which requires no code modification elsewhere, and is cryptographically secure. Like the standard Rnd function, it must return a Single value type. Like the standard Rnd function, the replacement can be used with parameter number or without it... the latter returns a value equal or greater than 0 and less than 1 (i.e. >= 0 and < 1).
APIs, as long as they are supported by default from Windows XP/Server 2003 to Windows 10, are welcome.
Why a Rnd replacement instead of a fit-my-mold function? Because there are thousands of Rnd-dependent functions on the net, for n different purposes, many of which have shortcomings due to the inherent weakness in the standard Rnd function.
Re: Replace VB6's Rnd function with cryptographically secure alternative
@flyguille
It's not for communication, no.
* * *
Here's a function by Bonnie West that I believe can be edited to replace Rnd:
Code:
Option Explicit
Private Declare Function CryptAcquireContextW Lib "advapi32.dll" (ByRef phProv As Long, ByVal pszContainer As Long, ByVal pszProvider As Long, ByVal dwProvType As Long, ByVal dwFlags As Long) As Long
Private Declare Function CryptGenRandom Lib "advapi32.dll" (ByVal hProv As Long, ByVal dwLen As Long, ByRef pbBuffer As Any) As Long
Private Declare Function CryptReleaseContext Lib "advapi32.dll" (ByVal hProv As Long, Optional ByVal dwFlags As Long) As Long
Public Function GenRnd() As Long
Const PROV_RSA_FULL = 1&, CRYPT_VERIFYCONTEXT = &HF0000000
Dim hProvider As Long
If CryptAcquireContextW(hProvider, 0&, 0&, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT) Then
If CryptGenRandom(hProvider, 4&, GenRnd) = 0& Then GenRnd = 0&
hProvider = CryptReleaseContext(hProvider): Debug.Assert hProvider
End If
End Function
Re: Replace VB6's Rnd function with cryptographically secure alternative
Perhaps something like this (first attempt to Rnd replacement):
It uses the previous code that you posted.
Code:
Public Function Rnd(Optional ByVal Number) As Single
Dim Dbl As Double
Static sLast As Single
If IsMissing(Number) Then
Number = 1
End If
Select Case Number
Case Is < 0 ' The same number every time, using Number as the seed.
Rnd = VBA.Rnd
Case Is > 0 ' The next random number in the sequence.
Dbl = CDbl(GenRnd)
Dbl = Dbl + 2147483648#
Dbl = Dbl / 4294967296#
Rnd = CSng(Dbl)
Case Else ' 0: The most recently generated number.
If sLast <> 0 Then
Rnd = sLast
Else
Rnd = Rnd(1)
End If
End Select
sLast = Rnd
End Function
Last edited by Eduardo-; Mar 19th, 2017 at 05:01 PM.
Re: Replace VB6's Rnd function with cryptographically secure alternative
being it for communication or storage is more or less the same thing but with particular differences...., if someone want to decrypt your file, is not only how to get the seed, if brute force or from some file containing it, it is also knowing how you use the RND function and how you apply the numbers in data record.
So, the hacker already dissasemble or traced your EXE, for knowing how to read your records. If it is a DB like access is far more easy thing, than custom binary file format.
Concern about the speed of the code, can make you to do a weaker or harder cryptography.
If for comunication, can be included universal things like "UTC time" in the cryptography, so the message a given day isn't the same as next day.
if for storage, your APP must konw how to decrypt it to use, if not inputed by user on every instance, so in some place you needs to save the seed. And there is a place of interest for the guy trying to do inverse engineering.
But there is a basic rule, the software will deserve the man-hours needed to hack it or not?. Do it a bit harder than what the hacker is willing to invest and your software or files never will be cracked.
Re: Replace VB6's Rnd function with cryptographically secure alternative
Originally Posted by veloz
There's no need to set the seed in most cases (like, >99%) if all you want is true randomization.
Can you incorporate GenRnd() into Rnd() to make it a single function?
but if you can't repeat the rnd serie (setting the seed), ¿how do you build up the same kripto password again and again?. The only other way I see, is to save the krypto password already builded in some place, and that is a weakness because if found saved in a file it is already done!, ofcourse you can save the krypto pass in another encrypted file, but that is a vicious circle.
Last edited by flyguille; Mar 19th, 2017 at 06:11 PM.
Re: Replace VB6's Rnd function with cryptographically secure alternative
Originally Posted by veloz
There's no need to set the seed in most cases (like, >99%) if all you want is true randomization.
Can you incorporate GenRnd() into Rnd() to make it a single function?
Code:
Private Declare Function CryptAcquireContextW Lib "advapi32.dll" (ByRef phProv As Long, ByVal pszContainer As Long, ByVal pszProvider As Long, ByVal dwProvType As Long, ByVal dwFlags As Long) As Long
Private Declare Function CryptGenRandom Lib "advapi32.dll" (ByVal hProv As Long, ByVal dwLen As Long, ByRef pbBuffer As Any) As Long
Private Declare Function CryptReleaseContext Lib "advapi32.dll" (ByVal hProv As Long, Optional ByVal dwFlags As Long) As Long
Public Function Rnd(Optional ByVal Number) As Single
Dim Dbl As Double
Static sLast As Single
Const PROV_RSA_FULL = 1&, CRYPT_VERIFYCONTEXT = &HF0000000
Dim hProvider As Long
Dim Lng As Long
If IsMissing(Number) Then
Number = 1
End If
Select Case Number
Case Is < 0 ' The same number every time, using Number as the seed.
Rnd = VBA.Rnd
Case Is > 0 ' The next random number in the sequence.
If CryptAcquireContextW(hProvider, 0&, 0&, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT) Then
If CryptGenRandom(hProvider, 4&, Lng) = 0& Then Lng = 0&
hProvider = CryptReleaseContext(hProvider)
End If
If Lng <> 0 Then
Dbl = CDbl(Lng)
Dbl = Dbl + 2147483648#
Dbl = Dbl / 4294967296#
Rnd = CSng(Dbl)
Else
Rnd = VBA.Rnd
End If
Case Else ' 0: The most recently generated number.
If sLast <> 0 Then
Rnd = sLast
Else
Rnd = Rnd(1)
End If
End Select
sLast = Rnd
End Function
Re: Replace VB6's Rnd function with cryptographically secure alternative
Originally Posted by flyguille
but if you can't repeat the rnd serie (setting the seed), ¿how do you build up the same kripto password again and again?. The only other way I see, is to save the krypto password already builded in some place, and that is a weakness because if found saved in a file it is already done!, ofcourse you can save the krypto pass in another encrypted file, but that is a vicious circle.
In that case then there is the need to find another function to generate the random numbers that can accept a seed.
Re: Replace VB6's Rnd function with cryptographically secure alternative
Originally Posted by flyguille
but if you can't repeat the rnd serie (setting the seed), ¿how do you build up the same kripto password again and again?
I don't need to. The whole point is to avoid a pattern, i.e. to make it truly random.
* * *
Thanks, Eduardo.
What is VBA.Rnd? My guess is that you need to call the VB6's Rnd() inside a function with the same name, and VBA.Rnd is some kind of workaround, though I have never heard of it.
As for the code, I'm using it, but I would like to hear what other experts have to say regarding its safety and reliability.
EDIT: See the attached image. The vast majority of outputs are 0,decimals, but shouldn't ALL outputs be 0,decimals? Why is this one 3,decimals?
Re: Replace VB6's Rnd function with cryptographically secure alternative
Originally Posted by veloz
I don't need to. The whole point is to avoid a pattern, i.e. to make it truly random.
* * *
Thanks, Eduardo.
What is VBA.Rnd? My guess is that you need to call the VB6's Rnd() inside a function with the same name, and VBA.Rnd is some kind of workaround, though I have never heard of it.
As for the code, I'm using it, but I would like to hear what other experts have to say regarding its safety and reliability.
EDIT: See the attached image. The vast majority of outputs are 0,decimals, but shouldn't ALL outputs be 0,decimals? Why is this one 3,decimals?
for make it truly random just set up the seed with the system TIMER. is an old trick from very old computers.
As the app never start from the same micro-second than any other instance, you can read system tick count, and with it set up the seed.
RND() also has a function to do that, iirc, if parameter positive is a seed, repeatable, if negative the seed is initialize in the mentioned way (IIRC), so, no pattern repeated.
Re: Replace VB6's Rnd function with cryptographically secure alternative
Randomize uses the timer, meaning the range of the seed can be guessed. The standard Rnd function is just not recommended for implementations where security is important.
See:
Historically, we always told developers not to use functions such as rand to generate keys, nonces and passwords, rather they should use functions like CryptGenRandom, which creates cryptographically secure random numbers.
Creating a replacement for Rnd with CryptGenRandom will solve this 'flaw' while being compatible with thousands of Rnd-dependent functions readily available on the internet, and this is my intent.
I'm using Eduardo's code from post #10 but I need other experts in the community to vouch for its security and reliability. For instance: can it generate any number between 0 and 1000000 (one million) using it like e.g.:
Code:
CLng((1000000 * Rnd) + 0)
... or would any number(s) be never reproduced in this manner?
Re: Replace VB6's Rnd function with cryptographically secure alternative
Originally Posted by veloz
Randomize uses the timer, meaning the range of the seed can be guessed. The standard Rnd function is just not recommended for implementations where security is important.
Creating a replacement for Rnd with CryptGenRandom will solve this 'flaw' while being compatible with thousands of Rnd-dependent functions readily available on the internet, and this is my intent.
oh!, you means that the range of possibles seeds are too small, so susceptible to brute force (IF hacker knows how looks the uncrypted data).
Well, when I secured my software communications I didn't use RND(), I uses XOR , AND , NOT , POWERs and DIVISIONS manually, strings, ambient universal values, plus multiple layers of packaging with CRCs, universal factors taken from SSL methods, etc.,, and by example, for most the trafic one cryptographic a single layer is enough, for more sensitive information, like DRM, nestling another crypto/packing protocolo as parameter of the main protocol, three times, is the best..., just too much headache for the cracker, and nobody will want to crack it.
Now in storage as the best think, don't use standard file formats like DB access, etc. Unless massive data handling, and fast, is a must have, ofcourse you can do your own DB engine in plain BASIC, and make it work unrecognizable for the human eye.
About paswords, the rule is NEVER NEVER store a password, store a hash or MD5 of it, and store it in the unrecognizable most twisted format your pick.
Needs to read it again, so hold the seed or string key somewhere?, ok an idea, krypto it with the MAIN admin password hash, and lets the app asks for it before it can ever read the DB. If the admin introduce wrong password, it generate incorrect hash which lead to incorrect CRC attempting to read the DB. The only bad thing, if the admin account change its password is require to recrypt all the database before forgetting the old password.
is there so many ways to protect information.
But the weaker point of it all, is the VB compiled CODE, it is not like you doing nasty things abusing of hard to known ASM opcodes behaviour to build up twisted routines in ASM, in VB as C, all compiled code is easy to understand, boring, just easy, traceable , easy easy....
So then it all relies on how many seeds, keys, are possible. and how many time the hacker wants to invest.
Last edited by flyguille; Mar 20th, 2017 at 12:24 AM.
Re: Replace VB6's Rnd function with cryptographically secure alternative
Originally Posted by veloz
Thanks, Eduardo.
You're welcome.
Originally Posted by veloz
What is VBA.Rnd? My guess is that you need to call the VB6's Rnd() inside a function with the same name, and VBA.Rnd is some kind of workaround, though I have never heard of it.
Yes, since the function's name is Rnd, now to call the VB6's Rnd we cannot just write Rnd, we need to qualify with VBA.Rnd (that means Rnd from the VBA library, not this one that would be Module1.Rnd -or ModuleName.Rnd-)
Originally Posted by veloz
As for the code, I'm using it, but I would like to hear what other experts have to say regarding its safety and reliability.
Yes, that would be nice, because I'm not an expert in security.
Originally Posted by veloz
EDIT: See the attached image. The vast majority of outputs are 0,decimals, but shouldn't ALL outputs be 0,decimals? Why is this one 3,decimals?
They are all values between 0 and 1, like the VB6's Rnd (and that's what I get).
Some of them are small values, yes, but not "the majority".