PageRenderTime 62ms CodeModel.GetById 24ms RepoModel.GetById 1ms app.codeStats 0ms

/src/PortePlugins/Crypt.php

https://github.com/pop/porte
PHP | 176 lines | 125 code | 11 blank | 40 comment | 19 complexity | 66d560fef22d1bea08b29062ac948d2e MD5 | raw file
  1. <?php
  2. /**
  3. * Copyright (c) 2008, SARL Adaltas. All rights reserved.
  4. * Code licensed under the BSD License:
  5. * http://www.php-pop.org/porte/license.html
  6. */
  7. /**
  8. * Plugin to store crypted content into the database.
  9. *
  10. * @author David Worms info(at)adaltas.com
  11. * @copyright 2008-2009 Adaltas
  12. */
  13. class PortePlugins_Crypt{
  14. public static $methods = array('AES'=>array('ECB'));
  15. /**
  16. * Register the plugin with a Porte instance.
  17. */
  18. public static function register(Porte $porte){
  19. PorteEvents::connect('model_property_before',array('PortePlugins_Crypt','_modelPropertyBefore'));
  20. }
  21. public static function _modelPropertyBefore($models,$type,$property){
  22. $model = $models->{$type};
  23. $propertyModel = $model['properties'][$property];
  24. if(!empty($propertyModel['crypt'])){
  25. switch(gettype($propertyModel['crypt'])){
  26. case 'boolean';
  27. case 'integer';
  28. $propertyModel['crypt'] = array(
  29. 'method' => 'AES');
  30. break;
  31. case 'string';
  32. $propertyModel['crypt'] = array(
  33. 'method' => 'AES',
  34. 'key'=>$propertyModel['crypt']);
  35. break;
  36. case 'array':
  37. // ok
  38. break;
  39. default:
  40. throw new PorteException('Invalid AES configuration "'.$type.'.'.$property.'": "'.PurLang::toString($propertyModel).'"');
  41. }
  42. if(!empty($models->config->crypt)){
  43. $propertyModel['crypt'] = array_merge($models->config->crypt,$propertyModel['crypt']);
  44. }else if(!empty($model['crypt'])){
  45. $propertyModel['crypt'] = array_merge($model['crypt'],$propertyModel['crypt']);
  46. }
  47. if(empty($propertyModel['crypt']['hex'])){
  48. $propertyModel['crypt']['hex'] = false;
  49. }
  50. if(array_key_exists('method',$propertyModel['crypt'])&&empty($propertyModel['crypt']['method'])){
  51. // it's ok, if method is defined but null or empty,
  52. // we only convert the value to hexadecimal
  53. $propertyModel['crypt']['method'] = null;
  54. }else if(empty($propertyModel['crypt']['method'])){
  55. $propertyModel['crypt']['method'] = 'AES';
  56. }else{
  57. $propertyModel['crypt']['method'] = strtoupper($propertyModel['crypt']['method']);
  58. if(!in_array($propertyModel['crypt']['method'],array_keys(self::$methods))){
  59. throw new PorteException('Incryption method not supported in "'.$type.'.'.$property.'": "'.$propertyModel['crypt']['method'].'"');
  60. }
  61. }
  62. if($propertyModel['crypt']['method']){
  63. if(empty($propertyModel['crypt']['mode'])){
  64. $propertyModel['crypt']['mode'] = self::$methods[$propertyModel['crypt']['method']][0];
  65. }else{
  66. $propertyModel['crypt']['mode'] = strtoupper($propertyModel['crypt']['mode']);
  67. }
  68. if(empty($propertyModel['crypt']['key'])){
  69. throw new PorteException('No available encryption key in "'.$type.'.'.$property.'"');
  70. }
  71. }
  72. $propertyModel['type'] = 'string';
  73. $propertyModel['class'] = 'PortePlugins_CryptType';
  74. $models->{$type}['properties'][$property] = $propertyModel;
  75. }
  76. }
  77. /**
  78. * Encryp the value with the AES 128 algorythm and convert it
  79. * into an hexadecimal representation.
  80. *
  81. * The result is Mysql compatible with the following statement:
  82. *
  83. * HEX(AES_ENCRYPT($value))
  84. *
  85. * Convert into an hexadecimal representation and crypt
  86. * AES 128 compatible mysql HEX(AES_ENCRYPT()) of a srting value
  87. *
  88. * @return string The string in hexadecimal
  89. * @param string $value The string to crypt
  90. * @param string $key The key for crypt
  91. */
  92. public static function encrypt($value, array $options) {
  93. if(empty($value)){
  94. return null;
  95. }
  96. if(!empty($options['method'])){
  97. switch($options['method']){
  98. case 'AES':
  99. if(empty($options['key'])){
  100. throw new InvalidArgumentException('No decrypt key provided');
  101. }
  102. $mode = constant('MCRYPT_MODE_'.$options['mode']);
  103. $value = mcrypt_encrypt(
  104. MCRYPT_RIJNDAEL_128,
  105. $options['key'],
  106. str_pad(
  107. $value,
  108. (16*(floor(strlen($value) / 16)+1)),
  109. chr(16-(strlen($value) % 16))),
  110. $mode,
  111. mcrypt_create_iv(
  112. mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, $mode),
  113. MCRYPT_DEV_URANDOM));
  114. break;
  115. default:
  116. throw new PorteException('Unsupported encryption method: "'.$options['method'].'"');
  117. }
  118. }
  119. if(!empty($options['hex'])){
  120. $value = bin2hex($value);
  121. }
  122. return $value;
  123. }
  124. /**
  125. * Decrypt an AES 128 encoding value
  126. * stored as an hexadecimal representation into a string.
  127. *
  128. * @return string The converted string
  129. * @param string $hexValue The string to crypt
  130. * @param string $key The key for crypt
  131. */
  132. public static function decrypt($value, array $options) {
  133. if(empty($value)){
  134. return null;
  135. }
  136. if(!empty($options['hex'])){
  137. $value = pack('H*', $value);
  138. }
  139. if(!empty($options['method'])){
  140. switch($options['method']){
  141. case 'AES':
  142. $mode = constant('MCRYPT_MODE_'.$options['mode']);
  143. if(empty($options['key'])){
  144. throw new InvalidArgumentException('No decrypt key provided');
  145. }
  146. $mode = constant('MCRYPT_MODE_'.$options['mode']);
  147. $value = mcrypt_decrypt(
  148. MCRYPT_RIJNDAEL_128,
  149. $options['key'],
  150. $value,
  151. $mode,
  152. mcrypt_create_iv(
  153. mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, $mode),
  154. MCRYPT_DEV_URANDOM ) );
  155. $value = rtrim(
  156. $value,
  157. ((ord(substr($value, strlen($value)-1, 1 )) >= 0 && ord(substr($value, strlen($value)-1, 1 ) ) <= 16 ) ? chr(ord(substr($value, strlen($value)-1, 1 ))): null) );
  158. break;
  159. default:
  160. throw new PorteException('Unsupported encryption method: "'.$options['method'].'"');
  161. }
  162. }
  163. return $value;
  164. }
  165. }