Show DevBest Noncify

Markshall

Русский Стандарт
Contributor
Dec 18, 2010
2,637
2,389
I needed a nonce-generating script for a project I'm working on at work and this is what I ended up with.

Feel free to use.



PHP:
<?php
/**
  * @name  Noncify
  * @author  Mark Eriksson (https://markwrites.codes)
  * @link  https://github.com/Markshall/Noncify
  * @desc  Generate and verify previously generated nonces for use in web forms
  */
class Noncify {
  
  /**
    * @param $key  the salt being used by the website
    * @param $timeout  the amount of time (in minutes) after which the nonce will expire. if value is not supplied, the default of 5 will be used
    * @return string  the generated nonce
    */
  public static function generate($key, $timeout=5) {
    if (!is_string($key) || !is_numeric($timeout)) {
      throw new InvalidArgumentException('Invalid arguments supplied');
    }
    
    return sha1($key) . '.' . ($timestamp=time()+($timeout*60)) . '.' . ($salt=self::randString($timeout)) . '.' . sha1("{$salt}.{$timestamp}.{$key}");
  }
  
  
  /**
    * @param $nonce  the full nonce string created by this class
    * @param $key  the salt passed into generate() used by the website
    * @return bool  if the nonce is valid and not expired
    */
  public static function verify($nonce, $key) {
    list($nonceStart, $timeout, $salt, $hash) = explode('.', $nonce);
    return sha1($key) === $nonceStart && time() < $timeout && sha1("{$salt}.{$timeout}.{$key}") === $hash;
  }
  
  
  /**
    * @param $length  the amount of characters to be used in the random string
    *                 not user defined. value is based on the $timeout param in generate()
    *                 we divide the $timeout param by 4 and if its value is less than 8 then
    *                 make the random string 8 chars long
    * @return string  the randomly generated string
    */
  private static function randString($length) {
    $chars   = '1QAZ2WSX3EDC4RFV5TGB6YHN7UJM8IK9OL0Pqazwsxedcrfvtgbyhnujmikolp';
    $string  = '';
    $length /= 4;
    
    if (strval($length) < 8) $length = 8;
    
    for ($i=0; $i<round($length); $i++) $string .= $chars[mt_rand(0, strlen($chars)-1)];
    
    return $string;
  }
}

Usage:
PHP:
<?php
require_once('Noncify.php');

define('NONCE_SALT', 'f7H4gx88ZaqwM3'); // you'd probably store this in a config file or in a database

$nonce = Noncify::generate(NONCE_SALT, 3); // generates a nonce salt that expires after 3 minutes

// the verify() method must be provided the same nonce salt that you passed through to generate()
if (Noncify::verify($nonce, NONCE_SALT)) {
  echo 'Verified!';
} else {
  echo 'Wrong salt key supplied, or nonce has expired.';
}
 
Last edited:

n4te

zzz
Oct 27, 2014
669
293
I needed a nonce-generating script for a project I'm working on at work and this is what I ended up with.

Feel free to use.



PHP:
<?php
/**
  * @name  Noncify
  * @author  Mark Eriksson (https://markwrites.codes)
  * @link  https://github.com/Markshall/Noncify
  * @desc  Generate and verify previously generated nonces for use in web forms
  */
class Noncify {
 
  /**
   * @param $key  the salt being used by the website
   * @param $timeout  the amount of time (in minutes) after which the nonce will expire
   * @return string  the generated nonce
   */
  public static function generate($key, $timeout=5) {
   if (!is_string($key) || !is_numeric($timeout)) {
     throw new InvalidArgumentException('Invalid arguments supplied');
   }
  
   $salt = self::randString($timeout);
  
   $nonce = substr(sha1($key), 0, 15) . '.' . (time()+($timeout*60)) . '.' . $salt . '.' . sha1($salt . $key);
   return $nonce;
  }
 
 
  /**
   * @param $nonce  the full nonce string created by this class
   * @param $key  the salt passed into generate() used by the website
   * @return bool  if the nonce is valid and not expired
   */
  public static function verify($nonce, $key) {
   $nonceBits = explode('.', $nonce);
  
   return substr(sha1($key), 0, 15) === $nonceBits[0] && time() < $nonceBits[1] && sha1($nonceBits[2] . $key) === $nonceBits[3];
  }
 
 
  /**
   * @param $length  the amount of characters to be used in the random string
   *                 not user defined. value is based on the $timeout param in generate()
   *                 we divide the $timeout param by 4 and if its value is less than 8 then
   *                 make the random string 8 chars long
   * @return string  the randomly generated string
   */
  private static function randString($length) {
   $chars   = '1QAZ2WSX3EDC4RFV5TGB6YHN7UJM8IK9OL0Pqazwsxedcrfvtgbyhnujmikolp';
   $string  = '';
   $length /= 4;
  
   if (strval($length) < 8)
     $length = 8;
  
   for ($i=0; $i<round($length); $i++)
     $string .= $chars[mt_rand(0, strlen($chars)-1)];
  
   return $string;
  }
}

Usage:
PHP:
<?php
require_once('Noncify.php');

define('NONCE_SALT', 'f7H4gx88ZaqwM3'); // you'd probably store this in a config file or in a database

$nonce = Noncify::generate(NONCE_SALT, 3); // generates a nonce salt that expires after 3 minutes

// the verify() method must be provided the same nonce salt that you passed through to generate()
if (Noncify::verify($nonce, NONCE_SALT)) {
  echo 'Verified!';
} else {
  echo 'Wrong salt key supplied, or nonce has expired.';
}
You're always creating cool and useful stuff to share with us. Kudos man.
 

Adil

DevBest CEO
May 28, 2011
1,276
713
When I saw nonce I thought you were referring to the Jimmy Savile variety... :lol:

Nice work Mark :cool:
 

Markshall

Русский Стандарт
Contributor
Dec 18, 2010
2,637
2,389
You're always creating cool and useful stuff to share with us. Kudos man.
Cheers man, this site needs more development threads going... or just threads in general to be honest, so just doing my bit.

When I saw nonce I thought you were referring to the Jimmy Savile variety... :lol:

Nice work Mark :cool:
Haha, can't say it would be a surprise if that was the caseSoBayed
 

n4te

zzz
Oct 27, 2014
669
293
Cheers man, this site needs more development threads going... or just threads in general to be honest, so just doing my bit.


Haha, can't say it would be a surprise if that was the caseSoBayed
Yeah, no doubt. I always check your stuff out when you create a thread.
 

RastaLulz

fight teh power
Staff member
May 3, 2010
3,926
3,920
Opened a so that the client can't modify the timestamp.

Out of curiosity, what is the first part of the nonce (substr(sha1($key), 0, 15)) attempting to accomplish, that the last part doesn't? At first glance it seems redundant.

For open source related stuff (and in general), I'd recommend following and ; this makes it easier for contributors.
 

Markshall

Русский Стандарт
Contributor
Dec 18, 2010
2,637
2,389
Opened a so that the client can't modify the timestamp.

Out of curiosity, what is the first part of the nonce (substr(sha1($key), 0, 15)) attempting to accomplish, that the last part doesn't? At first glance it seems redundant.

For open source related stuff (and in general), I'd recommend following and ; this makes it easier for contributors.
Nothing per-se, it’s just to obscure it a little more.

And thanks for the PR, can’t believe I overlooked that. But nothing is perfect first time around is it!?
 
Last edited:

M8than

yes
Mar 16, 2012
463
102
'.' . ($salt=self::randString($timeout)) . '.' .

Isn't this just adding the word true to the string?
 

Markshall

Русский Стандарт
Contributor
Dec 18, 2010
2,637
2,389
'.' . ($salt=self::randString($timeout)) . '.' .

Isn't this just adding the word true to the string?
No, it’s self-assigning a variable whilst concatenating it to the string simultaneously.

It prints it to the string at the same time as assigning it as a variable so I can use it later on. What you’re thinking of is this:

PHP:
'.' . ($salt==self::randString($timeout)) . '.' .
The extra = symbol. Which would echo out false in this case, since $salt is previously undefined so would have no value and would therefore not match the value of self::randString($timeout)
 

Markshall

Русский Стандарт
Contributor
Dec 18, 2010
2,637
2,389
I'm not actually thinking of that, I'm think of if you do an if ($a = $b) it will always be true.
It would do if I had an 'if' beforehand. It would cause an error anyway because I'm not giving a result of the if statement.

It's assigning $salt a random string, placing that in the string, and then using it later on down the line in sha1("{$salt}.{$timestamp}.{$key}")
$salt
is being called from when it was assigned at $salt=self::randString($timeout)
 

Users who are viewing this thread

Top