Mcrypt.php 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. <?php
  2. /**
  3. * The Encrypt Mcrypt engine provides two-way encryption of text and binary strings
  4. * using the [Mcrypt](http://php.net/mcrypt) extension, which consists of three
  5. * parts: the key, the cipher, and the mode.
  6. *
  7. * The Key
  8. * : A secret passphrase that is used for encoding and decoding
  9. *
  10. * The Cipher
  11. * : A [cipher](http://php.net/mcrypt.ciphers) determines how the encryption
  12. * is mathematically calculated. By default, the "rijndael-128" cipher
  13. * is used. This is commonly known as "AES-128" and is an industry standard.
  14. *
  15. * The Mode
  16. * : The [mode](http://php.net/mcrypt.constants) determines how the encrypted
  17. * data is written in binary form. By default, the "nofb" mode is used,
  18. * which produces short output with high entropy.
  19. *
  20. * @package Kohana/Encrypt
  21. * @author Kohana Team
  22. * @copyright (c) Kohana Team
  23. * @license https://koseven.ga/LICENSE.md
  24. */
  25. class Kohana_Encrypt_Engine_Mcrypt extends Kohana_Encrypt_Engine {
  26. /**
  27. * @var string RAND type to use
  28. *
  29. * Only MCRYPT_DEV_URANDOM and MCRYPT_DEV_RANDOM are considered safe.
  30. * Using MCRYPT_RAND will silently revert to MCRYPT_DEV_URANDOM
  31. */
  32. protected static $_rand = MCRYPT_DEV_URANDOM;
  33. /**
  34. * @var int the size of the Initialization Vector (IV) in bytes
  35. */
  36. protected $_iv_size;
  37. /**
  38. * Creates a new mcrypt wrapper.
  39. *
  40. * @param mixed $key_config mcrypt key or config array
  41. * @param string $mode mcrypt mode
  42. * @param string $cipher mcrypt cipher
  43. */
  44. public function __construct($key_config, $mode = NULL, $cipher = NULL)
  45. {
  46. if ($mode === NULL)
  47. {
  48. // Add the default mode
  49. $mode = MCRYPT_MODE_NOFB;
  50. }
  51. if ($cipher === NULL)
  52. {
  53. // Add the default cipher
  54. $cipher = MCRYPT_RIJNDAEL_128;
  55. }
  56. parent::__construct($key_config, $mode, $cipher);
  57. // Find the max length of the key, based on cipher and mode
  58. $size = mcrypt_get_key_size($this->_cipher, $this->_mode);
  59. if (isset($this->_key[$size]))
  60. {
  61. // Shorten the key to the maximum size
  62. $this->_key = substr($this->_key, 0, $size);
  63. }
  64. else
  65. {
  66. $this->_key = $this->_normalize_key($this->_key, $this->_cipher, $this->_mode);
  67. }
  68. /*
  69. * Silently use MCRYPT_DEV_URANDOM when the chosen random number generator
  70. * is not one of those that are considered secure.
  71. */
  72. if ((Encrypt_Engine_Mcrypt::$_rand !== MCRYPT_DEV_URANDOM) AND (Encrypt_Engine_Mcrypt::$_rand !== MCRYPT_DEV_RANDOM))
  73. {
  74. Encrypt_Engine_Mcrypt::$_rand = MCRYPT_DEV_URANDOM;
  75. }
  76. // Store the IV size
  77. $this->_iv_size = mcrypt_get_iv_size($this->_cipher, $this->_mode);
  78. }
  79. /**
  80. * Encrypts a string and returns an encrypted string that can be decoded.
  81. *
  82. * $data = $encrypt->encode($data);
  83. *
  84. * The encrypted binary data is encoded using [base64](http://php.net/base64_encode)
  85. * to convert it to a string. This string can be stored in a database,
  86. * displayed, and passed using most other means without corruption.
  87. *
  88. * @param string $data data to be encrypted
  89. * @return string
  90. */
  91. public function encrypt($data, $iv)
  92. {
  93. // Encrypt the data using the configured options and generated iv
  94. $data = mcrypt_encrypt($this->_cipher, $this->_key, $data, $this->_mode, $iv);
  95. // Use base64 encoding to convert to a string
  96. return base64_encode($iv.$data);
  97. }
  98. /**
  99. * Decrypts an encoded string back to its original value.
  100. *
  101. * $data = $encrypt->decode($data);
  102. *
  103. * @param string $data encoded string to be decrypted
  104. * @return FALSE if decryption fails
  105. * @return string
  106. */
  107. public function decrypt($data)
  108. {
  109. // Convert the data back to binary
  110. $data = base64_decode($data, TRUE);
  111. if ( ! $data)
  112. {
  113. // Invalid base64 data
  114. return FALSE;
  115. }
  116. // Extract the initialization vector from the data
  117. $iv = substr($data, 0, $this->_iv_size);
  118. if ($this->_iv_size !== strlen($iv))
  119. {
  120. // The iv is not the expected size
  121. return FALSE;
  122. }
  123. // Remove the iv from the data
  124. $data = substr($data, $this->_iv_size);
  125. // Return the decrypted data, trimming the \0 padding bytes from the end of the data
  126. return rtrim(mcrypt_decrypt($this->_cipher, $this->_key, $data, $this->_mode, $iv), "\0");
  127. }
  128. /**
  129. * Proxy for the mcrypt_create_iv function - to allow mocking and testing against KAT vectors
  130. *
  131. * @return string the initialization vector or FALSE on error
  132. */
  133. public function create_iv()
  134. {
  135. // Create a random initialization vector of the proper size for the current cipher
  136. return mcrypt_create_iv($this->_iv_size, Encrypt_Engine_Mcrypt::$_rand);
  137. }
  138. /**
  139. * Normalize key for PHP 5.6 for backwards compatibility
  140. *
  141. * This method is a shim to make PHP 5.6 behave in a B/C way for
  142. * legacy key padding when shorter-than-supported keys are used
  143. *
  144. * @param string $key encryption key
  145. * @param string $cipher mcrypt cipher
  146. * @param string $mode mcrypt mode
  147. */
  148. protected function _normalize_key($key, $cipher, $mode)
  149. {
  150. // open the cipher
  151. $td = mcrypt_module_open($cipher, '', $mode, '');
  152. // loop through the supported key sizes
  153. foreach (mcrypt_enc_get_supported_key_sizes($td) as $supported) {
  154. // if key is short, needs padding
  155. if (strlen($key) <= $supported)
  156. {
  157. return str_pad($key, $supported, "\0");
  158. }
  159. }
  160. // at this point key must be greater than max supported size, shorten it
  161. return substr($key, 0, mcrypt_get_key_size($cipher, $mode));
  162. }
  163. }