SiteSecret.php 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. <?php
  2. namespace Elgg\Database;
  3. /**
  4. * Manages a site-specific secret key, encoded as a 32 byte string "secret"
  5. *
  6. * The key can have two formats:
  7. * - Since 1.8.17 all keys generated are Base64URL-encoded with the 1st character set to "z" so that
  8. * the format can be recognized. With one character lost, this makes the keys effectively 186 bits.
  9. * - Before 1.8.17 keys were hex-encoded (128 bits) but created from insufficiently random sources.
  10. *
  11. * The hex keys were created with rand() as the only decent source of entropy (the site's creation time
  12. * is not too difficult to find). As such, systems with a low getrandmax() value created particularly
  13. * weak keys. You can check key string using getStrength().
  14. *
  15. * @access private
  16. *
  17. * @package Elgg.Core
  18. * @subpackage Database
  19. * @since 1.10.0
  20. */
  21. class SiteSecret {
  22. /**
  23. * Initialise the site secret (32 bytes: "z" to indicate format + 186-bit key in Base64 URL).
  24. *
  25. * Used during installation and saves as a datalist.
  26. *
  27. * Note: Old secrets were hex encoded.
  28. *
  29. * @return mixed The site secret hash or false
  30. * @access private
  31. */
  32. function init() {
  33. $secret = 'z' . _elgg_services()->crypto->getRandomString(31);
  34. if (_elgg_services()->datalist->set('__site_secret__', $secret)) {
  35. return $secret;
  36. }
  37. return false;
  38. }
  39. /**
  40. * Returns the site secret.
  41. *
  42. * Used to generate difficult to guess hashes for sessions and action tokens.
  43. *
  44. * @param bool $raw If true, a binary key will be returned
  45. *
  46. * @return string Site secret.
  47. * @access private
  48. */
  49. function get($raw = false) {
  50. $secret = _elgg_services()->datalist->get('__site_secret__');
  51. if (!$secret) {
  52. $secret = init_site_secret();
  53. }
  54. if ($raw) {
  55. // try to return binary key
  56. if ($secret[0] === 'z') {
  57. // new keys are "z" + base64URL
  58. $base64 = strtr(substr($secret, 1), '-_', '+/');
  59. $key = base64_decode($base64);
  60. if ($key !== false) {
  61. // on failure, at least return string key :/
  62. return $key;
  63. }
  64. } else {
  65. // old keys are hex
  66. return hex2bin($secret);
  67. }
  68. }
  69. return $secret;
  70. }
  71. /**
  72. * Get the strength of the site secret
  73. *
  74. * If "weak" or "moderate" is returned, this assumes we're running on the same system that created
  75. * the key.
  76. *
  77. * @return string "strong", "moderate", or "weak"
  78. * @access private
  79. */
  80. function getStrength() {
  81. $secret = get_site_secret();
  82. if ($secret[0] !== 'z') {
  83. $rand_max = getrandmax();
  84. if ($rand_max < pow(2, 16)) {
  85. return 'weak';
  86. }
  87. if ($rand_max < pow(2, 32)) {
  88. return 'moderate';
  89. }
  90. }
  91. return 'strong';
  92. }
  93. }