random_int generating values less than minimum - php

I am generating passwords with random_int, but I noticed something weird. Sometimes (purely random), it generates a password less than the minimum value. For example, I set 10 and 15 the limits and once every circa 50-70 tries it pops out a 2-3 character long password. Is there something wrong with my script? It's hard to reproduce the output, just refresh the script till you get a similar result.
<?php
$r_number = random_int( 10 , 15 );
function random_str(
$length,
$keyspace = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ,./<>?;:"|[]{}-=_+`~!##$%^&*'
) {
$str = '';
$max = mb_strlen($keyspace, '8bit') - 1;
if ($max < 1) {
throw new Exception('$keyspace must be at least two characters long');
}
for ($i = 0; $i < $length; ++$i) {
$str .= $keyspace[random_int(0, $max)];
}
return $str;
}
$password = random_str($r_number);
echo $password;
?>

Going on a limb here, but...
If the generated password happens to include < - which is in your default $keyspace - and you are viewing the results in a browser, then the < is treated as the start of an HTML tag and won't be displayed, nor will anything after it unless a > happens to be chosen.
That's the only thing I can think of that would be causing this. Try echo htmlspecialchars($password); to output it.

Related

Timing attack with PHP

I'm trying to produce a timing attack in PHP and am using PHP 7.1 with the following script:
<?php
$find = "hello";
$length = array_combine(range(1, 10), array_fill(1, 10, 0));
for ($i = 0; $i < 1000000; $i++) {
for ($j = 1; $j <= 10; $j++) {
$testValue = str_repeat('a', $j);
$start = microtime(true);
if ($find === $testValue) {
// Do nothing
}
$end = microtime(true);
$length[$j] += $end - $start;
}
}
arsort($length);
$length = key($length);
var_dump($length . " found");
$found = '';
$alphabet = array_combine(range('a', 'z'), array_fill(1, 26, 0));
for ($len = 0; $len < $length; $len++) {
$currentIteration = $alphabet;
$filler = str_repeat('a', $length - $len - 1);
for ($i = 0; $i < 1000000; $i++) {
foreach ($currentIteration as $letter => $time) {
$testValue = $found . $letter . $filler;
$start = microtime(true);
if ($find === $testValue) {
// Do nothing
}
$end = microtime(true);
$currentIteration[$letter] += $end - $start;
}
}
arsort($currentIteration);
$found .= key($currentIteration);
}
var_dump($found);
This is searching for a word with the following constraints
a-z only
up to 10 characters
The script finds the length of the word without any issue, but the value of the word never comes back as expected with a timing attack.
Is there something I am doing wrong?
The script loops though lengths, correctly identifies the length. It then loops though each letter (a-z) and checks the speed on these. In theory, 'haaaa' should be slightly slower than 'aaaaa' due to the first letter being a h. It then carries on for each of the five letters.
Running gives something like 'brhas' which is clearly wrong (it's different each time, but always wrong).
Is there something I am doing wrong?
I don't think so. I tried your code and I too, like you and the other people who tried in the comments, get completely random results for the second loop. The first one (the length) is mostly reliable, though not 100% of the times. By the way, the $argv[1] trick suggested didn't really improve the consistency of the results, and honestly I don't really see why it should.
Since I was curious I had a look at the PHP 7.1 source code. The string identity function (zend_is_identical) looks like this:
case IS_STRING:
return (Z_STR_P(op1) == Z_STR_P(op2) ||
(Z_STRLEN_P(op1) == Z_STRLEN_P(op2) &&
memcmp(Z_STRVAL_P(op1), Z_STRVAL_P(op2), Z_STRLEN_P(op1)) == 0));
Now it's easy to see why the first timing attack on the length works great. If the length is different then memcmp is never called and therefore it returns a lot faster. The difference is easily noticeable, even without too many iterations.
Once you have the length figured out, in your second loop you are basically trying to attack the underlying memcmp. The problem is that the difference in timing highly depends on:
the implementation of memcmp
the current load and interfering processes
the architecture of the machine.
I recommend this article titled "Benchmarking memcmp for timing attacks" for more detailed explanations. They did a much more precise benchmark and still were not able to get a clear noticeable difference in timing. I'm simply going to quote the conclusion of the article:
In conclusion, it highly depends on the circumstances if a memcmp() is subject to a timing attack.

Random generator returning endless duplicates

I am trying to create a random string which will be used as a short reference number. I have spent the last couple of days trying to get this to work but it seems to get to around 32766 records and then it continues with endless duplicates. I need at minimum 200,000 variations.
The code below is a very simple mockup to explain what happens. The code should be syntaxed according to 1a-x1y2z (example) which should give a lot more results than 32k
I have a feeling it may be related to memory but not sure. Any ideas?
<?php
function createReference() {
$num = rand(1, 9);
$alpha = substr(str_shuffle("abcdefghijklmnopqrstuvwxyz"), 0, 1);
$char = '0123456789abcdefghijklmnopqrstuvwxyz';
$charLength = strlen($char);
$rand = '';
for ($i = 0; $i < 6; $i++) {
$rand .= $char[rand(0, $charLength - 1)];
}
return $num . $alpha . "-" . $rand;
}
$codes = [];
for ($i = 1; $i <= 200000; $i++) {
$code = createReference();
while (in_array($code, $codes) == true) {
echo 'Duplicate: ' . $code . '<br />';
$code = createReference();
}
$codes[] = $code;
echo $i . ": " . $code . "<br />";
}
exit;
?>
UPDATE
So I am beginning to wonder if this is not something with our WAMP setup (Bitnami) as our local machine gets to exactly 1024 records before it starts duplicating. By removing 1 character from the string above (instead of 6 in the for loop I make it 5) it gets to exactly 32768 records.
I uploaded the script to our centos server and had no duplicates.
What in our enviroment could cause such a behaviour?
The code looks overly complex to me. Let's assume for the moment you really want to create n unique strings each based on a single random value (rand/mt_rand/something between INT_MIN,INT_MAX).
You can start by decoupling the generation of the random values from the encoding (there seems to be nothing in the code that makes a string dependant on any previous state - excpt for the uniqueness). Comparing integers is quite a bit faster than comparing arbitrary strings.
mt_rand() returns anything between INT_MIN and INT_MAX, using 32bit integers (could be 64bit as well, depends on how php has been compiled) that gives ~232 elements. You want to pick 200k, let's make it 400k, that's ~ a 1/10000 of the value range. It's therefore reasonable to assume everything goes well with the uniqueness...and then check at a later time. and add more values if a collision occured. Again much faster than checking in_array in each iteration of the loop.
Once you have enough values, you can encode/convert them to a format you wish. I don't know whether the <digit><character>-<something> format is mandatory but assume it is not -> base_convert()
<?php
function unqiueRandomValues($n) {
$values = array();
while( count($values) < $n ) {
for($i=count($values);$i<$n; $i++) {
$values[] = mt_rand();
}
$values = array_unique($values);
}
return $values;
}
function createReferences($n) {
return array_map(
function($e) {
return base_convert($e, 10, 36);
},
unqiueRandomValues($n)
);
}
$start = microtime(true);
$references = createReferences(400000);
$end = microtime(true);
echo count($references), ' ', count(array_unique($references)), ' ', $end-$start, ' ', $references[0];
prints e.g. 400000 400000 3.3981630802155 f3plox on my i7-4770. (The $end-$start part is constantly between 3.2 and 3.4)
Using base_convert() there can be strings like li10, which can be quite annoying to decipher if you have to manually type the string.

Advanced Algoithm issues to generate unique 6 char long code

I have used this algorithm to generate 100 codes. Now Once again i have searched the threads on this site and on google before posting. The algorthms found do work in generating the code the issue I got is i have to generate UNIQUE codes from the one i already have. The problem i am finding is all the scripts are all failing to execute.
So basically I have an ARRAY holding 100 voucher codes I need to generate 400 more voucher codes however while my algorithm's works it keeps timing out due to it taking to long to execute. I have tried several other algorithms from the threads on Stack overflow but for some reason they all keep timing out. I need advice on what I can do to my algorithm to actually produce 400 more unique 6 Char codes.
Here is script I have
/**
**Use this portion to get my current 100 codes in an array which i use
**/
$redeem = 'THIS IS A STRING WHICH CREATES AN ARRAY CONTIANING 100 VALUES';
$redeem = preg_replace('/\s+/', '', $redeem);
$redeem_code = str_split($redeem, 6);
/**
**Function generates unique 6 letter voucher codes
**
**/
function random_str($length, $keyspace = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ')
{
$str = '';
$max = mb_strlen($keyspace, '8bit') - 1;
for ($i = 0; $i < $length; ++$i) {
$str .= $keyspace[mt_rand(0, $max)];
}
return $str;
}
/**
**This is the query which checks against my array and then echo's a valid code
**
**/
$redeem_count = count($redeem_code);
$i = 0;
$ia = 1;
while($i <= 500){
$string = random_str(6);
if(in_array($string, $redeem_code))
{
echo $string;
$i= $i+1;
}
}
Constant Error Message on All functions tried.
Fatal error: Maximum execution time of 120 seconds exceeded in C:\wamp\www\nfr_chip.php on line 115
You never add anything to the array and only increase $i if the code already exist.
This should work...
$redeem_count = count($redeem_code);
while($redeem_count <= 500) {
$string = random_str(6);
if(!in_array($string, $redeem_code))
{
$redeem_code[] = $string;
$redeem_count++;
}
}
And for the way you are splitting your string with codes, instead of using preg_replace (avoid regex unless you really need it):
$redeem_code = explode(" ", $redeem);
You can safely use openssl_random_pseudo_bytes with bin2hex to generate pseudo-random, as the name implies, strings.
Here's an example:
for ($i=1;$i<=5;$i++){
print bin2hex(openssl_random_pseudo_bytes(3)) . PHP_EOL;
}
//output
9282fb
3b9798
c187a0
a058e3
df2e4b
3 bytes will give you a 6 char string

How to save user-created content as a URL (hash) parameter?

I want to enable "Save" feature in my web app. I will send data to a PHP post receiver, and save the data in a MySQL row, so normally I can load it with its id like this:
site.com/content/123
But I want (just for the fancy looks) to use a "hash" (not sure if it's the right term) for this, like :
site.com/content/A2w7SqZ
just like jsFiddle does. How can I convert the id (integer) to a hash?
Example :
http://jsfiddle.net/sfu24/
The only way I can think of is MD5. But it generates a very long string. I think 6 characters are more than enough.
So how can I make a hash system like jsfiddle?
Thanks for any help !
P.S. I'm sure this question has been asked million times. But I couldn't find it. If you know an already-existing answer, please post the link and I will delete the question.
to generate random chars
function generate_random($length = 10) {
$characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
$randomString = '';
for($i = 0; $i < $length; $i ++) {
$randomString .= $characters [rand ( 0, strlen ( $characters ) - 1 )];
}
return $randomString;
}
Take a look as base_convert()
or the hashids
which will help you generate short hashes from numbers (like YouTube and Bitly).
function generateHash($int) {
$rand_letters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
$newstr = '';
for ($i = 0; $i < strlen($int); $i++) {
$newstr .= $rand_letters[rand(0, strlen($rand_letters)-1)];
}
return $newstr;
}
function myHash($int) {
$newstr = generateHash($int);
$result = $db->query("SELECT COUNT(*) FROM hashes WHERE hash = '$newstr';");
if ($result->num_rows > 0) {
myHash($int);
}
return $newstr;
}
echo myHash(973451);
You generate string on the base of the length of your passed integer. That's what generateHash() does. And myHash() uses this string, if it's already present, runs itself again, until generate not-present string, so returns it.
The hashes are random, so they are not straight reversable (they still can be), but "12345" will not result in one and the same string everytime.

Run A PHP function only 30% of Time

I need help creating PHP code to echo and run a function only 30% of the time.
Currently I have code below but it doesn't seem to work.
if (mt_rand(1, 3) == 2)
{
echo '';
theFunctionIWantCalled();
}
Are you trying to echo what the function returns? That would be
if(mt_rand(1,100) <= 30)
{
echo function();
}
What you currently have echoes a blank statement, then executes a function. I also changed the random statement. Since this is only pseudo-random and not true randomness, more options will give you a better chance of hitting it 30% of the time.
If you intended to echo a blank statement, then execute a function,
if(mt_rand(1,100) <= 30)
{
echo '';
function();
}
would be correct. Once again, I've changed the if-statement to make it more evenly distributed. To help insure a more even distribution, you could even do
if(mt_rand(1,10000) <= 3000)
since we aren't dealing with true randomness here. It's entirely possible that the algorithm is choosing one number more than others. As was mentioned in the comments of this question, since the algorithm is random, it could be choosing the same number over, and over, and over again. However, in practice, having more numbers to choose from will most likely result in an even distribution. Having only 3 numbers to choose from can skew the results.
Since you are using rand you can't guarantee it will be called 30% of the time. Where you could instead use modulus which will effectively give you 1/3 of the time, not sure how important this is for you but...
$max = 27;
for($i = 1; $i < $max; $i++){
if($i % 3 == 0){
call_function_here();
}
}
Since modulus does not work with floats you can use fmod, this code should be fairly close you can substitute the total iterations and percent...
$total = 50;
$percent = 0.50;
$calls = $total * $percent;
$interval = $total / $calls;
$called = 0;
$notcalled = 0;
for($i = 0; $i <= $total; $i++){
if(fmod($i, $interval) < 1){
$called++;
echo "Called" . "\n";
}else{
$notcalled++;
echo "Not Called" . "\n";
}
}
echo "Called: " . $called . "\n";
echo "Not Called: " . $notcalled . "\n";

Categories