PageRenderTime 46ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/concrete/vendor/zendframework/zend-crypt/src/Key/Derivation/Scrypt.php

https://gitlab.com/koodersmiikka/operaatio-terveys
PHP | 341 lines | 249 code | 18 blank | 74 comment | 28 complexity | eafad7f5e813f3e8002f710c73afa6e6 MD5 | raw file
  1. <?php
  2. /**
  3. * Zend Framework (http://framework.zend.com/)
  4. *
  5. * @link http://github.com/zendframework/zf2 for the canonical source repository
  6. * @copyright Copyright (c) 2005-2014 Zend Technologies USA Inc. (http://www.zend.com)
  7. * @license http://framework.zend.com/license/new-bsd New BSD License
  8. */
  9. namespace Zend\Crypt\Key\Derivation;
  10. /**
  11. * Scrypt key derivation function
  12. *
  13. * @see http://www.tarsnap.com/scrypt.html
  14. * @see https://tools.ietf.org/html/draft-josefsson-scrypt-kdf-01
  15. */
  16. abstract class Scrypt
  17. {
  18. /**
  19. * Execute the scrypt algorithm
  20. *
  21. * @param string $password
  22. * @param string $salt
  23. * @param int $n CPU cost
  24. * @param int $r Memory cost
  25. * @param int $p parallelization cost
  26. * @param int $length size of the output key
  27. * @return string
  28. */
  29. public static function calc($password, $salt, $n, $r, $p, $length)
  30. {
  31. if ($n == 0 || ($n & ($n - 1)) != 0) {
  32. throw new Exception\InvalidArgumentException("N must be > 0 and a power of 2");
  33. }
  34. if ($n > PHP_INT_MAX / 128 / $r) {
  35. throw new Exception\InvalidArgumentException("Parameter n is too large");
  36. }
  37. if ($r > PHP_INT_MAX / 128 / $p) {
  38. throw new Exception\InvalidArgumentException("Parameter r is too large");
  39. }
  40. if (extension_loaded('Scrypt')) {
  41. if ($length < 16) {
  42. throw new Exception\InvalidArgumentException("Key length is too low, must be greater or equal to 16");
  43. }
  44. return self::hex2bin(scrypt($password, $salt, $n, $r, $p, $length));
  45. }
  46. $b = Pbkdf2::calc('sha256', $password, $salt, 1, $p * 128 * $r);
  47. $s = '';
  48. for ($i = 0; $i < $p; $i++) {
  49. $s .= self::scryptROMix(substr($b, $i * 128 * $r, 128 * $r), $n, $r);
  50. }
  51. return Pbkdf2::calc('sha256', $password, $s, 1, $length);
  52. }
  53. /**
  54. * scryptROMix
  55. *
  56. * @param string $b
  57. * @param int $n
  58. * @param int $r
  59. * @return string
  60. * @see https://tools.ietf.org/html/draft-josefsson-scrypt-kdf-01#section-4
  61. */
  62. protected static function scryptROMix($b, $n, $r)
  63. {
  64. $x = $b;
  65. $v = array();
  66. for ($i = 0; $i < $n; $i++) {
  67. $v[$i] = $x;
  68. $x = self::scryptBlockMix($x, $r);
  69. }
  70. for ($i = 0; $i < $n; $i++) {
  71. $j = self::integerify($x) % $n;
  72. $t = $x ^ $v[$j];
  73. $x = self::scryptBlockMix($t, $r);
  74. }
  75. return $x;
  76. }
  77. /**
  78. * scryptBlockMix
  79. *
  80. * @param string $b
  81. * @param int $r
  82. * @return string
  83. * @see https://tools.ietf.org/html/draft-josefsson-scrypt-kdf-01#section-3
  84. */
  85. protected static function scryptBlockMix($b, $r)
  86. {
  87. $x = substr($b, -64);
  88. $even = '';
  89. $odd = '';
  90. $len = 2 * $r;
  91. for ($i = 0; $i < $len; $i++) {
  92. if (PHP_INT_SIZE === 4) {
  93. $x = self::salsa208Core32($x ^ substr($b, 64 * $i, 64));
  94. } else {
  95. $x = self::salsa208Core64($x ^ substr($b, 64 * $i, 64));
  96. }
  97. if ($i % 2 == 0) {
  98. $even .= $x;
  99. } else {
  100. $odd .= $x;
  101. }
  102. }
  103. return $even . $odd;
  104. }
  105. /**
  106. * Salsa 20/8 core (32 bit version)
  107. *
  108. * @param string $b
  109. * @return string
  110. * @see https://tools.ietf.org/html/draft-josefsson-scrypt-kdf-01#section-2
  111. * @see http://cr.yp.to/salsa20.html
  112. */
  113. protected static function salsa208Core32($b)
  114. {
  115. $b32 = array();
  116. for ($i = 0; $i < 16; $i++) {
  117. list(, $b32[$i]) = unpack("V", substr($b, $i * 4, 4));
  118. }
  119. $x = $b32;
  120. for ($i = 0; $i < 8; $i += 2) {
  121. $a = ($x[ 0] + $x[12]);
  122. $x[ 4] ^= ($a << 7) | ($a >> 25) & 0x7f;
  123. $a = ($x[ 4] + $x[ 0]);
  124. $x[ 8] ^= ($a << 9) | ($a >> 23) & 0x1ff;
  125. $a = ($x[ 8] + $x[ 4]);
  126. $x[12] ^= ($a << 13) | ($a >> 19) & 0x1fff;
  127. $a = ($x[12] + $x[ 8]);
  128. $x[ 0] ^= ($a << 18) | ($a >> 14) & 0x3ffff;
  129. $a = ($x[ 5] + $x[ 1]);
  130. $x[ 9] ^= ($a << 7) | ($a >> 25) & 0x7f;
  131. $a = ($x[ 9] + $x[ 5]);
  132. $x[13] ^= ($a << 9) | ($a >> 23) & 0x1ff;
  133. $a = ($x[13] + $x[ 9]);
  134. $x[ 1] ^= ($a << 13) | ($a >> 19) & 0x1fff;
  135. $a = ($x[ 1] + $x[13]);
  136. $x[ 5] ^= ($a << 18) | ($a >> 14) & 0x3ffff;
  137. $a = ($x[10] + $x[ 6]);
  138. $x[14] ^= ($a << 7) | ($a >> 25) & 0x7f;
  139. $a = ($x[14] + $x[10]);
  140. $x[ 2] ^= ($a << 9) | ($a >> 23) & 0x1ff;
  141. $a = ($x[ 2] + $x[14]);
  142. $x[ 6] ^= ($a << 13) | ($a >> 19) & 0x1fff;
  143. $a = ($x[ 6] + $x[ 2]);
  144. $x[10] ^= ($a << 18) | ($a >> 14) & 0x3ffff;
  145. $a = ($x[15] + $x[11]);
  146. $x[ 3] ^= ($a << 7) | ($a >> 25) & 0x7f;
  147. $a = ($x[ 3] + $x[15]);
  148. $x[ 7] ^= ($a << 9) | ($a >> 23) & 0x1ff;
  149. $a = ($x[ 7] + $x[ 3]);
  150. $x[11] ^= ($a << 13) | ($a >> 19) & 0x1fff;
  151. $a = ($x[11] + $x[ 7]);
  152. $x[15] ^= ($a << 18) | ($a >> 14) & 0x3ffff;
  153. $a = ($x[ 0] + $x[ 3]);
  154. $x[ 1] ^= ($a << 7) | ($a >> 25) & 0x7f;
  155. $a = ($x[ 1] + $x[ 0]);
  156. $x[ 2] ^= ($a << 9) | ($a >> 23) & 0x1ff;
  157. $a = ($x[ 2] + $x[ 1]);
  158. $x[ 3] ^= ($a << 13) | ($a >> 19) & 0x1fff;
  159. $a = ($x[ 3] + $x[ 2]);
  160. $x[ 0] ^= ($a << 18) | ($a >> 14) & 0x3ffff;
  161. $a = ($x[ 5] + $x[ 4]);
  162. $x[ 6] ^= ($a << 7) | ($a >> 25) & 0x7f;
  163. $a = ($x[ 6] + $x[ 5]);
  164. $x[ 7] ^= ($a << 9) | ($a >> 23) & 0x1ff;
  165. $a = ($x[ 7] + $x[ 6]);
  166. $x[ 4] ^= ($a << 13) | ($a >> 19) & 0x1fff;
  167. $a = ($x[ 4] + $x[ 7]);
  168. $x[ 5] ^= ($a << 18) | ($a >> 14) & 0x3ffff;
  169. $a = ($x[10] + $x[ 9]);
  170. $x[11] ^= ($a << 7) | ($a >> 25) & 0x7f;
  171. $a = ($x[11] + $x[10]);
  172. $x[ 8] ^= ($a << 9) | ($a >> 23) & 0x1ff;
  173. $a = ($x[ 8] + $x[11]);
  174. $x[ 9] ^= ($a << 13) | ($a >> 19) & 0x1fff;
  175. $a = ($x[ 9] + $x[ 8]);
  176. $x[10] ^= ($a << 18) | ($a >> 14) & 0x3ffff;
  177. $a = ($x[15] + $x[14]);
  178. $x[12] ^= ($a << 7) | ($a >> 25) & 0x7f;
  179. $a = ($x[12] + $x[15]);
  180. $x[13] ^= ($a << 9) | ($a >> 23) & 0x1ff;
  181. $a = ($x[13] + $x[12]);
  182. $x[14] ^= ($a << 13) | ($a >> 19) & 0x1fff;
  183. $a = ($x[14] + $x[13]);
  184. $x[15] ^= ($a << 18) | ($a >> 14) & 0x3ffff;
  185. }
  186. for ($i = 0; $i < 16; $i++) {
  187. $b32[$i] = $b32[$i] + $x[$i];
  188. }
  189. $result = '';
  190. for ($i = 0; $i < 16; $i++) {
  191. $result .= pack("V", $b32[$i]);
  192. }
  193. return $result;
  194. }
  195. /**
  196. * Salsa 20/8 core (64 bit version)
  197. *
  198. * @param string $b
  199. * @return string
  200. * @see https://tools.ietf.org/html/draft-josefsson-scrypt-kdf-01#section-2
  201. * @see http://cr.yp.to/salsa20.html
  202. */
  203. protected static function salsa208Core64($b)
  204. {
  205. $b32 = array();
  206. for ($i = 0; $i < 16; $i++) {
  207. list(, $b32[$i]) = unpack("V", substr($b, $i * 4, 4));
  208. }
  209. $x = $b32;
  210. for ($i = 0; $i < 8; $i += 2) {
  211. $a = ($x[ 0] + $x[12]) & 0xffffffff;
  212. $x[ 4] ^= ($a << 7) | ($a >> 25);
  213. $a = ($x[ 4] + $x[ 0]) & 0xffffffff;
  214. $x[ 8] ^= ($a << 9) | ($a >> 23);
  215. $a = ($x[ 8] + $x[ 4]) & 0xffffffff;
  216. $x[12] ^= ($a << 13) | ($a >> 19);
  217. $a = ($x[12] + $x[ 8]) & 0xffffffff;
  218. $x[ 0] ^= ($a << 18) | ($a >> 14);
  219. $a = ($x[ 5] + $x[ 1]) & 0xffffffff;
  220. $x[ 9] ^= ($a << 7) | ($a >> 25);
  221. $a = ($x[ 9] + $x[ 5]) & 0xffffffff;
  222. $x[13] ^= ($a << 9) | ($a >> 23);
  223. $a = ($x[13] + $x[ 9]) & 0xffffffff;
  224. $x[ 1] ^= ($a << 13) | ($a >> 19);
  225. $a = ($x[ 1] + $x[13]) & 0xffffffff;
  226. $x[ 5] ^= ($a << 18) | ($a >> 14);
  227. $a = ($x[10] + $x[ 6]) & 0xffffffff;
  228. $x[14] ^= ($a << 7) | ($a >> 25);
  229. $a = ($x[14] + $x[10]) & 0xffffffff;
  230. $x[ 2] ^= ($a << 9) | ($a >> 23);
  231. $a = ($x[ 2] + $x[14]) & 0xffffffff;
  232. $x[ 6] ^= ($a << 13) | ($a >> 19);
  233. $a = ($x[ 6] + $x[ 2]) & 0xffffffff;
  234. $x[10] ^= ($a << 18) | ($a >> 14);
  235. $a = ($x[15] + $x[11]) & 0xffffffff;
  236. $x[ 3] ^= ($a << 7) | ($a >> 25);
  237. $a = ($x[ 3] + $x[15]) & 0xffffffff;
  238. $x[ 7] ^= ($a << 9) | ($a >> 23);
  239. $a = ($x[ 7] + $x[ 3]) & 0xffffffff;
  240. $x[11] ^= ($a << 13) | ($a >> 19);
  241. $a = ($x[11] + $x[ 7]) & 0xffffffff;
  242. $x[15] ^= ($a << 18) | ($a >> 14);
  243. $a = ($x[ 0] + $x[ 3]) & 0xffffffff;
  244. $x[ 1] ^= ($a << 7) | ($a >> 25);
  245. $a = ($x[ 1] + $x[ 0]) & 0xffffffff;
  246. $x[ 2] ^= ($a << 9) | ($a >> 23);
  247. $a = ($x[ 2] + $x[ 1]) & 0xffffffff;
  248. $x[ 3] ^= ($a << 13) | ($a >> 19);
  249. $a = ($x[ 3] + $x[ 2]) & 0xffffffff;
  250. $x[ 0] ^= ($a << 18) | ($a >> 14);
  251. $a = ($x[ 5] + $x[ 4]) & 0xffffffff;
  252. $x[ 6] ^= ($a << 7) | ($a >> 25);
  253. $a = ($x[ 6] + $x[ 5]) & 0xffffffff;
  254. $x[ 7] ^= ($a << 9) | ($a >> 23);
  255. $a = ($x[ 7] + $x[ 6]) & 0xffffffff;
  256. $x[ 4] ^= ($a << 13) | ($a >> 19);
  257. $a = ($x[ 4] + $x[ 7]) & 0xffffffff;
  258. $x[ 5] ^= ($a << 18) | ($a >> 14);
  259. $a = ($x[10] + $x[ 9]) & 0xffffffff;
  260. $x[11] ^= ($a << 7) | ($a >> 25);
  261. $a = ($x[11] + $x[10]) & 0xffffffff;
  262. $x[ 8] ^= ($a << 9) | ($a >> 23);
  263. $a = ($x[ 8] + $x[11]) & 0xffffffff;
  264. $x[ 9] ^= ($a << 13) | ($a >> 19);
  265. $a = ($x[ 9] + $x[ 8]) & 0xffffffff;
  266. $x[10] ^= ($a << 18) | ($a >> 14);
  267. $a = ($x[15] + $x[14]) & 0xffffffff;
  268. $x[12] ^= ($a << 7) | ($a >> 25);
  269. $a = ($x[12] + $x[15]) & 0xffffffff;
  270. $x[13] ^= ($a << 9) | ($a >> 23);
  271. $a = ($x[13] + $x[12]) & 0xffffffff;
  272. $x[14] ^= ($a << 13) | ($a >> 19);
  273. $a = ($x[14] + $x[13]) & 0xffffffff;
  274. $x[15] ^= ($a << 18) | ($a >> 14);
  275. }
  276. for ($i = 0; $i < 16; $i++) {
  277. $b32[$i] = ($b32[$i] + $x[$i]) & 0xffffffff;
  278. }
  279. $result = '';
  280. for ($i = 0; $i < 16; $i++) {
  281. $result .= pack("V", $b32[$i]);
  282. }
  283. return $result;
  284. }
  285. /**
  286. * Integerify
  287. *
  288. * Integerify (B[0] ... B[2 * r - 1]) is defined as the result
  289. * of interpreting B[2 * r - 1] as a little-endian integer.
  290. * Each block B is a string of 64 bytes.
  291. *
  292. * @param string $b
  293. * @return int
  294. * @see https://tools.ietf.org/html/draft-josefsson-scrypt-kdf-01#section-4
  295. */
  296. protected static function integerify($b)
  297. {
  298. $v = 'v';
  299. if (PHP_INT_SIZE === 8) {
  300. $v = 'V';
  301. }
  302. list(,$n) = unpack($v, substr($b, -64));
  303. return $n;
  304. }
  305. /**
  306. * Convert hex string in a binary string
  307. *
  308. * @param string $hex
  309. * @return string
  310. */
  311. protected static function hex2bin($hex)
  312. {
  313. if (version_compare(PHP_VERSION, '5.4') >= 0) {
  314. return hex2bin($hex);
  315. }
  316. $len = strlen($hex);
  317. $result = '';
  318. for ($i = 0; $i < $len; $i+=2) {
  319. $result .= chr(hexdec($hex[$i] . $hex[$i+1]));
  320. }
  321. return $result;
  322. }
  323. }