PageRenderTime 52ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/wp-content/plugins/wordfence/modules/login-security/classes/model/crypto/base2n.php

https://bitbucket.org/frogdog/noveosdx
PHP | 304 lines | 177 code | 50 blank | 77 comment | 38 complexity | 74b8b00f5e4927dc5d21afb2d206b3f1 MD5 | raw file
Possible License(s): GPL-2.0, MIT, GPL-3.0, 0BSD, BSD-3-Clause, Apache-2.0
  1. <?php
  2. namespace WordfenceLS\Crypto;
  3. /**
  4. * Binary-to-text PHP Utilities
  5. *
  6. * @package binary-to-text-php
  7. * @link https://github.com/ademarre/binary-to-text-php
  8. * @author Andre DeMarre
  9. * @copyright 2009-2013 Andre DeMarre
  10. * @license http://opensource.org/licenses/MIT MIT
  11. */
  12. /**
  13. * Class for binary-to-text encoding with a base of 2^n
  14. *
  15. * The Base2n class is for binary-to-text conversion. It employs a
  16. * generalization of the algorithms used by many encoding schemes that
  17. * use a fixed number of bits to encode each character. In other words,
  18. * the base is a power of 2.
  19. *
  20. * Earlier versions of this class were named
  21. * FixedBitNotation and FixedBitEncoding.
  22. *
  23. * @package binary-to-text-php
  24. */
  25. class Model_Base2n
  26. {
  27. protected $_chars;
  28. protected $_bitsPerCharacter;
  29. protected $_radix;
  30. protected $_rightPadFinalBits;
  31. protected $_padFinalGroup;
  32. protected $_padCharacter;
  33. protected $_caseSensitive;
  34. protected $_charmap;
  35. /**
  36. * Constructor
  37. *
  38. * @param integer $bitsPerCharacter Bits to use for each encoded character
  39. * @param string $chars Base character alphabet
  40. * @param boolean $caseSensitive To decode in a case-sensitive manner
  41. * @param boolean $rightPadFinalBits How to encode last character
  42. * @param boolean $padFinalGroup Add padding to end of encoded output
  43. * @param string $padCharacter Character to use for padding
  44. *
  45. * @throws InvalidArgumentException for incompatible parameters
  46. */
  47. public function __construct(
  48. $bitsPerCharacter,
  49. $chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_',
  50. $caseSensitive = TRUE, $rightPadFinalBits = FALSE,
  51. $padFinalGroup = FALSE, $padCharacter = '=')
  52. {
  53. // Ensure validity of $chars
  54. if (!is_string($chars) || ($charLength = strlen($chars)) < 2) {
  55. throw new \InvalidArgumentException('$chars must be a string of at least two characters');
  56. }
  57. // Ensure validity of $padCharacter
  58. if ($padFinalGroup) {
  59. if (!is_string($padCharacter) || !isset($padCharacter[0])) {
  60. throw new \InvalidArgumentException('$padCharacter must be a string of one character');
  61. }
  62. if ($caseSensitive) {
  63. $padCharFound = strpos($chars, $padCharacter[0]);
  64. } else {
  65. $padCharFound = stripos($chars, $padCharacter[0]);
  66. }
  67. if ($padCharFound !== FALSE) {
  68. throw new \InvalidArgumentException('$padCharacter can not be a member of $chars');
  69. }
  70. }
  71. // Ensure validity of $bitsPerCharacter
  72. if (!is_int($bitsPerCharacter)) {
  73. throw new \InvalidArgumentException('$bitsPerCharacter must be an integer');
  74. }
  75. if ($bitsPerCharacter < 1) {
  76. // $bitsPerCharacter must be at least 1
  77. throw new \InvalidArgumentException('$bitsPerCharacter can not be less than 1');
  78. } elseif ($charLength < 1 << $bitsPerCharacter) {
  79. // Character length of $chars is too small for $bitsPerCharacter
  80. // Find greatest acceptable value of $bitsPerCharacter
  81. $bitsPerCharacter = 1;
  82. $radix = 2;
  83. while ($charLength >= ($radix <<= 1) && $bitsPerCharacter < 8) {
  84. $bitsPerCharacter++;
  85. }
  86. $radix >>= 1;
  87. throw new \InvalidArgumentException(
  88. '$bitsPerCharacter can not be more than ' . $bitsPerCharacter
  89. . ' given $chars length of ' . $charLength
  90. . ' (max radix ' . $radix . ')');
  91. } elseif ($bitsPerCharacter > 8) {
  92. // $bitsPerCharacter must not be greater than 8
  93. throw new \InvalidArgumentException('$bitsPerCharacter can not be greater than 8');
  94. } else {
  95. $radix = 1 << $bitsPerCharacter;
  96. }
  97. $this->_chars = $chars;
  98. $this->_bitsPerCharacter = $bitsPerCharacter;
  99. $this->_radix = $radix;
  100. $this->_rightPadFinalBits = $rightPadFinalBits;
  101. $this->_padFinalGroup = $padFinalGroup;
  102. $this->_padCharacter = $padCharacter[0];
  103. $this->_caseSensitive = $caseSensitive;
  104. }
  105. /**
  106. * Encode a string
  107. *
  108. * @param string $rawString Binary data to encode
  109. * @return string
  110. */
  111. public function encode($rawString)
  112. {
  113. // Unpack string into an array of bytes
  114. $bytes = unpack('C*', $rawString);
  115. $byteCount = count($bytes);
  116. $encodedString = '';
  117. $byte = array_shift($bytes);
  118. $bitsRead = 0;
  119. $oldBits = 0;
  120. $chars = $this->_chars;
  121. $bitsPerCharacter = $this->_bitsPerCharacter;
  122. $rightPadFinalBits = $this->_rightPadFinalBits;
  123. $padFinalGroup = $this->_padFinalGroup;
  124. $padCharacter = $this->_padCharacter;
  125. $charsPerByte = 8 / $bitsPerCharacter;
  126. $encodedLength = $byteCount * $charsPerByte;
  127. // Generate encoded output; each loop produces one encoded character
  128. for ($c = 0; $c < $encodedLength; $c++) {
  129. // Get the bits needed for this encoded character
  130. if ($bitsRead + $bitsPerCharacter > 8) {
  131. // Not enough bits remain in this byte for the current character
  132. // Save the remaining bits before getting the next byte
  133. $oldBitCount = 8 - $bitsRead;
  134. $oldBits = $byte ^ ($byte >> $oldBitCount << $oldBitCount);
  135. $newBitCount = $bitsPerCharacter - $oldBitCount;
  136. if (!$bytes) {
  137. // Last bits; match final character and exit loop
  138. if ($rightPadFinalBits) $oldBits <<= $newBitCount;
  139. $encodedString .= $chars[$oldBits];
  140. if ($padFinalGroup) {
  141. // Array of the lowest common multiples of $bitsPerCharacter and 8, divided by 8
  142. $lcmMap = array(1 => 1, 2 => 1, 3 => 3, 4 => 1, 5 => 5, 6 => 3, 7 => 7, 8 => 1);
  143. $bytesPerGroup = $lcmMap[$bitsPerCharacter];
  144. $pads = $bytesPerGroup * $charsPerByte - ceil((strlen($rawString) % $bytesPerGroup) * $charsPerByte);
  145. $encodedString .= str_repeat($padCharacter, $pads);
  146. }
  147. break;
  148. }
  149. // Get next byte
  150. $byte = array_shift($bytes);
  151. $bitsRead = 0;
  152. } else {
  153. $oldBitCount = 0;
  154. $newBitCount = $bitsPerCharacter;
  155. }
  156. // Read only the needed bits from this byte
  157. $bits = $byte >> 8 - ($bitsRead + ($newBitCount));
  158. $bits ^= $bits >> $newBitCount << $newBitCount;
  159. $bitsRead += $newBitCount;
  160. if ($oldBitCount) {
  161. // Bits come from seperate bytes, add $oldBits to $bits
  162. $bits = ($oldBits << $newBitCount) | $bits;
  163. }
  164. $encodedString .= $chars[$bits];
  165. }
  166. return $encodedString;
  167. }
  168. /**
  169. * Decode a string
  170. *
  171. * @param string $encodedString Data to decode
  172. * @param boolean $strict Returns NULL if $encodedString contains an undecodable character
  173. * @return string
  174. */
  175. public function decode($encodedString, $strict = FALSE)
  176. {
  177. if (!$encodedString || !is_string($encodedString)) {
  178. // Empty string, nothing to decode
  179. return '';
  180. }
  181. $chars = $this->_chars;
  182. $bitsPerCharacter = $this->_bitsPerCharacter;
  183. $radix = $this->_radix;
  184. $rightPadFinalBits = $this->_rightPadFinalBits;
  185. $padFinalGroup = $this->_padFinalGroup;
  186. $padCharacter = $this->_padCharacter;
  187. $caseSensitive = $this->_caseSensitive;
  188. // Get index of encoded characters
  189. if ($this->_charmap) {
  190. $charmap = $this->_charmap;
  191. } else {
  192. $charmap = array();
  193. for ($i = 0; $i < $radix; $i++) {
  194. $charmap[$chars[$i]] = $i;
  195. }
  196. $this->_charmap = $charmap;
  197. }
  198. // The last encoded character is $encodedString[$lastNotatedIndex]
  199. $lastNotatedIndex = strlen($encodedString) - 1;
  200. // Remove trailing padding characters
  201. if ($padFinalGroup) {
  202. while ($encodedString[$lastNotatedIndex] === $padCharacter) {
  203. $encodedString = substr($encodedString, 0, $lastNotatedIndex);
  204. $lastNotatedIndex--;
  205. }
  206. }
  207. $rawString = '';
  208. $byte = 0;
  209. $bitsWritten = 0;
  210. // Convert each encoded character to a series of unencoded bits
  211. for ($c = 0; $c <= $lastNotatedIndex; $c++) {
  212. if (!$caseSensitive && !isset($charmap[$encodedString[$c]])) {
  213. // Encoded character was not found; try other case
  214. if (isset($charmap[$cUpper = strtoupper($encodedString[$c])])) {
  215. $charmap[$encodedString[$c]] = $charmap[$cUpper];
  216. } elseif (isset($charmap[$cLower = strtolower($encodedString[$c])])) {
  217. $charmap[$encodedString[$c]] = $charmap[$cLower];
  218. }
  219. }
  220. if (isset($charmap[$encodedString[$c]])) {
  221. $bitsNeeded = 8 - $bitsWritten;
  222. $unusedBitCount = $bitsPerCharacter - $bitsNeeded;
  223. // Get the new bits ready
  224. if ($bitsNeeded > $bitsPerCharacter) {
  225. // New bits aren't enough to complete a byte; shift them left into position
  226. $newBits = $charmap[$encodedString[$c]] << $bitsNeeded - $bitsPerCharacter;
  227. $bitsWritten += $bitsPerCharacter;
  228. } elseif ($c !== $lastNotatedIndex || $rightPadFinalBits) {
  229. // Zero or more too many bits to complete a byte; shift right
  230. $newBits = $charmap[$encodedString[$c]] >> $unusedBitCount;
  231. $bitsWritten = 8; //$bitsWritten += $bitsNeeded;
  232. } else {
  233. // Final bits don't need to be shifted
  234. $newBits = $charmap[$encodedString[$c]];
  235. $bitsWritten = 8;
  236. }
  237. $byte |= $newBits;
  238. if ($bitsWritten === 8 || $c === $lastNotatedIndex) {
  239. // Byte is ready to be written
  240. $rawString .= pack('C', $byte);
  241. if ($c !== $lastNotatedIndex) {
  242. // Start the next byte
  243. $bitsWritten = $unusedBitCount;
  244. $byte = ($charmap[$encodedString[$c]] ^ ($newBits << $unusedBitCount)) << 8 - $bitsWritten;
  245. }
  246. }
  247. } elseif ($strict) {
  248. // Unable to decode character; abort
  249. return NULL;
  250. }
  251. }
  252. return $rawString;
  253. }
  254. }