encryption.module

This is the main module file for the encryption module.

File

modules/encryption/encryption.module
View source
  1. <?php
  2. /**
  3. * @file
  4. * This is the main module file for the encryption module.
  5. */
  6. /**
  7. * Implements hook_perm
  8. */
  9. function encryption_perm() {
  10. return array(
  11. "administer_encryption" => array(
  12. "title" => t("Administer encryption module"),
  13. "description" => t("Configure settings relating to the encryption module."),
  14. "admin_restricted" => TRUE, // means only appears for admin (user_id == 1)
  15. ),
  16. );
  17. }
  18. /**
  19. * Implements hook_menu
  20. */
  21. function encryption_menu() {
  22. $items = array();
  23. $items["admin/config/encryption"] = array(
  24. "title" => "Encryption settings",
  25. "description" => "Configure settings related to the encryption module.",
  26. "page_callback" => "fp_render_form",
  27. "page_arguments" => array("encryption_settings_form"),
  28. "access_arguments" => array("administer_encryption"),
  29. "page_settings" => array(
  30. "menu_icon" => fp_get_module_path('system') . "/icons/lock.png",
  31. "menu_links" => array(
  32. 0 => array(
  33. "text" => "Admin Console",
  34. "path" => "admin-tools/admin",
  35. "query" => "de_catalog_year=%DE_CATALOG_YEAR%",
  36. ),
  37. ),
  38. ),
  39. "type" => MENU_TYPE_NORMAL_ITEM,
  40. "tab_parent" => "admin-tools/admin",
  41. );
  42. return $items;
  43. }
  44. function encryption_settings_form() {
  45. $form = array();
  46. $hash = encryption_get_hash_protocol();
  47. $cipher = encryption_get_cipher_algorithm();
  48. if ($hash) {
  49. $form["encryption_markup_1"] = array(
  50. "value" => t("<br><br><b>The hash protocol your system supports is: %hash.</b>
  51. <br>This hash will be used
  52. to convert your key (specified below) into a uniform and unique string. If you ever switch servers,
  53. you must ensure the same hash protocol is available and being used, or your
  54. encrypted values will not be readable. You should make a note of which hash protocol
  55. your system is using. See the README.txt file for information on how to specify which
  56. protocol to use, if you do not wish to use %hash.<br><br>", array("%hash" => $hash)),
  57. );
  58. }
  59. else {
  60. // Couldn't find any values for hash!
  61. fp_add_message(t("This module will NOT work correctly, because no hash protocol could be found!
  62. Check your server settings and make sure this page does not display an error before
  63. attempting to use this module!"), "error");
  64. return $form;
  65. }
  66. if ($hash) {
  67. $form["encryption_markup_2"] = array(
  68. "value" => t("<b>The cipher algorithm your system supports is: %cipher.</b>
  69. <br>This cipher will be used
  70. to actually encrypt and decrypt data. If you ever switch servers,
  71. you must ensure the same cipher is available and being used, or your
  72. encrypted values will not be readable. You should make a note of which cipher algorithm
  73. your system is using. See the README.txt file for information on how to specify which
  74. protocol to use, if you do not wish to use %cipher.<br><br>", array("%cipher" => $cipher)),
  75. );
  76. }
  77. else {
  78. // Couldn't find any values for hash!
  79. fp_add_message(t("This module will NOT work correctly, because no cipher protocol could be found!
  80. Check your server settings and make sure this page does not display an error before
  81. attempting to use this module!"), "error");
  82. return $form;
  83. }
  84. $form['mark_encryption_key_string'] = array(
  85. 'value' => t("<p><b>Encryption Key</b><br>
  86. To add an encryption key string, edit your settings.php file and add a variable like so:
  87. <br> &nbsp; &nbsp; <code>\$GLOBALS['encryption_key_string'] = 'random text goes here';</code>
  88. <br> Make your random text at least 32 characters long.</p>"),
  89. );
  90. if (!isset($GLOBALS['encryption_key_string'])) {
  91. $form['mark_encryption_key_string__notice'] = array(
  92. 'value' => t("<br><p><b>NOTE:</b> <u>No encryption key found</u> in your settings.php file. This module will not function correctly without either
  93. a key set in your settings.php file or as a text file below.</p>"),
  94. );
  95. }
  96. else {
  97. $form['mark_encryption_key_string__found'] = array(
  98. 'value' => t("<p><b>NOTE:</b> <u>Encryption key WAS found</u> in your settings.php file. Make sure to store the key in a safe place. If you lose the key,
  99. you will not be able to decrypt encrypted values or files.</p>"),
  100. );
  101. }
  102. $form["encryption_key_path"] = array(
  103. "label" => t("Encryption Key File Absolute Path:"),
  104. "type" => "textfield",
  105. "maxlength" => 255,
  106. "value" => variable_get("encryption_key_path", ""),
  107. "description" => t("If you prefer, you may enter your key string into a file, then store that file somewhere on your server. Enter
  108. the absolute path to the file here. Ex: /var/misc/key/my-key.txt. It should be in a location outside of the webroot,
  109. which web users couldn't get to by guessing a URL.
  110. If you enter anything here, the encryption key above will be ignored.
  111. <br><br><b>WARNING: DO NOT CHANGE THE KEY VALUE</b> once you have decided
  112. on a key. Doing so will cause <b>all previously encrypted files or values to be unreadable.</b>"),
  113. );
  114. $form["encryption_files_encryption"] = array(
  115. "type" => "select",
  116. "label" => "Encrypt uploaded files?",
  117. "options" => array("yes" => t("Yes"), "no" => t("No")),
  118. "value" => variable_get("encryption_files_encryption", "yes"),
  119. "description" => t("When files are uploaded or attached to a piece of content (for example, an email attachment or text message attachment)
  120. they can be automatically encrypted before being saved to the server. Do you wish
  121. to do this? If so, the extension \".enc\" will be added to the end of encrypted files.
  122. When files are downloaded through the Encryption module, they will be automatically decrypted
  123. for the end user.
  124. <br><br>
  125. Note: this does not affect files uploaded to a student's History tab. To configure
  126. encryption of those files, see the Student Files settings page."),
  127. "prefix" => "<fieldset><legend>" . t("Encryption Settings") . "</legend>",
  128. "suffix" => "</fieldset>",
  129. );
  130. $form["encryption_confirm"] = array(
  131. "label" => "Are you sure you want to save changes?",
  132. "type" => "textfield",
  133. "size" => 10,
  134. "required" => TRUE,
  135. "description" => t("If you are certain you wish to save changes to this form, enter YES (all caps)."),
  136. );
  137. $form["submit_btn"] = array(
  138. "type" => "submit",
  139. "value" => "Submit",
  140. );
  141. return $form;
  142. }
  143. function encryption_settings_form_validate($form, $form_state) {
  144. // Did the user enter "YES" to the confirmation question?
  145. if (trim($form_state["values"]["encryption_confirm"]) != "YES") {
  146. form_error("encryption_confirm", t("To submit this form, you must enter YES (all caps) in the confirmation box."));
  147. return;
  148. }
  149. // If they entered a path to the file, make sure it exists and we can read it.
  150. if ($encryption_key_path != "") {
  151. $contents = file_get_contents($encryption_key_path);
  152. if (!$contents) {
  153. form_error("encryption_key_path", t("You entered a path to a key file, but either that file doesn't exist, is empty, or is unreadable by the
  154. web user on your system. Please correct the issue and try again."));
  155. return;
  156. }
  157. }
  158. }
  159. /**
  160. * The submit handler
  161. */
  162. function encryption_settings_form_submit($form, $form_state) {
  163. $encryption_key_path = trim($form_state["values"]["encryption_key_path"]);
  164. // We made it here, so its safe to save everything.
  165. variable_set("encryption_key_path", $encryption_key_path);
  166. fp_add_message(t("Your encryption settings have been saved. A reminder: if you change these settings after encrypting
  167. files or values, those files will no longer be readable. Save your encryption key value (whether in a file
  168. or in settings.php as a string) in a safe place."));
  169. }
  170. /**
  171. * Returns back a suitable key, either from our string or file location.
  172. *
  173. * We are going to convert either one into a SHA1 string
  174. */
  175. function encryption_get_key() {
  176. $encryption_key_path = trim(variable_get("encryption_key_path", ""));
  177. if ($encryption_key_path != "") {
  178. $contents = trim(file_get_contents($encryption_key_path));
  179. if ($contents) {
  180. $encryption_key_string = openssl_digest($contents, "sha256", TRUE);
  181. }
  182. }
  183. else {
  184. if (!isset($GLOBALS['encryption_key_string'])) {
  185. fp_add_message("No encryption key has been set. The encrypt module will cause unforseen problems.", "error");
  186. return FALSE;
  187. }
  188. $encryption_key_string = openssl_digest($GLOBALS['encryption_key_string'], "sha256", TRUE);
  189. }
  190. if (!$encryption_key_string) {
  191. fp_add_message("No encryption key has been set. The encrypt module will cause unforseen problems. Do not proceed until this issue is corrected.", "error");
  192. return FALSE;
  193. }
  194. /*
  195. //I don't think this is true anymore...
  196. // The key must be a smaller size than the hash algorithm we have chosen. This is because our AES encryption is 128 bit, meaning
  197. // they key must be 256 bits or less (32 characters). We will take a substring for 32 chars in this case.
  198. //$encryption_key_string = substr($encryption_key_string, 0, 32);
  199. */
  200. return $encryption_key_string;
  201. }
  202. /**
  203. * This looks at the hash_algos() return to see if we can use SHA256, else return FALSE.
  204. *
  205. * You can override which hash is used by adding
  206. * $GLOBALS["encryption_hash"] = "PROTOCOL HERE";
  207. * to the settings.php file.
  208. *
  209. *
  210. */
  211. function encryption_get_hash_protocol() {
  212. if (isset($GLOBALS["encryption_hash"])) return $GLOBALS["encryption_hash"];
  213. $arr = openssl_get_md_methods();
  214. if (in_array("sha256", $arr)) return "sha256";
  215. return FALSE;
  216. }
  217. /**
  218. * Similar to the function above, this finds the "best" cipher which the server can support.
  219. * Or, it can be manually set in the settings.php file by entering:
  220. * $GLOBALS['encryption_cipher'] = 'NAME OF CIPHER';
  221. */
  222. function encryption_get_cipher_algorithm() {
  223. if (isset($GLOBALS["encryption_cipher"])) return $GLOBALS["encryption_cipher"];
  224. $arr = openssl_get_cipher_methods();
  225. if (in_array('aes-256-cbc', $arr)) return 'aes-256-cbc';
  226. if (in_array('aes-256-ctr', $arr)) return 'aes-256-ctr';
  227. if (in_array('aes-256-cfb', $arr)) return 'aes-256-cfb';
  228. if (in_array('aes-128-cbc', $arr)) return 'aes-128-cbc';
  229. if (in_array('aes-128-ctr', $arr)) return 'aes-128-ctr';
  230. if (in_array('aes-128-cfb', $arr)) return 'aes-128-cfb';
  231. return FALSE;
  232. }
  233. // Credit: Some of this code is based on answers on this StackOverflow page:
  234. // https://stackoverflow.com/questions/48017856/correct-way-to-use-php-openssl-encrypt
  235. function encryption_encrypt($plain_contents) {
  236. $cipher = encryption_get_cipher_algorithm();
  237. $key = encryption_get_key();
  238. $plaintext = base64_encode($plain_contents); // convert to base64 so binary will work as well as text files.
  239. $ivlen = openssl_cipher_iv_length($cipher);
  240. $iv = openssl_random_pseudo_bytes($ivlen);
  241. // replace OPENSSL_RAW_DATA & $iv with 0 & bin2hex($iv) for hex cipher (eg. for transmission over internet)
  242. $ciphertext_raw = openssl_encrypt($plaintext, $cipher, $key, OPENSSL_RAW_DATA, $iv);
  243. // increase security with hashed cipher; (hex or base64 printable eg. for transmission over internet)
  244. $hmac = hash_hmac("sha256", $ciphertext_raw, $key, true);
  245. return base64_encode($iv . $hmac . $ciphertext_raw);
  246. }
  247. /**
  248. * This will decrypt an encrypted string.
  249. */
  250. function encryption_decrypt($ciphertext) {
  251. $c = base64_decode($ciphertext);
  252. $cipher = encryption_get_cipher_algorithm();
  253. $key = encryption_get_key();
  254. $ivlen = openssl_cipher_iv_length($cipher);
  255. $iv = substr($c, 0, $ivlen);
  256. $hmac = substr($c, $ivlen, $sha2len = 32);
  257. $ciphertext_raw = substr($c, $ivlen + $sha2len);
  258. $original_plaintext = openssl_decrypt($ciphertext_raw, $cipher, $key, OPENSSL_RAW_DATA, $iv);
  259. $calcmac = hash_hmac("sha256", $ciphertext_raw, $key, true);
  260. if ($calcmac && $hmac) {
  261. if (hash_equals($hmac, $calcmac)) return base64_decode($original_plaintext);
  262. }
  263. return FALSE;
  264. }

Functions

Namesort descending Description
encryption_decrypt This will decrypt an encrypted string.
encryption_encrypt
encryption_get_cipher_algorithm Similar to the function above, this finds the "best" cipher which the server can support. Or, it can be manually set in the settings.php file by entering: $GLOBALS['encryption_cipher'] = 'NAME OF CIPHER';
encryption_get_hash_protocol This looks at the hash_algos() return to see if we can use SHA256, else return FALSE.
encryption_get_key Returns back a suitable key, either from our string or file location.
encryption_menu Implements hook_menu
encryption_perm Implements hook_perm
encryption_settings_form
encryption_settings_form_submit The submit handler
encryption_settings_form_validate