Function to generate a really random string

Started by ., Aug 30, 2015, 04:33 PM

Previous topic - Next topic

.

I needed a function tonight to help me generate a really random string to be used as the salt in the player accounts. And then I decided to share it in case anyone else needs something similar.

NOTE: This needs the Hashing plugin to which it falls back if it couldn't generate the random string.

This is the code:
/* ------------------------------------------------------------------------------------------------
 * A string used with the format() function to generate a string from ASCII characters
 * NOTE: Duplicate the second line to allow bigger strings!
*/
g_FMT_CHARACTER_MASK <- @"%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c" +
                        @"%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c" +
                        @"%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c" +
                        @"%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c" +
                        @"%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c" +
                        @"%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c" +
                        @"%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c" +
                        @"%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c";

/* ------------------------------------------------------------------------------------------------
 * Function used to generate a trully random string
 *
 * @arg len [integer] The desired length of the string
*/
function GenerateRandomStr(len)
{
    // The array containing the random ascii characters + 2 extra arguments
    local args = ::array(len + 2, 48);
    // Fill the ascii characters array with random values
    args.apply( @(v) ::rand() % 94 + 33 );
    // Set the first element in the array to the 'this' environment
    args[0] = this;
    // Set the second argument to the formatting string
    args[1] = ((len * 2) > g_FMT_CHARACTER_MASK.len()) ?
                g_FMT_CHARACTER_MASK : g_FMT_CHARACTER_MASK.slice(0, len * 2);
    // Call the format function with the resulted arguments
    local str = ::format.pacall(args);
    // Return the resulted string or return the failsafe string
    return (typeof str == "string") ? str : ::MD5("" + rand());
}

Use this somewhere on server start to feed the random generator seed:
::srand((::GetTickCount() % ::time()) / 3);
Example:
for (local i = 0; i < 10; ++i)
{
print(GenerateRandomStr(64));
print("----------------------------------------------------------------");
}

Possible output:
[SCRIPT]  6x8nznXwLPdU\E~Tz!*q5"c'RqCmw#d~_vFT"!is4H85]z1{AgIM)W!}~:9iw_r)
[SCRIPT]  ----------------------------------------------------------------
[SCRIPT]  0/>$Y\u4Un)=nJ&Epf{4Y.>kgZUtz[WdA8FXD#P%%at9nIZ-y=M!-k`TO\;L;gcx
[SCRIPT]  ----------------------------------------------------------------
[SCRIPT]  R5<Q^_s;'*[email protected]/6>hr&e|RC>(/-BRX+W?IKXo\UIyL0&gCNeZCuQZ?K
[SCRIPT]  ----------------------------------------------------------------
[SCRIPT]  uRL_*\(Ng3.N5[<>'y/Gc/Vt>og-|TXm:c6Zaz{iaw!po<oQ6U`}/x|vcZ.}M-qJ
[SCRIPT]  ----------------------------------------------------------------
[SCRIPT]  /(}Mdn&J|o<O:rw[xx5B"\!C"So0@[CgR+Yy~e~#<>{[>T1B#:4*'&|]OSn<mTX$
[SCRIPT]  ----------------------------------------------------------------
[SCRIPT]  y+Pl]<E_YkGg@UMC1=#JX{/8Uqjr6D-3-Rx#&9/^xX?.B7J?2"d:fLUtVesI4hq^
[SCRIPT]  ----------------------------------------------------------------
[SCRIPT]  7ZAC`AJ+/\*W;Xm1;N{%,muG8}>}#aA9e!s6$~Wfty<2Yz%Gi_)oJe!BS:lnJ(,^
[SCRIPT]  ----------------------------------------------------------------
[SCRIPT]  ,7Eg0fps+6V/n]B5De{)b_fdE:+x]X^PVG&Bm;(_oNpML<g[36yM.W/VstLOQJrf
[SCRIPT]  ----------------------------------------------------------------
[SCRIPT]  HrrKRh0?9ynsg~B$%Z<F2,,%hz*:p],~8a&WOv+P:cDkt`AHU!:d}cK+K_@[sQkW
[SCRIPT]  ----------------------------------------------------------------
[SCRIPT]  ufz&.~/<,g#MRs38.83?`[L=+Ti&]s?X\LI"}R4Uqy?6>rt-Wjm3JfL*bD98v854
[SCRIPT]  ----------------------------------------------------------------

I usually pass the resulted string through the MD5(...) function to avoid having all those nasty characters. But they offer a good base for some random data.

Something like:
print( MD5( GenerateRandomStr(32) ) );
Which makes the output nicer:
[SCRIPT]  53CD561F2C53D00F13F3612392E44C2B
.

DizzasTeR


KAKAN

oh no

FinchDon

Bro Good Work But @S.L.C is this function will say password in encryption like? i think
For any help and support Join #s-s at IRC for Help in Scripting
( For Newbies )

Xmair


Credits to Boystang!

VU Full Member | VCDC 6 Coordinator & Scripter | EG A/D Contributor | Developer of VCCNR | Developer of KTB | Ex-Scripter of EAD

MatheuS

if( !sucess ) tryAgain();
Thanks to the VCMP community. It was the happiest period of my life.

.

#6
Let me explain what is a password salt because some of us might not know that (one in particular). A password salt is a really, really random string with a fixed size that is combined with the user password right before the encryption is performed. Making the password even stronger.

Let's give an example by trying to encrypt the password "mAzeLtov". And now I'm going to use that function to generate a really random string. Assuring me that there won't be any other salt like this one and if there is the chances are 1 in a few millions (billions depending on the length).

Let's begin with the dummy password:
local pass = "mAzeLtov";
Now let's generate the random string:
local salt = GenerateRandomStr(64);
And let's assume that this is the output:
Ewx;+?o9bH`"|6r%BoXCQ\+e@+i^z-.gto&j69B>5b"[($V'j)MN0ll\r;#<'Y';
Quite random isn't it? Great, but I don't like having all those symbols in my salt. I want a clean alpha-numeric salt. So what do we do now? We hash that random string.

So let's hash the generated string:
salt = MD5(salt);
For that particular string above the resulted hash will be:
4C6037453B35453A207C1A30741B3409
Very clean and very random isn't it? So what now? Now we add the salt before our password:
pass = (salt + pass);
The result should be something like:
4C6037453B35453A207C1A30741B3409mAzeLtov
Now we hash the password resulted from the concatenation of the user password and the salt to get the actual encrypted password:
local hash = SHA256(pass);
And we should get this:
118D0A54144C8D0FDC128B61458E12AA40C4CAB531F95250468FBF539B243339
This time we used an even stronger hashing algorithm. And if you are a really paranoid person you could also perform a multi-pass encryption on the resulted hash:
for (local i = 0; i < 10; ++i)
{
    hash = SHA256(hash);
}

Resulting in something like:
147DFE6A7123683AB4FB9D59EDDCA1F10B11D45D28FD37762975A3E27C3FC3F2
And this pretty much gives you an overkill password encryption. And now you save the salt and the password hash to the database and on each player login you retrieve the salt and the hash and perform the same operation again for the specified password and compare the resulted hashes to see if the passwords match.
.

KAKAN

Woa, NICE explanation, THis will help many newbies for sure
oh no

Thijn

I don't get how having a random salt saved alongside the encrypted password makes it any safer. A salt hardcoded in the code looks more secure since you would need to steal both the database and script. Care to explain? :)

.

Quote from: Thijn on Aug 31, 2015, 07:21 PMCare to explain? :)

If you reach the database then you obviously reached the script first. In the case of MySql you have the password hardcoded in the script and thus you need to get to the script first. And the SQLite story is quite obvious. What you need is a unique salt for each user in your database.

But if you truly want the best of both worlds. You could (literally) do that. Include a salt in the database and a hardcoded pepper in the script.

In the script you could add:
const PASSWORD_PEPPER = "53CD561F2C53D00F13F3612392E44C2B";
And change:
pass = (salt + pass);
To:
pass = (PASSWORD_PEPPER + salt + pass);
That way, you need to compromise both the database and the script to have something. But either way, this is usually enough for our VC:MP community. You of all people should know best ;D
.

EK.IceFlake


KAKAN

1st it was salt, but now its with pepper
oh no

.

Sorry people. That's the therm. Imagine it like this. The more salt and pepper you put on it the harder is going to be for the attacker to digest. Makes sense if you think about it.
.

KAKAN

:P we know, this would be very useful, atleast for VCMP, without that also SHA256 is cryptographic, so what's the need of a salt? I know it'll make the SHA256 code more powerfull
oh no

.

#14
Quote from: KAKAN on Sep 04, 2015, 11:42 AM...so what's the need of a salt?...

The way I see it is to prevent common passwords from being easilly cracked. Having a password like "123456" or "qwerty" (I've seen lots of people using these!) could be easily cracked when trying any common passwords. But when you combine that with a salt and pepper it suddenly becomes "4C6037453B35453A207C1A30741B340953CD561F2C53D00F13F3612392E44C2Bquerty". Now try and crack that without compromising both the database and script to extract the two key segments from the password. And after you've compromised that you have to add them before every password that you might brute-force your way into. And you can kiss goodbye from your rainbow tables. And pretty much you've converted a dummy password into a spartan one. And when you finish it with the multi-pass hashing you've pretty much made your attacker cry a bit. Because he must decrypt through an arbitrary levels of hashes to get to the actual hash and then decrypt that as well.

Well, this was supposed to be about generating a random string but I noticed it became something different. TBH it is not my concern how you protect your passwords. You can save them as plain text if that's what you desire even though not recommended.
.