Slimmed down version of class OemrUI - Take 4 (#2044)
[openemr.git] / library / crypto.php
blob608abcab92c0f4d9fbb7b1a3e9c15a7a2bc458d4
1 <?php
2 /**
3 * Crypto library.
5 * @package OpenEMR
6 * @link http://www.open-emr.org
7 * @author Ensoftek, Inc
8 * @author Brady Miller <brady.g.miller@gmail.com>
9 * @copyright Copyright (c) 2015 Ensoftek, Inc
10 * @copyright Copyright (c) 2018 Brady Miller <brady.g.miller@gmail.com>
11 * @license https://github.com/openemr/openemr/blob/master/LICENSE GNU General Public License 3
14 /**
15 * Function to AES256 encrypt a given string
17 * @param string $sValue Raw data that will be encrypted.
18 * @param string $customPassword If null, then use standard key. If provide a password, then will derive key from this.
19 * @param string $baseEncode True if wish to base64_encode() encrypted data.
20 * @return string returns the encrypted data.
22 function aes256Encrypt($sValue, $customPassword = null, $baseEncode = true)
24 if (!extension_loaded('openssl')) {
25 error_log("OpenEMR Error : Encryption is not working because missing openssl extension.");
28 if (empty($customPassword)) {
29 // Collect the encryption key. If it does not exist, then create it
30 $sSecretKey = aes256PrepKey("two", "a");
31 } else {
32 // Turn the password into a hash(note use binary) to use as the key
33 $sSecretKey = hash("sha256", $customPassword, true);
35 // Collect the separate key for the HMAC hash. If it does not exist, then create it
36 $sSecretKeyHmac = aes256PrepKey("two", "b");
38 if (empty($sSecretKey) || empty($sSecretKeyHmac)) {
39 error_log("OpenEMR Error : Encryption is not working because key(s) is blank.");
42 try {
43 $iv = random_bytes(openssl_cipher_iv_length('AES-256-CBC'));
44 } catch (Error $e) {
45 error_log('OpenEMR Error : Encryption is not working because of random_bytes() Error: ' . $e->getMessage());
46 } catch (Exception $e) {
47 error_log('OpenEMR Error : Encryption is not working because of random_bytes() Exception: ' . $e->getMessage());
50 $processedValue = openssl_encrypt(
51 $sValue,
52 'AES-256-CBC',
53 $sSecretKey,
54 OPENSSL_RAW_DATA,
55 $iv
58 $hmacHash = hash_hmac('sha256', $iv.$processedValue, $sSecretKeyHmac, true);
60 if ($sValue != "" && ($processedValue == "" || $hmacHash == "")) {
61 error_log("OpenEMR Error : Encryption is not working.");
64 // prepend the encrypted value with the $hmacHash and $iv
65 $completedValue = $hmacHash . $iv . $processedValue;
67 if ($baseEncode) {
68 return base64_encode($completedValue);
69 } else {
70 return $completedValue;
75 /**
76 * Function to AES256 decrypt a given string, version 2
78 * @param string $sValue Encrypted data that will be decrypted.
79 * @param string $customPassword If null, then use standard key. If provide a password, then will derive key from this.
80 * @param string $baseEncode True if wish to base64_decode() encrypted data.
81 * @return string or false returns the decrypted data or false if failed.
83 function aes256DecryptTwo($sValue, $customPassword = null, $baseEncode = true)
85 if (!extension_loaded('openssl')) {
86 error_log("OpenEMR Error : Decryption is not working because missing openssl extension.");
87 return false;
90 if (empty($customPassword)) {
91 // Collect the encryption key.
92 $sSecretKey = aes256PrepKey("two", "a");
93 } else {
94 // Turn the password into a hash(note use primary) to use as the key
95 $sSecretKey = hash("sha256", $customPassword, true);
97 // Collect the separate key for the HMAC hash. If it does not exist, then create it
98 $sSecretKeyHmac = aes256PrepKey("two", "b");
100 if (empty($sSecretKey) || empty($sSecretKeyHmac)) {
101 error_log("OpenEMR Error : Encryption is not working because key(s) is blank.");
102 return false;
105 if ($baseEncode) {
106 $raw = base64_decode($sValue, true);
107 if ($raw === false) {
108 error_log("OpenEMR Error : Encryption did not work because illegal characters were noted in base64_encoded data.");
109 return false;
111 } else {
112 $raw = $sValue;
115 $ivLength = openssl_cipher_iv_length('AES-256-CBC');
116 $hmacHash = mb_substr($raw, 0, 32, '8bit');
117 $iv = mb_substr($raw, 32, $ivLength, '8bit');
118 $encrypted_data = mb_substr($raw, ($ivLength+32), null, '8bit');
120 $calculatedHmacHash = hash_hmac('sha256', $iv.$encrypted_data, $sSecretKeyHmac, true);
122 if (hash_equals($hmacHash, $calculatedHmacHash)) {
123 return openssl_decrypt(
124 $encrypted_data,
125 'AES-256-CBC',
126 $sSecretKey,
127 OPENSSL_RAW_DATA,
130 } else {
131 error_log("OpenEMR Error : Decryption failed authentication.");
137 * Function to AES256 decrypt a given string, version 1
139 * @param string $sValue Encrypted data that will be decrypted.
140 * @param string $customPassword If null, then use standard key. If provide a password, then will derive key from this.
141 * @param string $baseEncode True if wish to base64_decode() encrypted data.
142 * @return string returns the decrypted data.
144 function aes256DecryptOne($sValue, $customPassword = null, $baseEncode = true)
146 if (!extension_loaded('openssl')) {
147 error_log("OpenEMR Error : Decryption is not working because missing openssl extension.");
150 if (empty($customPassword)) {
151 // Collect the key. If it does not exist, then create it
152 $sSecretKey = aes256PrepKey();
153 } else {
154 // Turn the password into a hash to use as the key
155 $sSecretKey = hash("sha256", $customPassword);
158 if (empty($sSecretKey)) {
159 error_log("OpenEMR Error : Encryption is not working.");
162 if ($baseEncode) {
163 $raw = base64_decode($sValue);
164 } else {
165 $raw = $sValue;
168 $ivLength = openssl_cipher_iv_length('AES-256-CBC');
170 $iv = substr($raw, 0, $ivLength);
171 $encrypted_data = substr($raw, $ivLength);
173 return openssl_decrypt(
174 $encrypted_data,
175 'AES-256-CBC',
176 $sSecretKey,
177 OPENSSL_RAW_DATA,
182 // Function to decrypt a given string
183 // This specific function is only used for backward compatibility
184 function aes256Decrypt_mycrypt($sValue)
186 $sSecretKey = pack('H*', "bcb04b7e103a0cd8b54763051cef08bc55abe029fdebae5e1d417e2ffb2a00a3");
187 return rtrim(
188 mcrypt_decrypt(
189 MCRYPT_RIJNDAEL_256,
190 $sSecretKey,
191 base64_decode($sValue),
192 MCRYPT_MODE_ECB,
193 mcrypt_create_iv(
194 mcrypt_get_iv_size(
195 MCRYPT_RIJNDAEL_256,
196 MCRYPT_MODE_ECB
198 MCRYPT_RAND
201 "\0"
205 // Function to collect (and create, if needed) the standard key
206 // The key is stored at sites/<site-dir>/documents/logs_and_misc/methods/one
207 // This mechanism will allow easy migration to new keys/ciphers in the future while
208 // also maintaining backward compatibility of encrypted data (for example, if upgrade
209 // to another cipher/mode, then could place the new key for this in
210 // sites/<site-dir>/documents/logs_and_misc/methods/two and then adjust pertinent code).
211 function aes256PrepKey($version = "one", $sub = "")
213 // Build the label
214 $label = $version.$sub;
216 // Collect the key. If it does not exist, then create it
217 if (!file_exists($GLOBALS['OE_SITE_DIR'] . "/documents/logs_and_misc/methods/" . $label)) {
218 // Create a key file
220 try {
221 // Produce a 256bit key (32 bytes equals 256 bits)
222 $newKey = random_bytes(32);
223 } catch (Error $e) {
224 error_log('OpenEMR Error : Encryption is not working because of random_bytes() Error: ' . $e->getMessage());
225 } catch (Exception $e) {
226 error_log('OpenEMR Error : Encryption is not working because of random_bytes() Exception: ' . $e->getMessage());
229 file_put_contents($GLOBALS['OE_SITE_DIR'] . "/documents/logs_and_misc/methods/". $label, base64_encode($newKey));
232 // Collect key from file
233 $key = base64_decode(rtrim(file_get_contents($GLOBALS['OE_SITE_DIR'] . "/documents/logs_and_misc/methods/" . $label)));
235 if (empty($key)) {
236 error_log("OpenEMR Error : Key creation is not working.");
239 // Return the key
240 return $key;