forked from phalcon/cphalcon
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Showing
1 changed file
with
274 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,274 @@ | ||
/* | ||
+------------------------------------------------------------------------+ | ||
| Phalcon Framework | | ||
+------------------------------------------------------------------------+ | ||
| Copyright (c) 2011-2015 Phalcon Team (http://www.phalconphp.com) | | ||
+------------------------------------------------------------------------+ | ||
| This source file is subject to the New BSD License that is bundled | | ||
| with this package in the file docs/LICENSE.txt. | | ||
| | | ||
| If you did not receive a copy of the license and are unable to | | ||
| obtain it through the world-wide-web, please send an email | | ||
| to license@phalconphp.com so we can send you a copy immediately. | | ||
+------------------------------------------------------------------------+ | ||
| Authors: Serghei Iakovlev <sadhooklay@gmail.com> | | ||
+------------------------------------------------------------------------+ | ||
*/ | ||
|
||
namespace Phalcon\Security; | ||
|
||
/** | ||
* Phalcon\Security\Random | ||
* | ||
* Secure random number generator class. | ||
* | ||
* Provides secure random number generator which is suitable for generating | ||
* session key in HTTP cookies, etc. | ||
* | ||
* It supports following secure random number generators: | ||
* | ||
* - libsodium | ||
* - openssl | ||
* - /dev/urandom | ||
* | ||
*<code> | ||
* $random = new \Phalcon\Security\Random(); | ||
* | ||
* // Random binary string | ||
* $bytes = $random->bytes(); | ||
* | ||
* // Random hex string | ||
* echo $random->hex(10); // a29f470508d5ccb8e289 | ||
* echo $random->hex(10); // 533c2f08d5eee750e64a | ||
* echo $random->hex(11); // f362ef96cb9ffef150c9cd | ||
* echo $random->hex(12); // 95469d667475125208be45c4 | ||
* echo $random->hex(13); // 05475e8af4a34f8f743ab48761 | ||
* | ||
* // Random base64 string | ||
* echo $random->base64(12); // XfIN81jGGuKkcE1E | ||
* echo $random->base64(12); // 3rcq39QzGK9fUqh8 | ||
* echo $random->base64(); // DRcfbngL/iOo9hGGvy1TcQ== | ||
* echo $random->base64(16); // SvdhPcIHDZFad838Bb0Swg== | ||
* | ||
* // Random URL-safe base64 string | ||
* echo $random->base64Safe(); // PcV6jGbJ6vfVw7hfKIFDGA | ||
* echo $random->base64Safe(); // GD8JojhzSTrqX7Q8J6uug | ||
* echo $random->base64Safe(8); // mGyy0evy3ok | ||
* echo $random->base64Safe(null, true); // DRrAgOFkS4rvRiVHFefcQ== | ||
* | ||
* // Random UUID | ||
* echo $random->uuid(); // db082997-2572-4e2c-a046-5eefe97b1235 | ||
* echo $random->uuid(); // da2aa0e2-b4d0-4e3c-99f5-f5ef62c57fe2 | ||
* echo $random->uuid(); // 75e6b628-c562-4117-bb76-61c4153455a9 | ||
* echo $random->uuid(); // dc446df1-0848-4d05-b501-4af3c220c13d | ||
* | ||
* // Random number between 0 and $len | ||
* echo $random->number(256); // 84 | ||
* echo $random->number(256); // 79 | ||
* echo $random->number(100); // 29 | ||
* echo $random->number(300); // 40 | ||
*</code> | ||
* | ||
* This class partially borrows SecureRandom library from Ruby | ||
* | ||
* @link http://ruby-doc.org/stdlib-2.2.2/libdoc/securerandom/rdoc/SecureRandom.html | ||
*/ | ||
class Random | ||
{ | ||
/** | ||
* Generates a random binary string | ||
* | ||
* If $len is not specified, 16 is assumed. It may be larger in future. | ||
* The result may contain any byte: "x00" - "xFF". | ||
* | ||
*<code> | ||
* $random = new \Phalcon\Security\Random(); | ||
* | ||
* $bytes = $random->bytes(); | ||
*</code> | ||
* | ||
* @throws Exception If secure random number generator is not available or unexpected partial read | ||
*/ | ||
public function bytes(int len = null) -> string | ||
{ | ||
var n, handle, ret; | ||
|
||
if !len { | ||
let n = 16; | ||
} else { | ||
let n = len; | ||
} | ||
|
||
if function_exists("\\Sodium\\randombytes_buf") { | ||
return \\Sodium\\randombytes_buf(n); | ||
} | ||
|
||
if function_exists("openssl_random_pseudo_bytes") { | ||
return openssl_random_pseudo_bytes(n); | ||
} | ||
|
||
if file_exists("/dev/urandom") { | ||
let handle = fopen("/dev/urandom", "rb"); | ||
|
||
if handle !== false { | ||
stream_set_read_buffer(handle, 0); | ||
let ret = fread(handle, n); | ||
fclose(handle); | ||
|
||
if strlen(ret) != n { | ||
throw new Exception("Unexpected partial read from random device"); | ||
} | ||
|
||
return ret; | ||
} | ||
} | ||
|
||
throw new Exception("No random device"); | ||
} | ||
|
||
/** | ||
* Generates a random hex string | ||
* | ||
* If $len is not specified, 16 is assumed. It may be larger in future. | ||
* The length of the result string is usually greater of $len. | ||
* By default, padding is not generated because "=" may be used as a URL delimiter. | ||
* | ||
*<code> | ||
* $random = new \Phalcon\Security\Random(); | ||
* | ||
* echo $random->hex(10); // a29f470508d5ccb8e289 | ||
*</code> | ||
* | ||
* @throws Exception If secure random number generator is not available or unexpected partial read | ||
*/ | ||
public function hex(int len = null) -> string | ||
{ | ||
return array_shift(unpack("H*", this->bytes(len))); | ||
} | ||
|
||
/** | ||
* Generates a random base64 string | ||
* | ||
* If $len is not specified, 16 is assumed. It may be larger in future. | ||
* The length of the result string is usually greater of $len. | ||
* | ||
*<code> | ||
* $random = new \Phalcon\Security\Random(); | ||
* | ||
* echo $random->base64(12); // 3rcq39QzGK9fUqh8 | ||
*</code> | ||
* | ||
* @throws Exception If secure random number generator is not available or unexpected partial read | ||
*/ | ||
public function base64(int len = null) -> string | ||
{ | ||
return base64_encode(this->bytes(len)); | ||
} | ||
|
||
/** | ||
* Generates a random URL-safe base64 string | ||
* | ||
* If $len is not specified, 16 is assumed. It may be larger in future. | ||
* The length of the result string is usually greater of $len. | ||
* | ||
* By default, padding is not generated because "=" may be used as a URL delimiter. | ||
* The result may contain A-Z, a-z, 0-9, "-" and "_". "=" is also used if $padding is true. | ||
* See RFC 3548 for the definition of URL-safe base64. | ||
* | ||
*<code> | ||
* $random = new \Phalcon\Security\Random(); | ||
* | ||
* echo $random->base64Safe(); // GD8JojhzSTrqX7Q8J6uug | ||
*</code> | ||
* | ||
* @link https://www.ietf.org/rfc/rfc3548.txt | ||
* @throws Exception If secure random number generator is not available or unexpected partial read | ||
*/ | ||
public function base64Safe(int len = null, boolean padding = false) -> string | ||
{ | ||
var s; | ||
|
||
let s = preg_replace("#[^a-z0-9_=-]+#i", "", this->base64(len)); | ||
|
||
if !padding { | ||
return trim(s, "="); | ||
} | ||
|
||
return s; | ||
} | ||
|
||
/** | ||
* Generates a v4 random UUID (Universally Unique IDentifier) | ||
* | ||
* The version 4 UUID is purely random (except the version). It doesn't contain meaningful | ||
* information such as MAC address, time, etc. See RFC 4122 for details of UUID. | ||
* | ||
* This algorithm sets the version number (4 bits) as well as two reserved bits. | ||
* All other bits (the remaining 122 bits) are set using a random or pseudorandom data source. | ||
* Version 4 UUIDs have the form xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx where x is any hexadecimal | ||
* digit and y is one of 8, 9, A, or B (e.g., f47ac10b-58cc-4372-a567-0e02b2c3d479). | ||
* | ||
*<code> | ||
* $random = new \Phalcon\Security\Random(); | ||
* | ||
* echo $random->uuid(); // 1378c906-64bb-4f81-a8d6-4ae1bfcdec22 | ||
*</code> | ||
* | ||
* @link https://www.ietf.org/rfc/rfc4122.txt | ||
* @throws Exception If secure random number generator is not available or unexpected partial read | ||
*/ | ||
public function uuid() -> string | ||
{ | ||
var ary; | ||
|
||
let ary = array_values(unpack("N1a/n1b/n1c/n1d/n1e/N1f", this->bytes(16))); | ||
let ary[2] = (ary[2] & 0x0fff) | 0x4000; | ||
let ary[3] = (ary[3] & 0x3fff) | 0x8000; | ||
|
||
array_unshift(ary, "%08x-%04x-%04x-%04x-%04x%08x"); | ||
|
||
return call_user_func_array("sprintf", ary); | ||
} | ||
|
||
/** | ||
* Generates a random number between 0 and $len | ||
* | ||
*<code> | ||
* $random = new \Phalcon\Security\Random(); | ||
* | ||
* echo $random->number(16); // 8 | ||
*</code> | ||
* @throws Exception If secure random number generator is not available, unexpected partial read or $len <= 0 | ||
*/ | ||
public function number(int len) -> int | ||
{ | ||
var hex, bin, mask, rnd, ret, first; | ||
|
||
if len > 0 { | ||
let hex = dechex(len); | ||
|
||
if (strlen(hex) & 1) == 1 { | ||
let hex = "0" . hex; | ||
} | ||
|
||
let bin = pack("H*", hex); | ||
|
||
let mask = ord(substr(bin, 0, 1)); | ||
let mask = mask | (mask >> 1); | ||
let mask = mask | (mask >> 2); | ||
let mask = mask | (mask >> 4); | ||
|
||
do { | ||
let rnd = this->bytes(strlen(bin)); | ||
let first = ord(substr(rnd, 0, 1)); | ||
let rnd = substr_replace(rnd, chr(first & mask), 0, 1); | ||
} while (bin < rnd); | ||
|
||
let ret = unpack("H*", rnd); | ||
|
||
return hexdec(array_shift(ret)); | ||
} | ||
|
||
throw new Exception("Require a positive integer > 0"); | ||
} | ||
} |