Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
33 / 33
100.00% covered (success)
100.00%
11 / 11
CRAP
100.00% covered (success)
100.00%
1 / 1
AbstractEncrypter
100.00% covered (success)
100.00%
33 / 33
100.00% covered (success)
100.00%
11 / 11
23
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 setCipher
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
4
 getCipher
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 hasCipher
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setKey
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
4
 getKey
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
2
 hasKey
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getAllKeys
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setPreviousKeys
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
5
 getPreviousKeys
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
2
 hasPreviousKeys
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 isAvailable
n/a
0 / 0
n/a
0 / 0
0
 isValid
n/a
0 / 0
n/a
0 / 0
0
 encrypt
n/a
0 / 0
n/a
0 / 0
0
 decrypt
n/a
0 / 0
n/a
0 / 0
0
1<?php
2declare(strict_types=1);
3/**
4 * Pop PHP Framework (https://www.popphp.org/)
5 *
6 * @link       https://github.com/popphp/popphp-framework
7 * @author     Nick Sagona, III <nick@popphp.org>
8 * @copyright  Copyright (c) 2009-2026 Nick Sagona, III
9 * @license    https://www.popphp.org/license     New BSD License
10 */
11
12/**
13 * @namespace
14 */
15namespace Pop\Crypt\Encryption;
16
17/**
18 * Pop Crypt abstract encrypter
19 *
20 * @category   Pop
21 * @package    Pop\Crypt
22 * @author     Nick Sagona, III <nick@popphp.org>
23 * @copyright  Copyright (c) 2009-2026 Nick Sagona, III
24 * @license    https://www.popphp.org/license     New BSD License
25 * @version    4.0.0
26 */
27abstract class AbstractEncrypter implements EncrypterInterface
28{
29
30    /**
31     * Encryption cipher
32     * @var string
33     */
34    protected string $cipher = 'aes-256-cbc';
35
36    /**
37     * Encryption Key
38     * @var ?string
39     */
40    protected ?string $key = null;
41
42    /**
43     * Previous keys
44     * @var array
45     */
46    protected array $previousKeys = [];
47
48    /**
49     * Constructor
50     *
51     * Instantiate the Encrypter object
52     *
53     * @param  string $key
54     * @param  string $cipher
55     * @param  bool   $raw
56     * @throws Exception
57     */
58    public function __construct(string $key, string $cipher = 'aes-256-cbc', bool $raw = true)
59    {
60        $this->setCipher($cipher);
61        $this->setKey($key, $raw);
62    }
63
64    /**
65     * Set cipher
66     *
67     * @param  string $cipher
68     * @throws Exception
69     * @return static
70     */
71    public function setCipher(string $cipher): static
72    {
73        $cipher = strtolower($cipher);
74
75        if (!static::isAvailable($cipher)) {
76            throw new Exception('Error: Invalid or unsupported cipher.');
77        }
78        if ($this->hasKey() && !static::isValid($this->key, $cipher)) {
79            throw new Exception('Error: Invalid key or unsupported cipher.');
80        }
81
82        $this->cipher = $cipher;
83        return $this;
84    }
85
86    /**
87     * Get cipher
88     *
89     * @return string
90     */
91    public function getCipher(): string
92    {
93        return $this->cipher;
94    }
95
96    /**
97     * Has cipher
98     *
99     * @return bool
100     */
101    public function hasCipher(): bool
102    {
103        return !empty($this->cipher);
104    }
105
106    /**
107     * Set key
108     *
109     * @param  string $key
110     * @param  bool   $raw
111     * @throws Exception
112     * @return static
113     */
114    public function setKey(string $key, bool $raw = true): static
115    {
116        $key = ($raw) ? $key : base64_decode($key);
117
118        if (!empty($this->cipher) && !static::isValid($key, $this->cipher)) {
119            throw new Exception('Error: Invalid key or unsupported cipher.');
120        }
121
122        $this->key = $key;
123        return $this;
124    }
125
126    /**
127     * Get key
128     *
129     * @param  bool $raw
130     * @return string
131     */
132    public function getKey(bool $raw = false): string
133    {
134        return ($raw) ? $this->key : base64_encode($this->key);
135    }
136
137    /**
138     * Has key
139     *
140     * @return bool
141     */
142    public function hasKey(): bool
143    {
144        return !empty($this->key);
145    }
146
147    /**
148     * Get all keys
149     *
150     * @return array
151     */
152    public function getAllKeys(): array
153    {
154        return [$this->key, ...$this->previousKeys];
155    }
156
157    /**
158     * Set previous keys
159     *
160     * @param  array $previousKeys
161     * @param  bool  $raw
162     * @throws Exception
163     * @return static
164     */
165    public function setPreviousKeys(array $previousKeys, bool $raw = true): static
166    {
167        if (!empty($this->cipher)) {
168            foreach ($previousKeys as $i => $previousKey) {
169                if (!$raw) {
170                    $previousKey = base64_decode($previousKey);
171                }
172                if (!static::isValid($previousKey, $this->cipher)) {
173                    throw new Exception('Error: Invalid key or unsupported cipher.');
174                }
175                $this->previousKeys[] = $previousKey;
176            }
177        }
178
179        return $this;
180    }
181
182    /**
183     * Get previous keys
184     *
185     * @param  bool $raw
186     * @return array
187     */
188    public function getPreviousKeys(bool $raw = false): array
189    {
190        if (!$raw) {
191            return array_map(function ($value) {
192                return base64_encode($value);
193            }, $this->previousKeys);
194        } else {
195            return $this->previousKeys;
196        }
197    }
198
199    /**
200     * Has previous keys
201     *
202     * @return bool
203     */
204    public function hasPreviousKeys(): bool
205    {
206        return !empty($this->previousKeys);
207    }
208
209    /**
210     * Determine if the cipher is available
211     *
212     * @param  string $cipher
213     * @return bool
214     */
215    abstract public static function isAvailable(string $cipher);
216
217    /**
218     * Determine if the key and cipher combination is valid
219     *
220     * @param  string $key
221     * @param  string $cipher
222     * @param  bool   $raw
223     * @return bool
224     */
225    abstract public static function isValid(string $key, string $cipher, bool $raw = true): bool;
226
227    /**
228     * Encrypt value
229     *
230     * @param  string $value
231     * @return string
232     */
233    abstract public function encrypt(#[\SensitiveParameter] string $value): string;
234
235    /**
236     * Decrypt value
237     *
238     * @param  string $payload
239     * @return string
240     */
241    abstract public function decrypt(string $payload): string;
242
243}