-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathEncryptionProvider.php
138 lines (121 loc) · 4.46 KB
/
EncryptionProvider.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
<?php
namespace NPR\One\Providers;
use NPR\One\Interfaces\EncryptionInterface;
/**
* A sample encryption provider, used in tandem with the SecureCookieProvider as the default implementation for
* secure storage of refresh tokens.
*
* @package NPR\One\Providers
*/
class EncryptionProvider implements EncryptionInterface
{
/** @var string - the cipher method to use, assuming it is available; defaults to "aes-256-ctr"
* @internal */
protected $cipherMethod = 'aes-256-ctr';
/** @var string - the salt to use for the encryption algorithm
* @internal */
protected $salt;
/**
* {@inheritdoc}
*/
public function isValid(): bool
{
if (!extension_loaded('openssl') || !isset($this->salt))
{
return false;
}
if (!in_array($this->cipherMethod, openssl_get_cipher_methods(true)))
{
return false; // @codeCoverageIgnore
}
return true;
}
/**
* {@inheritdoc}
* @throws \Exception
*/
public function encrypt($value): string
{
if (empty($value))
{
throw new \InvalidArgumentException('Must specify a value to encrypt');
}
if (!is_string($value))
{
throw new \InvalidArgumentException('The passed-in value must be a string');
}
$ivSize = openssl_cipher_iv_length($this->cipherMethod);
$iv = openssl_random_pseudo_bytes($ivSize);
$hashedSalt = openssl_digest($this->salt, 'sha256', true);
$encryptedText = openssl_encrypt($value, $this->cipherMethod, $hashedSalt, OPENSSL_RAW_DATA, $iv);
if ($encryptedText === false)
{
throw new \Exception('EncryptionProvider failed to encrypt the text; error message: ' . openssl_error_string()); // @codeCoverageIgnore
}
$encryptedValue = base64_encode($iv . $encryptedText);
return $encryptedValue;
}
/**
* {@inheritdoc}
* @throws \Exception
*/
public function decrypt($value): string
{
if (empty($value))
{
throw new \InvalidArgumentException('Must specify a value to decrypt');
}
if (!is_string($value))
{
throw new \InvalidArgumentException('The passed-in value must be a string');
}
$encrypted = base64_decode($value);
$ivSize = openssl_cipher_iv_length($this->cipherMethod);
$iv = mb_substr($encrypted, 0, $ivSize, '8bit');
$encryptedText = mb_substr($encrypted, $ivSize, null, '8bit');
$hashedSalt = openssl_digest($this->salt, 'sha256', true);
$decryptedText = openssl_decrypt($encryptedText, $this->cipherMethod, $hashedSalt, OPENSSL_RAW_DATA, $iv);
if ($decryptedText === false)
{
throw new \Exception('EncryptionProvider failed to decrypt the text; error message: ' . openssl_error_string()); // @codeCoverageIgnore
}
return $decryptedText;
}
/**
* Sets the salt for the encryption. This function must be called with a valid argument at least once before the
* EncryptionProvider is available for use.
*
* @param string $salt
* @throws \InvalidArgumentException if the passed-in value is not a non-empty string
*/
public function setSalt($salt)
{
if (empty($salt) || !is_string($salt))
{
throw new \InvalidArgumentException('The encryption salt must be a string');
}
$this->salt = $salt;
}
/**
* Sets the cipher method to use for the encryption. By default, it will attempt to use "aes-256-ctr", but this
* may not be available on your system. For a complete list of possible inputs, call `openssl_get_cipher_methods()`
* on your server; results will vary by environment.
*
* @see https://php.net/manual/en/function.openssl-get-cipher-methods.php
*
* @param string $cipherMethod
* @throws \InvalidArgumentException if the passed-in value is not a non-empty string
*/
public function setCipherMethod($cipherMethod)
{
if (empty($cipherMethod) || !is_string($cipherMethod))
{
throw new \InvalidArgumentException('The encryption cipher method must be a string');
}
if (!in_array($cipherMethod, openssl_get_cipher_methods(true)))
{
throw new \InvalidArgumentException('The selected cipher is not available on your system');
}
$this->cipherMethod = $cipherMethod;
}
}