/administrator/components/com_users/src/Service/Encrypt.php

https://github.com/joomla/joomla-cms · PHP · 128 lines · 54 code · 18 blank · 56 comment · 6 complexity · 2791bbc5cec1f42d3111cce79d118588 MD5 · raw file

  1. <?php
  2. /**
  3. * @package Joomla.Administrator
  4. * @subpackage com_users
  5. *
  6. * @copyright (C) 2022 Open Source Matters, Inc. <https://www.joomla.org>
  7. * @license GNU General Public License version 2 or later; see LICENSE.txt
  8. */
  9. namespace Joomla\Component\Users\Administrator\Service;
  10. use Joomla\CMS\Encrypt\Aes;
  11. use Joomla\CMS\Factory;
  12. /**
  13. * Data encryption service.
  14. *
  15. * @since 4.2.0
  16. */
  17. class Encrypt
  18. {
  19. /**
  20. * The encryption engine used by this service
  21. *
  22. * @var Aes
  23. * @since 4.2.0
  24. */
  25. private $aes;
  26. /**
  27. * EncryptService constructor.
  28. *
  29. * @since 4.2.0
  30. */
  31. public function __construct()
  32. {
  33. $this->initialize();
  34. }
  35. /**
  36. * Encrypt the plaintext $data and return the ciphertext prefixed by ###AES128###
  37. *
  38. * @param string $data The plaintext data
  39. *
  40. * @return string The ciphertext, prefixed by ###AES128###
  41. *
  42. * @since 4.2.0
  43. */
  44. public function encrypt(string $data): string
  45. {
  46. if (!is_object($this->aes)) {
  47. return $data;
  48. }
  49. $this->aes->setPassword($this->getPassword(), false);
  50. $encrypted = $this->aes->encryptString($data, true);
  51. return '###AES128###' . $encrypted;
  52. }
  53. /**
  54. * Decrypt the ciphertext, prefixed by ###AES128###, and return the plaintext.
  55. *
  56. * @param string $data The ciphertext, prefixed by ###AES128###
  57. * @param bool $legacy Use legacy key expansion? Use it to decrypt data encrypted with FOF 3.
  58. *
  59. * @return string The plaintext data
  60. *
  61. * @since 4.2.0
  62. */
  63. public function decrypt(string $data, bool $legacy = false): string
  64. {
  65. if (substr($data, 0, 12) != '###AES128###') {
  66. return $data;
  67. }
  68. $data = substr($data, 12);
  69. if (!is_object($this->aes)) {
  70. return $data;
  71. }
  72. $this->aes->setPassword($this->getPassword(), $legacy);
  73. $decrypted = $this->aes->decryptString($data, true, $legacy);
  74. // Decrypted data is null byte padded. We have to remove the padding before proceeding.
  75. return rtrim($decrypted, "\0");
  76. }
  77. /**
  78. * Initialize the AES cryptography object
  79. *
  80. * @return void
  81. * @since 4.2.0
  82. */
  83. private function initialize(): void
  84. {
  85. if (is_object($this->aes)) {
  86. return;
  87. }
  88. $password = $this->getPassword();
  89. if (empty($password)) {
  90. return;
  91. }
  92. $this->aes = new Aes('cbc');
  93. $this->aes->setPassword($password);
  94. }
  95. /**
  96. * Returns the password used to encrypt information in the component
  97. *
  98. * @return string
  99. *
  100. * @since 4.2.0
  101. */
  102. private function getPassword(): string
  103. {
  104. try {
  105. return Factory::getApplication()->get('secret', '');
  106. } catch (\Exception $e) {
  107. return '';
  108. }
  109. }
  110. }