I need fast way for generating random strings a-Z0-9 in PHP. I've been doing some thinking and testing, this is what I've got so far:
function randStr($length) {
$result = null;
$replace = array('/', '+', '=');
while(!isset($result[$length-1])) {
$result.= str_replace($replace, NULL, base64_encode(mcrypt_create_iv($length, MCRYPT_RAND)));
}
return substr($result, 0, $length);
}
Function seems to be working fast compared to functions which iterate and choose random ASCII value for each char, but I'm concerned with 'quality' of my implementation. I do not know much about cryptography, so I'd like to ask whether this kind of function creates 'good' random values or not.
mcrypt_create_iv seems to return some kind of random binary values, actually used for encrypting/decrypting data with mcrypt library. What is base64_encode effect on this kind of binary data, do I actually decrease entropy, when I base64_encode it?
How does second parameter for mcrypt_create_iv affect my results? php.net manual states that MCRYPT_RAND is 'system random number generator'. Is it OS specific and if so, how good values are created?
This supposed to be secure on most of the systems and fast:
bin2hex(openssl_random_pseudo_bytes($length / 2));
benchmarks (1000000 records, string length 100 chars)
rstr1: 198.93383002281
rstr2: 35.5827729702
rstr3: 6.8811790943146
rstr4: 5.4545040130615
this:: 3.9310231208801
For anyone looking for an updated version of the "best" algorithm:
function randomString($length) {
$result = null;
$replace = array('/', '+', '=');
while(!isset($result[$length-1])) {
$result.= str_replace($replace, NULL, base64_encode(random_bytes($length)));
}
return substr($result, 0, $length);
}
I use the term "best" because it is faster than the random string manipulations of rstr1 and rstr2 and in comparison to the other solutions offers a full spectrum of letters (lower- and uppercased).
From my tests, your function is already very fast, but i managed to get to a faster one, even if it decreases the entropy
fcn time
rstr1: 1.074s (slowest)
rstr2: 0.917s
rstr3: 0.028s (yours)
rstr4: 0.022s (mine)
In my scenario, i needed 1k strings, as fast as possible.
function rstr1($length)
{
// #see http://stackoverflow.com/a/853846/11301
$alphabet='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
return substr(str_shuffle(str_repeat($alphabet, $length)), 0, $length);
}
function rstr2($length)
{
// #see http://stackoverflow.com/a/853870/11301
$alphabet='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
$str = '';
$count = strlen($alphabet);
while ($length--) {
$str .= $alphabet[mt_rand(0, $count-1)];
}
return $str;
}
function rstr3($length) {
// #see http://stackoverflow.com/q/4757392/11301
$result = null;
$replace = array('/', '+', '=');
while(!isset($result[$length-1])) {
$result.= str_replace($replace, NULL, base64_encode(mcrypt_create_iv($length, MCRYPT_RAND)));
}
return substr($result, 0, $length);
}
function rstr4($length)
{
// uses md5 & mt_rand. Not as "random" as it could be, but it works, and its fastest from my tests
return str_shuffle(substr(str_repeat(md5(mt_rand()), 2+$length/32), 0, $length));
}
// test the functions
for($i=0; $i<1000; $i++){
#$x = rstr1(1024); #
#$x = rstr2(1024); # 0.917s
#$x = rstr3(1024); # 0.028s
#$x = rstr4(1024); # 0.022s
#dlog($x); return;
}
base64_encoding won't decrease entropy, it is just a different representation of the same data.
It is OS specific, but I think the random values created are good enough with this function. Under PHP 5.3 you have to seed the generator beforehand, it can be a problem if you use this code on different servers.
I usually work with this one.
Also I can choose if I don't want certain characters
function rstr5($length = 1) {
return substr(str_shuffle(str_repeat("0123456789abcdefghijklmnopqrstuvwxyz", $length)), 0, $length);
}
This is how I'm doing it, though it's not exactly cryptographic; The Mersenne Twister is fast and reliable, but not the most secure.
function str_rand($chars, $len)
{
$str = '';
for ($max = strlen($chars) - 1, $i = 0; $i < $len; ++$i)
{
$str .= $chars[mt_rand(0, $max)];
}
return $str;
}
$strRand = str_rand('0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ', 40);
Related
I want to make a personal algorithm for hashing texts in PHP. The letter 'a' crypt in 'xyz', 'b' in '256' and some more. How it's possible this?
It's possible by simple create a function that make characters substitution, like this:
function myEncrypt ($text)
{
$text = str_replace(array('a', 'b'), array('xby', '256'), $text);
// ... others
return $text;
}
version with two arrays "search" and "replaceWith" passed as arguments:
function myEncrypt ($text, $search=array(), $replaceWith=array())
{
return str_replace($search, $replaceWith, $text);
}
WARNING: That way isn't a correct solution to encrypt a text, there are a lot of better ways to do a secure encryption with PHP (see for example this post).
I'm bored at work so I thought i'd give this a crack.
This isn't secure at all. The crypt must be hard coded and the crypted character must have a size of 3.
<?php
//define our character->crypted text
$cryptArray = array( "a"=>"xyz","b"=>"256");
//This is our input
$string = "aab";
//Function to crypt the string
function cryptit($string,$cryptArray){
//create a temp string
$temp = "";
//pull the length of the input
$length = strlen($string);
//loop thru the characters of the input
for($i=0; $i<$length; $i++){
//match our key inside the crypt array and store the contents in the temp array, this builds the crypted output
$temp .= $cryptArray[$string[$i]];
}
//returns the string
return $temp;
}
//function to decrypt
function decryptit($string,$cryptArray){
$temp = "";
$length = strlen($string);
//Swap the keys with data
$cryptArray = array_flip($cryptArray);
//since our character->crypt is count of 3 we must $i+3 to get the next set to decrypt
for($i =0; $i<$length; $i = $i+3){
//read from the key
$temp .= $cryptArray[$string[$i].$string[$i+1].$string[$i+2]];
}
return $temp;
}
$crypted = cryptit($string,$cryptArray);
echo $crypted;
$decrypted = decryptit($crypted,$cryptArray);
echo $decrypted;
The input was : aab
The output is:
xyzxyz256
aab
Here's the 3v4l link:
https://3v4l.org/chR2A
Is there an existing function which can be implemented the same way as fread but for a string?
for example.
while($string = str_read($huge_string, 500)) {
echo strlen($string); // 500
}
My current code looks like this.
$length = 8192;
$array = str_split($xml, $length);
while($string = array_shift($array)){
if (! xml_parse($parser, $string, false))
{
return xml_error_string(xml_get_error_code($parser));
}
}
xml_parse($parser, '', true);
xml_parser_free($parser);
Is this the most efficient way of doing this or can it be improved to offer better performance ?
would using a $length of int_get('memory_limit'); be better as it will use less iterations ?
Using PHP, I'm trying to encode a number into another number that I can decode back to the original number. The encoded string needs to be only numbers and should not contain anything else.
Eg: 10 becomes 573563547892 or something like that.
How can I do something like this in PHP? I tried quite a few encrypt decrypt functions, but none output only numbers.
I looking for something to use in a URL that isn't easy to guess.
So: http://www.me.com/index.PHP?page=20 becomes http://www.me.com/index.PHP?page=5705254782562466
Why not using a mathematicat operation on the original number? like x becomes x * y + z. you would only have to make the reverse operation to get the original number. consider using large enough prime numbers for y and/or z
Quite heavy, but very good encryption, by using ord & chr a bit. While this works, consider other options: just being able to use strings rather then numbers already makes it a lot simpler (base64_encode etc.):
<?php
class Crypter {
private $key = '';
private $iv = '';
function __construct($key,$iv){
$this->key = $key;
$this->iv = $iv;
}
protected function getCipher(){
$cipher = mcrypt_module_open(MCRYPT_BLOWFISH,'','cbc','');
mcrypt_generic_init($cipher, $this->key, $this->iv);
return $cipher;
}
function encrypt($string){
$binary = mcrypt_generic($this->getCipher(),$string);
$string = '';
for($i = 0; $i < strlen($binary); $i++){
$string .= str_pad(ord($binary[$i]),3,'0',STR_PAD_LEFT);
}
return $string;
}
function decrypt($encrypted){
//check for missing leading 0's
$encrypted = str_pad($encrypted, ceil(strlen($encrypted) / 3) * 3,'0', STR_PAD_LEFT);
$binary = '';
$values = str_split($encrypted,3);
foreach($values as $chr){
$chr = ltrim($chr,'0');
$binary .= chr($chr);
}
return mdecrypt_generic($this->getCipher(),$binary);
}
}
$crypt = new Crypter('secret key','12348765');
$encrypted = $crypt->encrypt(1234);
echo $encrypted.PHP_EOL;
//fake missing leading 0
$encrypted = ltrim($encrypted,'0');
echo $encrypted.PHP_EOL;
$decrypted = $crypt->decrypt($encrypted);
echo $decrypted.PHP_EOL;
Result:
057044206104214236155088
57044206104214236155088
1234
I use the following class in my CakePHP app to create reversible encrypted ids:
class Tiny
{
public static $set = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
public static function toTiny($id)
{
$set = self::$set;
$HexN="";
$id = floor(abs(intval($id)));
$radix = strlen($set);
while (true)
{
$R=$id%$radix;
$HexN = $set{$R}.$HexN;
$id=($id-$R)/$radix;
if ($id==0) break;
}
return $HexN;
}
public static function reverseTiny($str)
{
$set = self::$set;
$radix = strlen($set);
$strlen = strlen($str);
$N = 0;
for($i=0;$i<$strlen;$i++)
{
$N += strpos($set,$str{$i})*pow($radix,($strlen-$i-1));
}
return "{$N}";
}
}
I'm looking for something just as simple for strings. Where it has a simple set variable and just two functions, one for encrypting and one for decrypting. All of the ones I have seen so far have been over-complicated and too framework-based. I want a class that is completely stand-alone and not reliant on other files and easily integrated into CakePHP.
Can anyone help? Does anyone know of one or could help me modify this script to work with strings instead so I can create another class. It needs to be simple to use: e.g. Class::encrypt(string);
Also security is not a major concern here as it's not being used for protecting anything rather just hashing a string in a way that can be reversed.
This is what I want:
class Encrypt
{
public static $set = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
public static function Encrypt($string)
{
$set = self::$set;
return;
}
public static function Decrypt($string)
{
$set = self::$set;
return;
}
}
Here is a modified version of the code that I use. It relies on openssl, so it may not be suitable if you need it to be portable.
<?php
class Cipher {
public static function strongRand($num_bytes, $raw = false) {
$rand = openssl_random_pseudo_bytes($num_bytes);
if (!$raw) {
$rand = base64_encode($rand);
}
return $rand;
}
public static function encrypt($data, $password = "default", $type = "aes128") {
$iv = Cipher::strongRand(12);
$encrypted = openssl_encrypt($data, $type, $password, false, $iv);
return $iv . $encrypted;
}
public static function decrypt($data, $password = "default", $type = "aes128") {
$iv = substr($data, 0, 16);
$data = substr($data, 16);
$decrypted = openssl_decrypt($data, $type, $password, false, $iv);
return $decrypted;
}
}
?>
An example of how to use the code:
<?php
include('cipher.php');
$enc = Cipher::encrypt('kachow');
echo $enc . "\n";
$dec = Cipher::decrypt($enc);
echo $dec . "\n";
?>
Outputs:
0fykYiBPJAL/C3fFuX+jApFRdRw7NY8uYmGaaQ==
kachow
If you need to crypt numbers, I use those simple functions (change the random letters in function _map_key to whatever you want, just be sure that they are unique). If you do not have numbers but string, you can STR2BIN them, then use this function:
function _map_kid($kid, $umap=false){
$map = array('M','Y','S','I','M','P','L','E','K');
$ret = '';
for($i = 0; $i<strlen($kid); $i++){
if($umap){
$ret .= array_search(substr($kid,$i,1),$map);
} else {
$ret .= $map[substr($kid,$i,1)];
}
}
return $ret;
}
function cript_customer_id($customer_id, $key=0){
if($key==0){
$key = trim(microtime(true));
}
$key = intval($key);
if(strlen($key)<=3) $key +=999;
if(substr($key,-1)==0) $key +=3;
$key = substr($key,-3);
$kid = ((($customer_id.substr($key,0,1))+substr($key,1,1))*substr($key,-1)).$key;
return _map_kid($kid);
}
function _decript_customer_id($kid){
if(trim($kid)=='') return false;
$kid = strtoupper($kid);
$kid = _qsc2_map_kid($kid, true);
$key = substr($kid, -3);
$customer_id = substr($kid, 0, -3);
if(substr($key,-1)>0){
$customer_id = substr((($customer_id/substr($key,-1))-substr($key,1,1)),0,-1);
} else {
$customer_id = 0;
}
return $customer_id;
}
There are various pure PHP implementations of standard crypto primitives like AES that you could use, like this or this one.
The RC4 algorithm, in particular, is something you could implement in about a dozen lines of PHP if you wanted.
However, those implementations are not likely to be very efficient; in general, when it comes to crypto in high-level languages like PHP, you can have any two out of "secure", "fast" and "self-contained".
OK, if all you want is obfuscation, here's something based on this example by "peter at NOSPAM jamit dot com" over at php.net:
class Obfuscate
{
public static function obfuscate($string)
{
return str_rot13( base64_encode( $string ) );
}
public static function deobfuscate($string)
{
return base64_decode( str_rot13( $string ) );
}
}
This should be fast and self-contained, but it provides very little security. At best it makes a nice little puzzle for amateur cryptographers, of a level perhaps comparable with a newspaper crossword puzzle.
Look into MCrypt functions. It'll be even shorter than the above code. And secure too!
I prefer to use mcrypt, but if don't wanna, the try to find something useful on phpclasses.org, -like this http://www.phpclasses.org/package/2995-PHP-Encode-and-decode-text-strings-with-random-keys.html
I'm looking for a php function which can mask credit card & bank information such as routing number and account numbers. I need to mask many formats, so the existing stack overflow answers don't help me that much.
So for example, if the input is 304-443-2456, the function should return xxx-xxx-2456.
Sometimes the number has dashes, and can be in various lengths.
I'm looking for something generic, that I can extend as needed, preferably a zend framework view helper class.
Some little regex in a function of it own, configuration available:
$number = '304-443-2456';
function mask_number($number, $count = 4, $seperators = '-')
{
$masked = preg_replace('/\d/', 'x', $number);
$last = preg_match(sprintf('/([%s]?\d){%d}$/', preg_quote($seperators), $count), $number, $matches);
if ($last) {
list($clean) = $matches;
$masked = substr($masked, 0, -strlen($clean)) . $clean;
}
return $masked;
}
echo mask_number($number); # xxx-xxx-2456
If the function fails, it will return all masked (e.g. a different seperator, less than 4 digits etc.). Some child-safety build in you could say.
Demo
<?php
function ccmask($cc, $char = '#') {
$pattern = '/^([0-9-]+)([0-9]*)$/U';
$matches = array();
preg_match($pattern, $cc, $matches);
return preg_replace('([0-9])', $char, $matches[1]).$matches[2];
}
echo ccmask('304-443-2456'), "\n";
echo ccmask('4924-7921-9900-9876', '*'), "\n";
echo ccmask('30-43-56', 'x'), "\n";
Outputs:
###-###-2456
****-****-****-9876
xx-xx-56
I use a view helper for that. I tend to avoid Regex though as it always takes me ages to work out what it does, especially if I come back to code after a while.
class Zend_View_Helper_Ccmask
{
public function ccmask($ccNum)
{
$maskArray = explode('-', $ccNum);
$sections = count($maskArray) - 1;
for($i = 0; $i < $sections ; $i++){
$maskArray[$i] = str_replace(array(1,2,3,4,5,6,7,8,9,0), 'x', $maskArray[$i]);
}
return implode('-', $maskArray);
}
}
In your view
echo $this->ccmask('304-443-2456');
//output = xxx-xxx-2456
A good way to look at this is at what won't be masked and outputing xs for everything else. A simple, inexpensive solution is:
function cc_mask( $cc_raw, $unmask_count ){
$cc_masked = '';
for( $i=0; $i < ( strlen( $cc_raw ) - $unmask_count ) ; $i++ ){
//If you want to maintain hyphens and special characters
$char = substr( $cc_raw, $i, 1 );
$cc_masked .= ctype_digit( $char ) ? "*" : $char;
}
$cc_masked .= substr( $cc_raw , -$unmask_count );
return $cc_masked;
}
echo cc_mask("304-443-2456",4);
//Output
***-***-2456
Would be even faster if there was no need to maintain the hyphens and special characters