Issues (3627)

app/bundles/CoreBundle/Helper/EncryptionHelper.php (1 issue)

1
<?php
2
3
/*
4
 * @copyright   2014 Mautic Contributors. All rights reserved
5
 * @author      Mautic
6
 *
7
 * @link        http://mautic.org
8
 *
9
 * @license     GNU/GPLv3 http://www.gnu.org/licenses/gpl-3.0.html
10
 *
11
 * http://www.warpconduit.net/2013/04/14/highly-secure-data-encryption-decryption-made-easy-with-php-mcrypt-rijndael-256-and-cbc/
12
 */
13
14
namespace Mautic\CoreBundle\Helper;
15
16
use Mautic\CoreBundle\Security\Cryptography\Cipher\Symmetric\SymmetricCipherInterface;
17
use Mautic\CoreBundle\Security\Exception\Cryptography\Symmetric\InvalidDecryptionException;
18
19
class EncryptionHelper
20
{
21
    /** @var SymmetricCipherInterface[] */
22
    private $availableCiphers;
23
24
    /** @var string */
25
    private $key;
26
27
    public function __construct(
28
        CoreParametersHelper $coreParametersHelper
29
    ) {
30
        $nonCipherArgs = 1;
31
        for ($i = $nonCipherArgs; $i < func_num_args(); ++$i) {
32
            $possibleCipher = func_get_arg($i);
33
            if (!($possibleCipher instanceof SymmetricCipherInterface)) {
34
                throw new \InvalidArgumentException(get_class($possibleCipher).' has to implement '.SymmetricCipherInterface::class);
35
            }
36
            if (!$possibleCipher->isSupported()) {
37
                continue;
38
            }
39
            $this->availableCiphers[] = $possibleCipher;
40
        }
41
42
        if (!$this->availableCiphers || 0 === count($this->availableCiphers)) {
43
            throw new \RuntimeException('None of possible cryptography libraries is supported');
44
        }
45
46
        $this->key = $coreParametersHelper->get('mautic.secret_key');
47
    }
48
49
    /**
50
     * Returns a 64 character string.
51
     *
52
     * @return string
53
     */
54
    public static function generateKey()
55
    {
56
        return hash('sha256', uniqid(mt_rand(), true));
57
    }
58
59
    /**
60
     * Encrypt string.
61
     *
62
     * @param mixed $data
63
     *
64
     * @return string
65
     */
66
    public function encrypt($data)
67
    {
68
        $encryptionCipher = reset($this->availableCiphers);
69
        $initVector       = $encryptionCipher->getRandomInitVector();
70
        $encrypted        = $encryptionCipher->encrypt(serialize($data), $this->key, $initVector);
71
72
        return base64_encode($encrypted).'|'.base64_encode($initVector);
73
    }
74
75
    /**
76
     * Decrypt string.
77
     * Returns false in case of failed decryption.
78
     *
79
     * @param string $data
80
     * @param bool   $mainDecryptOnly
81
     *
82
     * @return mixed|false
83
     */
84
    public function decrypt($data, $mainDecryptOnly = false)
85
    {
86
        $encryptData      = explode('|', $data);
87
        $encryptedMessage = base64_decode($encryptData[0]);
88
        $initVector       = base64_decode($encryptData[1]);
89
        $mainTried        = false;
90
        foreach ($this->availableCiphers as $availableCipher) {
91
            if ($mainDecryptOnly && $mainTried) {
92
                return false;
93
            }
94
            try {
95
                return Serializer::decode($availableCipher->decrypt($encryptedMessage, $this->key, $initVector));
96
            } catch (InvalidDecryptionException $ex) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
97
            }
98
            $mainTried = true;
99
        }
100
101
        return false;
102
    }
103
}
104