ice framework documentation ice doc v1.10.1
Class Ice

Crypt

  1. namespace Ice;
  2.  
  3. /**
  4. * The Crypt library provides two-way encryption of text.
  5. *
  6. * @package Ice/Crypt
  7. * @category Library
  8. * @author Ice Team
  9. * @copyright (c) 2014-2023 Ice Team
  10. * @license http://iceframework.org/license
  11. * @uses openSSL
  12. */
  13. class Crypt
  14. {
  15. protected key { set };
  16. protected cipher = "aes-256" { set };
  17. protected mode = "cbc" { set };
  18. protected block = 16 { set };
  19.  
  20. /**
  21. * Create a new encrypter instance.
  22. *
  23. * @param string key
  24. * @return void
  25. */
  26. public function __construct(string key = null)
  27. {
  28. let this->key = key;
  29. }
  30.  
  31. /**
  32. * Encrypt the given value.
  33. *
  34. * @param string text
  35. * @return string
  36. */
  37. public function encrypt(string text) -> string
  38. {
  39. var iv, value, mac;
  40.  
  41. let iv = this->generateInputVector(),
  42. value = this->addPadding(serialize(text)),
  43. value = base64_encode(this->doEncrypt(value, iv));
  44.  
  45. // Once we have the encrypted value we will go ahead base64_encode the input
  46. // vector and create the MAC for the encrypted value so we can verify its
  47. // authenticity. Then, we'll JSON encode the data in a "payload" array.
  48. let iv = base64_encode(iv),
  49. mac = this->hash(value);
  50.  
  51. return base64_encode(json_encode([
  52. "iv": iv,
  53. "value": value,
  54. "mac": mac
  55. ]));
  56. }
  57.  
  58. /**
  59. * Generate an input vector.
  60. *
  61. * @return string
  62. */
  63. protected function generateInputVector() ->string
  64. {
  65. return openssl_random_pseudo_bytes(this->getIvSize());
  66. }
  67.  
  68. /**
  69. * Actually encrypt the value using the given Iv with the openssl library encrypt function.
  70. *
  71. * @param string value
  72. * @param string iv
  73. * @return string
  74. */
  75. protected function doEncrypt(string value, string iv) -> string
  76. {
  77. return openssl_encrypt(value, this->cipher . "-" . this->mode, this->key, OPENSSL_RAW_DATA, iv);
  78. }
  79.  
  80. /**
  81. * Decrypt the given value.
  82. *
  83. * @param string text payload
  84. * @return string
  85. */
  86. public function decrypt(string text) -> string
  87. {
  88. var value, payload, iv;
  89.  
  90. let payload = this->getJsonPayload(text);
  91.  
  92. // We'll go ahead and remove the PKCS7 padding from the encrypted value before
  93. // we decrypt it. Once we have the de-padded value, we will grab the vector
  94. // and decrypt the data, passing back the unserialized from of the value.
  95. let value = base64_decode(payload["value"]),
  96. iv = base64_decode(payload["iv"]);
  97.  
  98. return unserialize(this->stripPadding(this->doDecrypt(value, iv)));
  99. }
  100.  
  101. /**
  102. * Actually decrypt the value using the given Iv with the openssl library decrypt function.
  103. *
  104. * @param string value
  105. * @param string iv
  106. * @return string
  107. */
  108. protected function doDecrypt(string value, string iv) -> string
  109. {
  110. return openssl_decrypt(value, this->cipher . "-" . this->mode, this->key, OPENSSL_RAW_DATA, iv);
  111. }
  112.  
  113. /**
  114. * Get the JSON array from the given payload.
  115. *
  116. * @param string text payload
  117. * @return array
  118. */
  119. protected function getJsonPayload(string text) -> array
  120. {
  121. var payload;
  122.  
  123. let payload = [],
  124. payload = json_decode(base64_decode(text), true);
  125.  
  126. // If the payload is not valid JSON or does not have the proper keys set we will
  127. // assume it is invalid and bail out of the routine since we will not be able
  128. // to decrypt the given value. We'll also check the MAC for this encryption.
  129. if !payload || this->invalidPayload(payload) {
  130. throw new Exception("Invalid data passed to encrypter.");
  131. }
  132.  
  133. if payload["mac"] != this->hash(payload["value"]) {
  134. throw new Exception("MAC for payload is invalid.");
  135. }
  136.  
  137. return payload;
  138. }
  139.  
  140. /**
  141. * Create a MAC for the given value.
  142. *
  143. * @param string value
  144. * @return string
  145. */
  146. protected function hash(string value) -> string
  147. {
  148. return hash_hmac("sha256", value, this->key);
  149. }
  150.  
  151. /**
  152. * Add PKCS7 padding to a given value.
  153. *
  154. * @param string value
  155. * @return string
  156. */
  157. protected function addPadding(string value) -> string
  158. {
  159. var pad, len;
  160.  
  161. let len = strlen(value),
  162. pad = this->block - (len % this->block);
  163.  
  164. return value . str_repeat(chr(pad), pad);
  165. }
  166.  
  167. /**
  168. * Remove the padding from the given value.
  169. *
  170. * @param string value
  171. * @return string
  172. */
  173. protected function stripPadding(string value) -> string
  174. {
  175. var pad, len;
  176.  
  177. let len = (int) strlen(value),
  178. pad = (int) ord(value[len - 1]);
  179.  
  180. return this->paddingIsValid(pad, value) ? substr(value, 0, len - pad) : value;
  181. }
  182.  
  183. /**
  184. * Determine if the given padding for a value is valid.
  185. *
  186. * @param int pad
  187. * @param string value
  188. * @return bool
  189. */
  190. protected function paddingIsValid(int pad, string value) -> boolean
  191. {
  192. var beforePad;
  193.  
  194. let beforePad = strlen(value) - pad;
  195.  
  196. return substr(value, beforePad) == str_repeat(substr(value, -1), pad);
  197. }
  198.  
  199. /**
  200. * Verify that the encryption payload is valid.
  201. *
  202. * @param array data
  203. * @return bool
  204. */
  205. protected function invalidPayload(array data) -> boolean
  206. {
  207. return !isset data["iv"] || !isset data["value"] || !isset data["mac"];
  208. }
  209.  
  210. /**
  211. * Get the IV size for the cipher.
  212. *
  213. * @return int
  214. */
  215. protected function getIvSize() -> int
  216. {
  217. return openssl_cipher_iv_length(this->cipher . "-" . this->mode);
  218. }
  219. }