encrypt.inc 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. <?php
  2. /**
  3. * @file
  4. * Utility class definition.
  5. */
  6. /**
  7. * Handles encryption of credit-card information.
  8. *
  9. * Trimmed down version of GPL class by Tony Marston. Details available at
  10. * http://www.tonymarston.co.uk/php-mysql/encryption.html
  11. *
  12. * Usage:
  13. * 1) Create an encryption object.
  14. * ex: $crypt = new UbercartEncryption();
  15. * 2) To encrypt string data, use the encrypt method with the key.
  16. * ex: $encrypted = $crypt->encrypt($key, $string);
  17. * 3) To decrypt string data, use the decrypt method with the original key.
  18. * ex: $decrypted = $crypt->decrypt($key, $string);
  19. * 4) To check for errors, use the errors method to return an array of errors.
  20. * ex: $errors = $crypt->getErrors();
  21. */
  22. class UbercartEncryption {
  23. protected static $scramble1 = '! #$%&()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`"abcdefghijklmnopqrstuvwxyz{|}~';
  24. protected static $scramble2 = 'f^jAE]okIOzU[2&q1{3`h5w_794p@6s8?BgP>dFV=m" D<TcS%Ze|r:lGK/uCy.Jx)HiQ!#$~(;Lt-R}Ma,NvW+Ynb*0X';
  25. protected $errors = array();
  26. protected $adj = 1.75;
  27. protected $mod = 3;
  28. /**
  29. * Decrypts cyphertext.
  30. *
  31. * @param $key
  32. * String key used for encryption.
  33. * @param $source
  34. * Cyphertext. Text string containing encrypted $source.
  35. *
  36. * @return
  37. * Plaintext. Text string to be encrypted.
  38. */
  39. public function decrypt($key, $source) {
  40. $this->errors = array();
  41. // Convert key into sequence of numbers
  42. $fudgefactor = $this->convertKey($key);
  43. if ($this->errors) {
  44. return;
  45. }
  46. if (empty($source)) {
  47. // Commented out to prevent errors getting logged for use cases that may
  48. // have variable encryption/decryption requirements. -RS
  49. // $this->errors[] = t('No value has been supplied for decryption');
  50. return;
  51. }
  52. $target = NULL;
  53. $factor2 = 0;
  54. for ($i = 0; $i < strlen($source); $i++) {
  55. $char2 = substr($source, $i, 1);
  56. $num2 = strpos(self::$scramble2, $char2);
  57. if ($num2 === FALSE) {
  58. $this->errors[] = t('Source string contains an invalid character (@char)', array('@char' => $char2));
  59. return;
  60. }
  61. $adj = $this->applyFudgeFactor($fudgefactor);
  62. $factor1 = $factor2 + $adj;
  63. $num1 = $num2 - round($factor1);
  64. $num1 = $this->checkRange($num1);
  65. $factor2 = $factor1 + $num2;
  66. $char1 = substr(self::$scramble1, $num1, 1);
  67. $target .= $char1;
  68. }
  69. return rtrim($target);
  70. }
  71. /**
  72. * Encrypts plaintext.
  73. *
  74. * @param $key
  75. * String key used for encryption.
  76. * @param $source
  77. * Plaintext. Text string to be encrypted.
  78. * @param $sourcelen
  79. * Minimum plaintext length. Plaintext $source which is shorter than
  80. * $sourcelen will be padded by appending spaces.
  81. *
  82. * @return
  83. * Cyphertext. Text string containing encrypted $source.
  84. */
  85. public function encrypt($key, $source, $sourcelen = 0) {
  86. $this->errors = array();
  87. // Convert key into sequence of numbers
  88. $fudgefactor = $this->convertKey($key);
  89. if ($this->errors) {
  90. return;
  91. }
  92. if (empty($source)) {
  93. // Commented out to prevent errors getting logged for use cases that may
  94. // have variable encryption/decryption requirements. -RS
  95. // $this->errors[] = t('No value has been supplied for encryption');
  96. return;
  97. }
  98. while (strlen($source) < $sourcelen) {
  99. $source .= ' ';
  100. }
  101. $target = NULL;
  102. $factor2 = 0;
  103. for ($i = 0; $i < drupal_strlen($source); $i++) {
  104. $char1 = drupal_substr($source, $i, 1);
  105. $num1 = strpos(self::$scramble1, $char1);
  106. if ($num1 === FALSE) {
  107. $this->errors[] = t('Source string contains an invalid character (@char)', array('@char' => $char1));
  108. return;
  109. }
  110. $adj = $this->applyFudgeFactor($fudgefactor);
  111. $factor1 = $factor2 + $adj;
  112. $num2 = round($factor1) + $num1;
  113. $num2 = $this->checkRange($num2);
  114. $factor2 = $factor1 + $num2;
  115. $char2 = substr(self::$scramble2, $num2, 1);
  116. $target .= $char2;
  117. }
  118. return $target;
  119. }
  120. /**
  121. * Accessor for errors property.
  122. */
  123. public function getErrors() {
  124. return $this->errors;
  125. }
  126. /**
  127. * Mutator for errors property.
  128. */
  129. public function setErrors(array $errors) {
  130. $this->errors = $errors;
  131. }
  132. /**
  133. * Accessor for adj property.
  134. */
  135. public function getAdjustment() {
  136. return $this->adj;
  137. }
  138. /**
  139. * Mutator for adj property.
  140. */
  141. public function setAdjustment($adj) {
  142. $this->adj = (float) $adj;
  143. }
  144. /**
  145. * Accessor for mod property.
  146. */
  147. public function getModulus() {
  148. return $this->mod;
  149. }
  150. /**
  151. * Mutator for mod property.
  152. */
  153. public function setModulus($mod) {
  154. $this->mod = (int) abs($mod);
  155. }
  156. /**
  157. * Returns an adjustment value based on the contents of $fudgefactor.
  158. */
  159. protected function applyFudgeFactor(&$fudgefactor) {
  160. static $alerted = FALSE;
  161. if (!is_array($fudgefactor)) {
  162. $fudge = 0;
  163. if (!$alerted) {
  164. // Throw an error that makes sense so this stops getting reported.
  165. $this->errors[] = t('No encryption key was found.');
  166. drupal_set_message(t('Ubercart cannot find a necessary encryption key. Refer to the store admin <a href="@url">dashboard</a> to isolate which one.', array('@url' => url('admin/store'))), 'error');
  167. $alerted = TRUE;
  168. }
  169. }
  170. else {
  171. $fudge = array_shift($fudgefactor);
  172. }
  173. $fudge = $fudge + $this->adj;
  174. $fudgefactor[] = $fudge;
  175. if (!empty($this->mod)) {
  176. if ($fudge % $this->mod == 0) {
  177. $fudge = $fudge * -1;
  178. }
  179. }
  180. return $fudge;
  181. }
  182. /**
  183. * Checks that $num points to an entry in self::$scramble1.
  184. */
  185. protected function checkRange($num) {
  186. $num = round($num);
  187. $limit = strlen(self::$scramble1);
  188. while ($num >= $limit) {
  189. $num = $num - $limit;
  190. }
  191. while ($num < 0) {
  192. $num = $num + $limit;
  193. }
  194. return $num;
  195. }
  196. /**
  197. * Converts encryption key into an array of numbers.
  198. *
  199. * @param $key
  200. * Encryption key.
  201. *
  202. * @return
  203. * Array of integers.
  204. */
  205. protected function convertKey($key) {
  206. if (empty($key)) {
  207. // Commented out to prevent errors getting logged for use cases that may
  208. // have variable encryption/decryption requirements. -RS
  209. // $this->errors[] = 'No value has been supplied for the encryption key';
  210. return;
  211. }
  212. $array[] = strlen($key);
  213. $tot = 0;
  214. for ($i = 0; $i < strlen($key); $i++) {
  215. $char = substr($key, $i, 1);
  216. $num = strpos(self::$scramble1, $char);
  217. if ($num === FALSE) {
  218. $this->errors[] = t('Key contains an invalid character (@char)', array('@char' => $char));
  219. return;
  220. }
  221. $array[] = $num;
  222. $tot = $tot + $num;
  223. }
  224. $array[] = $tot;
  225. return $array;
  226. }
  227. }