5

My testcase as follows:

echo crypt('string', '_....salt');//error
echo crypt('string', '_A...salt');//fast
echo crypt('string', '_AAAAsalt');//slow

Explanation as stated at http://www.php.net/manual/en/function.crypt.php:

CRYPT_EXT_DES - Extended DES-based hash. The "salt" is a 9-character string consisting of an underscore followed by 4 bytes of iteration count and 4 bytes of salt. These are encoded as printable characters, 6 bits per character, least significant character first. The values 0 to 63 are encoded as "./0-9A-Za-z". Using invalid characters in the salt will cause crypt() to fail.

A dot is a printable character so why does it return an error? And which "order" applies on the used characters resulting "AAAA" more iterations than "A..."?

mgutt
  • 5,867
  • 2
  • 50
  • 77

4 Answers4

1

It says all in the quoted paragraph: - least significant character first - The values 0 to 63 are encoded as "./0-9A-Za-z"

So in your example "_....salt" would mean 0 rounds which obviously can't work. and "_A...salt" is less than "_AAAAsalt" considering the least significant character comes first.

"_...Asalt" would also be more than "_A...salt"

Foobar
  • 26
  • 1
1

The code of Klathmon is nice but has some mistakes:

First - alphabet

It is:
./0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
Should be:
./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz

Second - order of characters/digits

It generates for example: ...z
But it should generate: z...

The improved code:

function base64_int_encode($num) {
  $alphabet_raw='./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
  $alphabet=str_split($alphabet_raw);
  $arr=array();
  $base=sizeof($alphabet);
  while($num) {
    $rem=$num % $base;
    $num=(int)($num / $base);
    $arr[]=$alphabet[$rem];
  }

  $string=implode($arr);

  return str_pad($string, 4, '.', STR_PAD_RIGHT);
}
Kinga the Witch
  • 129
  • 1
  • 5
1

A number system used in Extended DES:

.... - 0 (Extended DES error)
/... - 1
0... - 2
1... - 3
2... - 4
3... - 5
4... - 6
5... - 7
6... - 8
7... - 9
8... - 10

z... - 63
./.. - 64
//.. - 65
0/.. - 66
1/.. - 67

Y/.. - 100
61.. - 200
g2.. - 300
E4.. - 400
o5.. - 500
M7.. - 600
w8.. - 700
UA.. - 800
2C.. - 900
cD.. - 1000

zz.. - 4095
../. - 4096
/./. - 4097
0./. - 4098
1./. - 4099

xzzz - 16 777 213
yzzz - 16 777 214
zzzz - 16 777 215

And in connection with salt:

_/...salt - 1
_0...salt - 2
_1...salt - 3
_2...salt - 4
_3...salt - 5
_4...salt - 6
_5...salt - 7
_6...salt - 8
_7...salt - 9
_8...salt - 10

_z...salt - 63
_./..salt - 64
_//..salt - 65
_0/..salt - 66
_1/..salt - 67

_Y/..salt - 100
_61..salt - 200
_g2..salt - 300
_E4..salt - 400
_o5..salt - 500
_M7..salt - 600
_w8..salt - 700
_UA..salt - 800
_2C..salt - 900
_cD..salt - 1000

_zz..salt - 4095
_../.salt - 4096
_/./.salt - 4097
_0./.salt - 4098
_1./.salt - 4099

_xzzzsalt - 16 777 213
_yzzzsalt - 16 777 214
_zzzzsalt - 16 777 215
Kinga the Witch
  • 129
  • 1
  • 5
0

This question is a bit old, however i found this when trying to wrap my head around how to create a hashing class for internal use here, and i came up with this little function which will base64 encode an integer with the appropriate characters/significance to be used as the 4 character 'iteration count'. Possible values are from 1 to 16,777,215

private function base64_int_encode($num){
    $alphabet_raw = "./0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
    $alphabet = str_split($alphabet_raw);
    $arr = array();
    $base = sizeof($alphabet);
    while($num){
        $rem = $num % $base;
        $num = (int)($num / $base);
        $arr[]=$alphabet[$rem];
    }

    $arr = array_reverse($arr);
    $string = implode($arr);

    return str_pad($string, 4, '.', STR_PAD_LEFT);
}

Hope it helps someone!

Klathmon
  • 273
  • 1
  • 11