forked from zendframework/zendframework
-
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.
Added the scrypt key derivation algorithm
- Loading branch information
Showing
4 changed files
with
538 additions
and
11 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
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 | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,343 @@ | |||
<?php | |||
/** | |||
* Zend Framework (http://framework.zend.com/) | |||
* | |||
* @link http://github.com/zendframework/zf2 for the canonical source repository | |||
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com) | |||
* @license http://framework.zend.com/license/new-bsd New BSD License | |||
* @package Zend_Crypt | |||
*/ | |||
|
|||
namespace Zend\Crypt\Key\Derivation; | |||
|
|||
use Zend\Crypt\Key\Derivation\Pbkdf2; | |||
|
|||
/** | |||
* Scrypt key derivation function | |||
* | |||
* @category Zend | |||
* @package Zend_Crypt | |||
* @see http://www.tarsnap.com/scrypt.html | |||
* @see https://tools.ietf.org/html/draft-josefsson-scrypt-kdf-01 | |||
*/ | |||
class Scrypt | |||
{ | |||
/** | |||
* Execute the scrypt algorithm | |||
* | |||
* @param string $password | |||
* @param string $salt | |||
* @param integer $n CPU cost | |||
* @param integer $r Memory cost | |||
* @param integer $p parallelization cost | |||
* @param integer $length size of the output key | |||
* @return string | |||
*/ | |||
public static function calc($password, $salt, $n, $r, $p, $length) | |||
{ | |||
if ($n == 0 || ($n & ($n - 1)) != 0) { | |||
throw new Exception\InvalidArgumentException("N must be > 0 and a power of 2"); | |||
} | |||
if ($n > PHP_INT_MAX / 128 / $r) { | |||
throw new Exception\InvalidArgumentException("Parameter n is too large"); | |||
} | |||
if ($r > PHP_INT_MAX / 128 / $p) { | |||
throw new Exception\InvalidArgumentException("Parameter r is too large"); | |||
} | |||
|
|||
if (extension_loaded('Scrypt')) { | |||
if ($length < 16) { | |||
throw new Exception\InvalidArgumentException("Key length is too low, must be greater or equal to 16"); | |||
} | |||
return self::hex2bin(scrypt($password, $salt, $n, $r, $p, $length)); | |||
} | |||
|
|||
$b = Pbkdf2::calc('sha256', $password, $salt, 1, $p * 128 * $r); | |||
|
|||
$s = ''; | |||
for ($i = 0; $i < $p; $i++) { | |||
$s .= self::scryptROMix(substr($b, $i * 128 * $r, 128 * $r), $n, $r); | |||
} | |||
|
|||
return Pbkdf2::calc('sha256', $password, $s, 1, $length); | |||
} | |||
|
|||
/** | |||
* scryptROMix | |||
* | |||
* @param string $b | |||
* @param integer $n | |||
* @param integer $r | |||
* @return string | |||
* @see https://tools.ietf.org/html/draft-josefsson-scrypt-kdf-01#section-4 | |||
*/ | |||
protected static function scryptROMix($b, $n, $r) | |||
{ | |||
$x = $b; | |||
$v = array(); | |||
for ($i = 0; $i < $n; $i++) { | |||
$v[$i] = $x; | |||
$x = self::scryptBlockMix($x, $r); | |||
} | |||
for ($i = 0; $i < $n; $i++) { | |||
$j = self::integerify($x) % $n; | |||
$t = $x ^ $v[$j]; | |||
$x = self::scryptBlockMix($t, $r); | |||
} | |||
return $x; | |||
} | |||
|
|||
/** | |||
* scryptBlockMix | |||
* | |||
* @param string $b | |||
* @param integer $r | |||
* @return string | |||
* @see https://tools.ietf.org/html/draft-josefsson-scrypt-kdf-01#section-3 | |||
*/ | |||
protected static function scryptBlockMix($b, $r) | |||
{ | |||
$x = substr($b, -64); | |||
$even = ''; | |||
$odd = ''; | |||
$len = 2 * $r; | |||
|
|||
for ($i = 0; $i < $len; $i++) { | |||
if (PHP_INT_SIZE === 4) { | |||
$x = self::salsa208Core32($x ^ substr($b, 64 * $i, 64)); | |||
} else { | |||
$x = self::salsa208Core64($x ^ substr($b, 64 * $i, 64)); | |||
} | |||
if ($i % 2 == 0) { | |||
$even .= $x; | |||
} else { | |||
$odd .= $x; | |||
} | |||
} | |||
return $even . $odd; | |||
} | |||
|
|||
/** | |||
* Salsa 20/8 core (32 bit version) | |||
* | |||
* @param string $b | |||
* @return string | |||
* @see https://tools.ietf.org/html/draft-josefsson-scrypt-kdf-01#section-2 | |||
* @see http://cr.yp.to/salsa20.html | |||
*/ | |||
protected static function salsa208Core32($b) | |||
{ | |||
$b32 = array(); | |||
for ($i = 0; $i < 16; $i++) { | |||
list(, $b32[$i]) = unpack("V", substr($b, $i * 4, 4)); | |||
} | |||
|
|||
$x = $b32; | |||
for ($i = 0; $i < 8; $i += 2) { | |||
$a = ($x[ 0] + $x[12]); | |||
$x[ 4] ^= ($a << 7) | ($a >> 25) & 0x7f; | |||
$a = ($x[ 4] + $x[ 0]); | |||
$x[ 8] ^= ($a << 9) | ($a >> 23) & 0x1ff; | |||
$a = ($x[ 8] + $x[ 4]); | |||
$x[12] ^= ($a << 13) | ($a >> 19) & 0x1fff; | |||
$a = ($x[12] + $x[ 8]); | |||
$x[ 0] ^= ($a << 18) | ($a >> 14) & 0x3ffff; | |||
$a = ($x[ 5] + $x[ 1]); | |||
$x[ 9] ^= ($a << 7) | ($a >> 25) & 0x7f; | |||
$a = ($x[ 9] + $x[ 5]); | |||
$x[13] ^= ($a << 9) | ($a >> 23) & 0x1ff; | |||
$a = ($x[13] + $x[ 9]); | |||
$x[ 1] ^= ($a << 13) | ($a >> 19) & 0x1fff; | |||
$a = ($x[ 1] + $x[13]); | |||
$x[ 5] ^= ($a << 18) | ($a >> 14) & 0x3ffff; | |||
$a = ($x[10] + $x[ 6]); | |||
$x[14] ^= ($a << 7) | ($a >> 25) & 0x7f; | |||
$a = ($x[14] + $x[10]); | |||
$x[ 2] ^= ($a << 9) | ($a >> 23) & 0x1ff; | |||
$a = ($x[ 2] + $x[14]); | |||
$x[ 6] ^= ($a << 13) | ($a >> 19) & 0x1fff; | |||
$a = ($x[ 6] + $x[ 2]); | |||
$x[10] ^= ($a << 18) | ($a >> 14) & 0x3ffff; | |||
$a = ($x[15] + $x[11]); | |||
$x[ 3] ^= ($a << 7) | ($a >> 25) & 0x7f; | |||
$a = ($x[ 3] + $x[15]); | |||
$x[ 7] ^= ($a << 9) | ($a >> 23) & 0x1ff; | |||
$a = ($x[ 7] + $x[ 3]); | |||
$x[11] ^= ($a << 13) | ($a >> 19) & 0x1fff; | |||
$a = ($x[11] + $x[ 7]); | |||
$x[15] ^= ($a << 18) | ($a >> 14) & 0x3ffff; | |||
$a = ($x[ 0] + $x[ 3]); | |||
$x[ 1] ^= ($a << 7) | ($a >> 25) & 0x7f; | |||
$a = ($x[ 1] + $x[ 0]); | |||
$x[ 2] ^= ($a << 9) | ($a >> 23) & 0x1ff; | |||
$a = ($x[ 2] + $x[ 1]); | |||
$x[ 3] ^= ($a << 13) | ($a >> 19) & 0x1fff; | |||
$a = ($x[ 3] + $x[ 2]); | |||
$x[ 0] ^= ($a << 18) | ($a >> 14) & 0x3ffff; | |||
$a = ($x[ 5] + $x[ 4]); | |||
$x[ 6] ^= ($a << 7) | ($a >> 25) & 0x7f; | |||
$a = ($x[ 6] + $x[ 5]); | |||
$x[ 7] ^= ($a << 9) | ($a >> 23) & 0x1ff; | |||
$a = ($x[ 7] + $x[ 6]); | |||
$x[ 4] ^= ($a << 13) | ($a >> 19) & 0x1fff; | |||
$a = ($x[ 4] + $x[ 7]); | |||
$x[ 5] ^= ($a << 18) | ($a >> 14) & 0x3ffff; | |||
$a = ($x[10] + $x[ 9]); | |||
$x[11] ^= ($a << 7) | ($a >> 25) & 0x7f; | |||
$a = ($x[11] + $x[10]); | |||
$x[ 8] ^= ($a << 9) | ($a >> 23) & 0x1ff; | |||
$a = ($x[ 8] + $x[11]); | |||
$x[ 9] ^= ($a << 13) | ($a >> 19) & 0x1fff; | |||
$a = ($x[ 9] + $x[ 8]); | |||
$x[10] ^= ($a << 18) | ($a >> 14) & 0x3ffff; | |||
$a = ($x[15] + $x[14]); | |||
$x[12] ^= ($a << 7) | ($a >> 25) & 0x7f; | |||
$a = ($x[12] + $x[15]); | |||
$x[13] ^= ($a << 9) | ($a >> 23) & 0x1ff; | |||
$a = ($x[13] + $x[12]); | |||
$x[14] ^= ($a << 13) | ($a >> 19) & 0x1fff; | |||
$a = ($x[14] + $x[13]); | |||
$x[15] ^= ($a << 18) | ($a >> 14) & 0x3ffff; | |||
} | |||
for ($i = 0; $i < 16; $i++) { | |||
$b32[$i] = $b32[$i] + $x[$i]; | |||
} | |||
$result = ''; | |||
for ($i = 0; $i < 16; $i++) { | |||
$result .= pack("V", $b32[$i]); | |||
} | |||
|
|||
return $result; | |||
} | |||
|
|||
/** | |||
* Salsa 20/8 core (64 bit version) | |||
* | |||
* @param string $b | |||
* @return string | |||
* @see https://tools.ietf.org/html/draft-josefsson-scrypt-kdf-01#section-2 | |||
* @see http://cr.yp.to/salsa20.html | |||
*/ | |||
protected static function salsa208Core64($b) | |||
{ | |||
$b32 = array(); | |||
for ($i = 0; $i < 16; $i++) { | |||
list(, $b32[$i]) = unpack("V", substr($b, $i * 4, 4)); | |||
} | |||
|
|||
$x = $b32; | |||
for ($i = 0; $i < 8; $i += 2) { | |||
$a = ($x[ 0] + $x[12]) & 0xffffffff; | |||
$x[ 4] ^= ($a << 7) | ($a >> 25); | |||
$a = ($x[ 4] + $x[ 0]) & 0xffffffff; | |||
$x[ 8] ^= ($a << 9) | ($a >> 23); | |||
$a = ($x[ 8] + $x[ 4]) & 0xffffffff; | |||
$x[12] ^= ($a << 13) | ($a >> 19); | |||
$a = ($x[12] + $x[ 8]) & 0xffffffff; | |||
$x[ 0] ^= ($a << 18) | ($a >> 14); | |||
$a = ($x[ 5] + $x[ 1]) & 0xffffffff; | |||
$x[ 9] ^= ($a << 7) | ($a >> 25); | |||
$a = ($x[ 9] + $x[ 5]) & 0xffffffff; | |||
$x[13] ^= ($a << 9) | ($a >> 23); | |||
$a = ($x[13] + $x[ 9]) & 0xffffffff; | |||
$x[ 1] ^= ($a << 13) | ($a >> 19); | |||
$a = ($x[ 1] + $x[13]) & 0xffffffff; | |||
$x[ 5] ^= ($a << 18) | ($a >> 14); | |||
$a = ($x[10] + $x[ 6]) & 0xffffffff; | |||
$x[14] ^= ($a << 7) | ($a >> 25); | |||
$a = ($x[14] + $x[10]) & 0xffffffff; | |||
$x[ 2] ^= ($a << 9) | ($a >> 23); | |||
$a = ($x[ 2] + $x[14]) & 0xffffffff; | |||
$x[ 6] ^= ($a << 13) | ($a >> 19); | |||
$a = ($x[ 6] + $x[ 2]) & 0xffffffff; | |||
$x[10] ^= ($a << 18) | ($a >> 14); | |||
$a = ($x[15] + $x[11]) & 0xffffffff; | |||
$x[ 3] ^= ($a << 7) | ($a >> 25); | |||
$a = ($x[ 3] + $x[15]) & 0xffffffff; | |||
$x[ 7] ^= ($a << 9) | ($a >> 23); | |||
$a = ($x[ 7] + $x[ 3]) & 0xffffffff; | |||
$x[11] ^= ($a << 13) | ($a >> 19); | |||
$a = ($x[11] + $x[ 7]) & 0xffffffff; | |||
$x[15] ^= ($a << 18) | ($a >> 14); | |||
$a = ($x[ 0] + $x[ 3]) & 0xffffffff; | |||
$x[ 1] ^= ($a << 7) | ($a >> 25); | |||
$a = ($x[ 1] + $x[ 0]) & 0xffffffff; | |||
$x[ 2] ^= ($a << 9) | ($a >> 23); | |||
$a = ($x[ 2] + $x[ 1]) & 0xffffffff; | |||
$x[ 3] ^= ($a << 13) | ($a >> 19); | |||
$a = ($x[ 3] + $x[ 2]) & 0xffffffff; | |||
$x[ 0] ^= ($a << 18) | ($a >> 14); | |||
$a = ($x[ 5] + $x[ 4]) & 0xffffffff; | |||
$x[ 6] ^= ($a << 7) | ($a >> 25); | |||
$a = ($x[ 6] + $x[ 5]) & 0xffffffff; | |||
$x[ 7] ^= ($a << 9) | ($a >> 23); | |||
$a = ($x[ 7] + $x[ 6]) & 0xffffffff; | |||
$x[ 4] ^= ($a << 13) | ($a >> 19); | |||
$a = ($x[ 4] + $x[ 7]) & 0xffffffff; | |||
$x[ 5] ^= ($a << 18) | ($a >> 14); | |||
$a = ($x[10] + $x[ 9]) & 0xffffffff; | |||
$x[11] ^= ($a << 7) | ($a >> 25); | |||
$a = ($x[11] + $x[10]) & 0xffffffff; | |||
$x[ 8] ^= ($a << 9) | ($a >> 23); | |||
$a = ($x[ 8] + $x[11]) & 0xffffffff; | |||
$x[ 9] ^= ($a << 13) | ($a >> 19); | |||
$a = ($x[ 9] + $x[ 8]) & 0xffffffff; | |||
$x[10] ^= ($a << 18) | ($a >> 14); | |||
$a = ($x[15] + $x[14]) & 0xffffffff; | |||
$x[12] ^= ($a << 7) | ($a >> 25); | |||
$a = ($x[12] + $x[15]) & 0xffffffff; | |||
$x[13] ^= ($a << 9) | ($a >> 23); | |||
$a = ($x[13] + $x[12]) & 0xffffffff; | |||
$x[14] ^= ($a << 13) | ($a >> 19); | |||
$a = ($x[14] + $x[13]) & 0xffffffff; | |||
$x[15] ^= ($a << 18) | ($a >> 14); | |||
} | |||
for ($i = 0; $i < 16; $i++) { | |||
$b32[$i] = ($b32[$i] + $x[$i]) & 0xffffffff; | |||
} | |||
$result = ''; | |||
for ($i = 0; $i < 16; $i++) { | |||
$result .= pack("V", $b32[$i]); | |||
} | |||
|
|||
return $result; | |||
} | |||
|
|||
/** | |||
* Integerify | |||
* | |||
* Integerify (B[0] ... B[2 * r - 1]) is defined as the result | |||
* of interpreting B[2 * r - 1] as a little-endian integer. | |||
* Each block B is a string of 64 bytes. | |||
* | |||
* @param string $b | |||
* @return integer | |||
* @see https://tools.ietf.org/html/draft-josefsson-scrypt-kdf-01#section-4 | |||
*/ | |||
protected static function integerify($b) { | |||
$v = 'v'; | |||
if (PHP_INT_SIZE === 8) { | |||
$v = 'V'; | |||
} | |||
list(,$n) = unpack($v, substr($b, -64)); | |||
return $n; | |||
} | |||
|
|||
/** | |||
* Convert hex string in a binary string | |||
* | |||
* @param string $hex | |||
* @return string | |||
*/ | |||
protected static function hex2bin($hex) { | |||
if (version_compare(PHP_VERSION, '5.4') >= 0) { | |||
return hex2bin($hex); | |||
} | |||
$len = strlen($hex); | |||
$result = ''; | |||
for ($i = 0; $i < $len; $i+=2) { | |||
$result .= chr(hexdec($hex[$i] . $hex[$i+1])); | |||
} | |||
return $result; | |||
} | |||
} |
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
Oops, something went wrong.