first commit

This commit is contained in:
2026-04-20 13:11:14 +02:00
commit e0b63ca5f9
7793 changed files with 1844488 additions and 0 deletions

View File

@@ -0,0 +1,9 @@
<Files *.php>
Order Deny,Allow
Deny from all
</Files>
<Files index.php>
Order Allow,Deny
Allow from all
</Files>

View File

@@ -0,0 +1,25 @@
<?php
/**
* Abstract class to extend in order to use the maximum potentialities of JsonSerialize
*
* @package VendorDuplicator\Amk\JsonSerialize
*/
namespace VendorDuplicator\Amk\JsonSerialize;
/**
* Abstract class to extend in order to use the maximum potentialities of JsonSerialize
*/
abstract class AbstractJsonSerializable extends AbstractJsonSerializeObjData implements \JsonSerializable
{
/**
* Prepared json serialized object
*
* @return mixed
*/
#[\ReturnTypeWillChange]
public final function jsonSerialize()
{
return self::objectToJsonData($this, 0, []);
}
}

View File

@@ -0,0 +1,277 @@
<?php
/**
* AbstractJsonSerializeObjData class
*
* @package VendorDuplicator\Amk\JsonSerialize
*/
namespace VendorDuplicator\Amk\JsonSerialize;
use Exception;
use ReflectionClass;
use ReflectionObject;
/**
* This calsse contains the logic that converts objects into values ready to be encoded in json
*/
abstract class AbstractJsonSerializeObjData
{
const CLASS_KEY_FOR_JSON_SERIALIZE = 'CL_-=_-=';
const JSON_SKIP_MAGIC_METHODS = 0b100000000000000000000000000000;
// 29 bit mask
const JSON_SKIP_CLASS_NAME = 0b1000000000000000000000000000000;
// 30 bit mask
const JSON_SKIP_SANITIZE = 0b10000000000000000000000000000000;
// 31 bit mask
/**
* Convert object to array with private and protected proprieties.
* Private parent class proprieties aren't considered.
*
* @param object $obj obejct to serialize
* @param int $flags flags bitmask
* @param int[]|string[] $objParents objs parents unique objects hash list
*
* @return mixed[]
*/
protected static final function objectToJsonData($obj, $flags = 0, $objParents = [])
{
$reflect = new ReflectionObject($obj);
$result = [];
if (!($flags & self::JSON_SKIP_CLASS_NAME)) {
$result[self::CLASS_KEY_FOR_JSON_SERIALIZE] = $reflect->name;
}
if (!($flags & self::JSON_SKIP_MAGIC_METHODS)) {
if (\method_exists($obj, '__serialize')) {
$data = $obj->__serialize();
if (!\is_array($data)) {
throw new Exception('__serialize method must return an array');
}
return \array_merge($data, $result);
} elseif (\method_exists($obj, '__sleep')) {
$includeProps = $obj->__sleep();
if (!\is_array($includeProps)) {
throw new Exception('__sleep method must return an array');
}
} else {
$includeProps = \true;
}
} else {
$includeProps = \true;
}
// Get all props of current class but not props private of parent class and static props
foreach ($reflect->getProperties() as $prop) {
if ($prop->isStatic()) {
continue;
}
$propName = $prop->getName();
if ($includeProps !== \true && !\in_array($propName, $includeProps)) {
continue;
}
$prop->setAccessible(\true);
$propValue = $prop->getValue($obj);
$result[$propName] = self::valueToJsonData($propValue, $flags, $objParents);
}
return $result;
}
/**
* Recursive parse values, all objects are transformed to array
*
* @param mixed $value valute to parse
* @param int $flags flags bitmask
* @param int[]|string[] $objParents objs parents unique hash or ids after PHP 7.2
*
* @return mixed
*/
protected static final function valueToJsonData($value, $flags = 0, $objParents = [])
{
switch (\gettype($value)) {
case "boolean":
case "integer":
case "double":
case "string":
case "NULL":
return $value;
case "array":
/** @var mixed[] $value */
$result = [];
foreach ($value as $key => $arrayVal) {
$result[$key] = self::valueToJsonData($arrayVal, $flags, $objParents);
}
return $result;
case "object":
/** @var object $value */
$objHash = self::getObjIdentifier($value);
if (\in_array($objHash, $objParents)) {
// prevent infinite recursion loop
return null;
}
$objParents[] = $objHash;
return self::objectToJsonData($value, $flags, $objParents);
case "resource":
case "resource (closed)":
case "unknown type":
default:
return null;
}
}
/**
* Return value from json decoded data
*
* @param mixed $value json decoded data
* @param int $flags flags bitmask
* @param ?JsonUnserializeMap $map unserialize map
*
* @return mixed
*/
protected static final function jsonDataToValue($value, $flags = 0, $map = null)
{
if ($map !== null) {
$current = $map->getCurrent();
if ($map->isMapped()) {
$mappedVal = $map->getMappedValue($value, $isReference);
if ($isReference) {
return $mappedVal;
}
switch (\gettype($mappedVal)) {
case 'array':
/** @var mixed[] $mappedVal */
$result = [];
foreach ($mappedVal as $key => $arrayVal) {
$map->setCurrent($key, $current);
$result[$key] = self::jsonDataToValue($arrayVal, $flags, $map);
}
return $result;
case 'object':
/** @var object $mappedVal */
if (!\is_array($value)) {
$value = [];
}
return self::fillObjFromValue($value, $mappedVal, $flags, $map);
default:
return $mappedVal;
}
}
}
switch (\gettype($value)) {
case 'array':
/** @var mixed[] $value */
if (($newClassName = self::getClassFromArray($value)) === \false) {
$result = [];
foreach ($value as $key => $arrayVal) {
if ($map !== null) {
$map->setCurrent($key, $current);
}
$result[$key] = self::jsonDataToValue($arrayVal, $flags, $map);
}
} else {
$result = self::fillObjFromValue($value, self::getObjFromClass($newClassName), $flags, $map);
}
return $result;
case 'boolean':
case 'integer':
case 'double':
case 'string':
case "NULL":
return $value;
default:
return null;
}
}
/**
* Get object from class name, if class don't exists return StdClass.
* the object is intialized without call the constructor.
*
* @param string $class class name
*
* @return object
*/
public static final function getObjFromClass($class)
{
if (\class_exists($class)) {
$classReflect = new ReflectionClass($class);
return $classReflect->newInstanceWithoutConstructor();
} else {
return new \StdClass();
}
}
/**
* Fill passed object from array values
*
* @param mixed[] $value value from json data
* @param object $obj object to fill with json data
* @param int $flags flags bitmask
* @param ?JsonUnserializeMap $map unserialize map
*
* @return object
*/
protected static final function fillObjFromValue($value, $obj, $flags = 0, $map = null)
{
if ($map !== null) {
$current = $map->getCurrent();
$map->addReferenceObjOfCurrent($obj);
}
if ($obj instanceof \stdClass) {
foreach ($value as $arrayProp => $arrayValue) {
if ($arrayProp == self::CLASS_KEY_FOR_JSON_SERIALIZE) {
continue;
}
if ($map !== null) {
$map->setCurrent($arrayProp, $current);
}
$obj->{$arrayProp} = self::jsonDataToValue($arrayValue, $flags, $map);
}
} else {
$skipMagicMethods = $flags & self::JSON_SKIP_MAGIC_METHODS;
if (!$skipMagicMethods && \method_exists($obj, '__unserialize')) {
$obj->__unserialize($value);
} else {
$reflect = new ReflectionObject($obj);
foreach ($reflect->getProperties() as $prop) {
$prop->setAccessible(\true);
$propName = $prop->getName();
if ($map !== null) {
$map->setCurrent($propName, $current);
if (!\array_key_exists($propName, $value) && $map->isMapped()) {
$value[$propName] = null;
}
}
if (!\array_key_exists($propName, $value) || $prop->isStatic()) {
continue;
}
$prop->setValue($obj, self::jsonDataToValue($value[$propName], $flags, $map));
}
if (!$skipMagicMethods && \method_exists($obj, '__wakeup')) {
$obj->__wakeup();
}
}
}
return $obj;
}
/**
* Return class name from array values
*
* @param mixed[] $array array data
*
* @return false|string false if prop not found
*/
protected static final function getClassFromArray($array)
{
/** @var false|string $result */
$result = isset($array[self::CLASS_KEY_FOR_JSON_SERIALIZE]) ? $array[self::CLASS_KEY_FOR_JSON_SERIALIZE] : \false;
return $result;
}
/**
* Get object unique identifier
*
* @param object $obj input object
*
* @return int|string
*/
protected static final function getObjIdentifier($obj)
{
static $useObjId = null;
if (\is_null($useObjId)) {
$useObjId = \function_exists('spl_object_id');
}
return $useObjId ? \spl_object_id($obj) : \spl_object_hash($obj);
}
}

View File

@@ -0,0 +1,75 @@
<?php
/**
* JsonSerialize class
*
* @package VendorDuplicator\Amk\JsonSerialize
*/
namespace VendorDuplicator\Amk\JsonSerialize;
/**
* Autoloader class
*/
final class Autoloader
{
const ROOT_NAMESPACE = __NAMESPACE__ . '\\';
/**
* Register autoloader function
*
* @return void
*/
public static function register()
{
\spl_autoload_register(array(__CLASS__, 'load'));
// @phpstan-ignore-line
}
/**
* Load class
*
* @param string $className class name
*
* @return bool return true if class is loaded
*/
public static function load($className)
{
if (\strpos($className, self::ROOT_NAMESPACE) !== 0) {
return \false;
}
foreach (self::getNamespacesMapping() as $namespace => $mappedPath) {
if (\strpos($className, $namespace) !== 0) {
continue;
}
$filepath = self::getFilenameFromClass($className, $namespace, $mappedPath);
if (\file_exists($filepath)) {
include $filepath;
return \true;
}
}
return \false;
}
/**
* Return PHP file full class from class name
*
* @param string $class Name of class
* @param string $namespace Base namespace
* @param string $mappedPath Base path
*
* @return string
*/
protected static function getFilenameFromClass($class, $namespace, $mappedPath)
{
$subPath = \str_replace('\\', '/', \substr($class, \strlen($namespace))) . '.php';
$subPath = \ltrim($subPath, '/');
return \rtrim($mappedPath, '\\/') . '/' . $subPath;
}
/**
* Return namespace mapping
*
* @return string[]
*/
protected static function getNamespacesMapping()
{
// the order is important, it is necessary to insert the longest namespaces first
return [self::ROOT_NAMESPACE => __DIR__ . '/'];
}
}

View File

@@ -0,0 +1,236 @@
<?php
/**
* JsonSerialize class
*
* @package VendorDuplicator\Amk\JsonSerialize
*/
namespace VendorDuplicator\Amk\JsonSerialize;
use Exception;
use stdClass;
/**
* This class serializes and deserializes a variable in json keeping the class type and saving also private objects
*/
class JsonSerialize extends AbstractJsonSerializeObjData
{
/**
* Return json string
*
* @param mixed $value value to serialize
* @param int $flags json_encode flags
* @param int<1, max> $depth json_encode depth
*
* @link https://www.php.net/manual/en/function.json-encode.php
*
* @return string|false Returns a JSON encoded string on success or false on failure.
*/
public static function serialize($value, $flags = 0, $depth = 512)
{
$jsonData = self::valueToJsonData($value, $flags);
$json = \version_compare(\PHP_VERSION, '5.5', '>=') ? \json_encode($jsonData, $flags, $depth) : \json_encode($jsonData, $flags);
// If json_encode() was successful, no need to do more sanity checking.
if (\false !== $json || $flags & self::JSON_SKIP_SANITIZE) {
return $json;
}
try {
$jsonData = self::sanitizeData($jsonData, $depth);
} catch (Exception $e) {
return \false;
}
return \version_compare(\PHP_VERSION, '5.5', '>=') ? \json_encode($jsonData, $flags, $depth) : \json_encode($jsonData, $flags);
}
/**
* Returns value ready to be serialized, for objects returns a value key array, other data types are unchanged
*
* @param mixed $value value to serialize
* @param integer $flags JsonSerialize flags
*
* @return mixed Returns values ready to be serialized
*/
public static function serializeToData($value, $flags = 0)
{
return self::valueToJsonData($value, $flags);
}
/**
* Unserialize from json
*
* @param string $json json string
* @param int<1, max> $depth json_decode depth
* @param int $flags json_decode flags
*
* @link https://www.php.net/manual/en/function.json-decode.php
*
* @return mixed
*/
public static function unserialize($json, $depth = 512, $flags = 0)
{
$publicArray = \json_decode($json, \true, $depth, $flags);
return self::jsonDataToValue($publicArray, $flags);
}
/**
* Unserialize from json
*
* @param string $json json string
* @param JsonUnserializeMap $map values mapping
* @param int<1, max> $depth json_decode depth
* @param int $flags json_decode flags
*
* @link https://www.php.net/manual/en/function.json-decode.php
*
* @return mixed
*/
public static function unserializeWithMap($json, JsonUnserializeMap $map, $depth = 512, $flags = 0)
{
$publicArray = \json_decode($json, \true, $depth, $flags);
$map->setCurrent('');
return self::jsonDataToValue($publicArray, $flags, $map);
}
/**
* Unserialize json on passed object
*
* @param string $json json string
* @param object|string $obj object or class name to fill
* @param int<1, max> $depth json_decode depth
* @param int $flags json_decode flags
*
* @link https://www.php.net/manual/en/function.json-decode.php
*
* @return object
*/
public static function unserializeToObj($json, $obj, $depth = 512, $flags = 0)
{
if (\is_object($obj)) {
} elseif (\is_string($obj) && \class_exists($obj)) {
$obj = self::getObjFromClass($obj);
} else {
throw new Exception('invalid obj param');
}
$value = \json_decode($json, \true, $depth, $flags);
if (!\is_array($value)) {
throw new Exception('json value isn\'t an array');
}
return self::fillObjFromValue($value, $obj, $flags);
}
/**
* Perform sanity checks on data that shall be encoded to JSON.
*
* @param mixed $data Variable (usually an array or object) to encode as JSON.
* @param int $depth Maximum depth to walk through $data. Must be greater than 0.
*
* @return mixed The sanitized data that shall be encoded to JSON.
*
* @throws Exception If depth limit is reached.
*
* From Worpdress function _wp_json_sanity_check
* @see https://github.com/WordPress/WordPress/blob/master/wp-includes/functions.php
*/
public static function sanitizeData($data, $depth)
{
if ($depth < 0) {
throw new Exception('Reached depth limit');
}
if (\is_array($data)) {
$output = array();
foreach ($data as $id => $el) {
// Don't forget to sanitize the ID!
if (\is_string($id)) {
$clean_id = self::convertString($id);
} else {
$clean_id = $id;
}
// Check the element type, so that we're only recursing if we really have to.
if (\is_array($el) || \is_object($el)) {
$output[$clean_id] = self::sanitizeData($el, $depth - 1);
} elseif (\is_string($el)) {
$output[$clean_id] = self::convertString($el);
} else {
$output[$clean_id] = $el;
}
}
} elseif (\is_object($data)) {
$output = new stdClass();
foreach ((array) $data as $id => $el) {
if (\is_string($id)) {
$clean_id = self::convertString($id);
} else {
$clean_id = $id;
}
if (\is_array($el) || \is_object($el)) {
$output->{$clean_id} = self::sanitizeData($el, $depth - 1);
} elseif (\is_string($el)) {
$output->{$clean_id} = self::convertString($el);
} else {
$output->{$clean_id} = $el;
}
}
} elseif (\is_string($data)) {
return self::convertString($data);
} else {
return $data;
}
return $output;
}
/**
* Convert a string to UTF-8, so that it can be safely encoded to JSON.
*
* @param string $string The string which is to be converted.
*
* @return string The checked string.
*
* From Worpdress function _wp_json_convert_string
* @see https://github.com/WordPress/WordPress/blob/master/wp-includes/functions.php
*/
protected static function convertString($string)
{
static $use_mb = null;
if (\is_null($use_mb)) {
$use_mb = \function_exists('mb_convert_encoding');
}
if ($use_mb) {
$encoding = \mb_detect_encoding($string, null, \true);
if ($encoding) {
return \mb_convert_encoding($string, 'UTF-8', $encoding);
} else {
return \mb_convert_encoding($string, 'UTF-8', 'UTF-8');
}
} else {
return self::checkInvalidUtf8($string, \true);
}
}
/**
* Checks for invalid UTF8 in a string.
*
* @param string $string The text which is to be checked.
* @param bool $strip Optional. Whether to attempt to strip out invalid UTF8. Default false.
*
* @return string The checked text.
*
* From Worpdress function wp_check_invalid_utf8
* @see https://github.com/WordPress/WordPress/blob/master/wp-includes/formatting.php
*/
protected static function checkInvalidUtf8($string, $strip = \false)
{
$string = (string) $string;
if (0 === \strlen($string)) {
return '';
}
// Check for support for utf8 in the installed PCRE library once and store the result in a static.
static $utf8_pcre = null;
if (!isset($utf8_pcre)) {
$utf8_pcre = @\preg_match('/^./u', 'a');
}
// We can't demand utf8 in the PCRE installation, so just return the string in those cases.
if (!$utf8_pcre) {
return $string;
}
if (1 === @\preg_match('/^./us', $string)) {
return $string;
}
// Attempt to strip the bad chars if requested (not recommended).
if ($strip && \function_exists('iconv')) {
return (string) \iconv('utf-8', 'utf-8', $string);
}
return '';
}
}

View File

@@ -0,0 +1,250 @@
<?php
/**
* JsonUnserializeMapping class
*
* @package VendorDuplicator\Amk\JsonSerialize
*/
namespace VendorDuplicator\Amk\JsonSerialize;
use Exception;
/**
* Unserialize mapping
*
* Accepted types
*
* bool
* boolean
* float
* int
* integer
* string
* array
* object
*
* Special types
* cl:ClassName Istance of class
* rf:PropReference Referenct of other prop
*
* If type start with ? is nullable
*/
class JsonUnserializeMap
{
/** @var MapItem */
private $map = null;
/** @var string */
private $currentProp = '';
/** @var bool */
private $isCurrentMapped = \false;
/** @var ?string */
private $currentType = null;
/** @var object[] */
private $objReferences = [];
/**
* Class constructor
*
* @param array<string, string> $map values map
*/
public function __construct($map = [])
{
if (!\is_array($map)) {
throw new Exception('map must be an array');
}
$this->map = new MapItem();
foreach ($map as $prop => $type) {
$this->addProp($prop, $type);
}
}
/**
* Reset current property
*
* @return void
*/
public function resetCurrent()
{
$this->currentProp = '';
$this->isCurrentMapped = \false;
$this->currentType = null;
$this->objReferences = [];
}
/**
* Add reference object
*
* @param object $obj object
*
* @return void
*/
public function addReferenceObjOfCurrent($obj)
{
$this->objReferences[$this->currentProp] = $obj;
}
/**
* Return current prop
*
* @return string
*/
public function getCurrent()
{
return $this->currentProp;
}
/**
* Return true if current propr is mapped
*
* @return bool
*/
public function isMapped()
{
return $this->isCurrentMapped;
}
/**
* Set current property
*
* @param string $prop property name
* @param string $parent property parent
*
* @return bool return true if current prop is mapped
*/
public function setCurrent($prop, $parent = '')
{
$this->currentProp = (\strlen($parent) ? $parent . '/' : '') . $prop;
$this->isCurrentMapped = \false;
$this->currentType = null;
if (\strlen($this->currentProp) == 0) {
if ($this->map->type !== null) {
$this->isCurrentMapped = \true;
$this->currentType = $this->map->type;
}
} else {
$pArray = \explode('/', $this->currentProp);
$cLevel = $this->map;
for ($i = 0; $i < \count($pArray); $i++) {
$cProp = $pArray[$i];
if (isset($cLevel->childs[$cProp])) {
$cLevel = $cLevel->childs[$cProp];
continue;
}
if (isset($cLevel->childs['*'])) {
// wildcard
$cLevel = $cLevel->childs['*'];
continue;
}
break;
}
if ($i == \count($pArray) && $cLevel->type !== null) {
$this->isCurrentMapped = \true;
$this->currentType = $cLevel->type;
}
}
return $this->isCurrentMapped;
}
/**
* Return mapped value
*
* @param mixed $value input value
* @param bool $isReference Set to true if is reference object
*
* @return mixed
*/
public function getMappedValue($value, &$isReference = \false)
{
if (!$this->isCurrentMapped) {
return $value;
}
$type = (string) $this->currentType;
if ($type[0] === '?') {
if ($value === null) {
return null;
}
$type = \substr($type, 1);
}
switch (\substr($type, 0, 3)) {
case 'cl:':
$newClassName = (string) \substr($type, 3);
// in PHP 5.6- return false if empty
return JsonSerialize::getObjFromClass($newClassName);
case 'rf:':
$reference = (string) \substr($type, 3);
// in PHP 5.6- return false if empty
$isReference = \true;
if (isset($this->objReferences[$reference])) {
return $this->objReferences[$reference];
} else {
return null;
}
}
switch ($type) {
case 'bool':
case 'boolean':
return \is_scalar($value) ? (bool) $value : \false;
case 'float':
return \is_scalar($value) ? (float) $value : 0.0;
case 'int':
case 'integer':
return \is_scalar($value) ? (int) $value : 0;
case 'string':
return \is_scalar($value) ? (string) $value : '';
case 'array':
return (array) $value;
case 'object':
return (object) $value;
case 'null':
return null;
default:
break;
}
/** @todo create flag not strict to return false */
throw new Exception('Invalid mapping');
}
/**
* Add map property
*
* @param string $prop property itendifier, if exists overite it
* @param string $type value type
*
* @return void
*/
public function addProp($prop, $type)
{
$cLevel = $this->map;
if (\strlen($prop) > 0) {
$pArray = \explode('/', $prop);
foreach ($pArray as $cProp) {
if (!isset($cLevel->childs[$cProp])) {
$cLevel->childs[$cProp] = new MapItem();
}
$cLevel = $cLevel->childs[$cProp];
}
}
$cLevel->type = $type;
}
/**
* Remove map property
*
* @param string $prop property itendifier
*
* @return void
*/
public function removeProp($prop)
{
$cLevel = $this->map;
if (\strlen($prop) > 0) {
$pArray = \explode('/', $prop);
foreach ($pArray as $cProp) {
if (!isset($cLevel->childs[$cProp])) {
return;
}
$cLevel = $cLevel->childs[$cProp];
}
}
$cLevel->type = null;
}
/**
* Remove all map properties
*
* @return void
*/
public function resetMap()
{
$this->map = new MapItem();
}
}

View File

@@ -0,0 +1,19 @@
<?php
/**
* Map item class
*
* @package VendorDuplicator\Amk\JsonSerialize
*/
namespace VendorDuplicator\Amk\JsonSerialize;
/**
* Map item element
*/
class MapItem
{
/** @var ?string */
public $type = null;
/** @var self[] */
public $childs = [];
}

View File

@@ -0,0 +1,227 @@
<?php
namespace VendorDuplicator\Cron;
/**
* Abstract CRON expression field
* TG changes: replaced [] with array() everywhere
*/
abstract class AbstractField implements FieldInterface
{
/**
* Full range of values that are allowed for this field type
* @var array
*/
protected $fullRange = array();
/**
* Literal values we need to convert to integers
* @var array
*/
protected $literals = array();
/**
* Start value of the full range
* @var integer
*/
protected $rangeStart;
/**
* End value of the full range
* @var integer
*/
protected $rangeEnd;
public function __construct()
{
$this->fullRange = \range($this->rangeStart, $this->rangeEnd);
}
/**
* Check to see if a field is satisfied by a value
*
* @param string $dateValue Date value to check
* @param string $value Value to test
*
* @return bool
*/
public function isSatisfied($dateValue, $value)
{
if ($this->isIncrementsOfRanges($value)) {
return $this->isInIncrementsOfRanges($dateValue, $value);
} elseif ($this->isRange($value)) {
return $this->isInRange($dateValue, $value);
}
return $value == '*' || $dateValue == $value;
}
/**
* Check if a value is a range
*
* @param string $value Value to test
*
* @return bool
*/
public function isRange($value)
{
return \strpos($value, '-') !== \false;
}
/**
* Check if a value is an increments of ranges
*
* @param string $value Value to test
*
* @return bool
*/
public function isIncrementsOfRanges($value)
{
return \strpos($value, '/') !== \false;
}
/**
* Test if a value is within a range
*
* @param string $dateValue Set date value
* @param string $value Value to test
*
* @return bool
*/
public function isInRange($dateValue, $value)
{
$parts = \array_map('trim', \explode('-', $value, 2));
return $dateValue >= $parts[0] && $dateValue <= $parts[1];
}
/**
* Test if a value is within an increments of ranges (offset[-to]/step size)
*
* @param string $dateValue Set date value
* @param string $value Value to test
*
* @return bool
*/
public function isInIncrementsOfRanges($dateValue, $value)
{
$chunks = \array_map('trim', \explode('/', $value, 2));
$range = $chunks[0];
$step = isset($chunks[1]) ? $chunks[1] : 0;
// No step or 0 steps aren't cool
if (\is_null($step) || '0' === $step || 0 === $step) {
return \false;
}
// Expand the * to a full range
if ('*' == $range) {
$range = $this->rangeStart . '-' . $this->rangeEnd;
}
// Generate the requested small range
$rangeChunks = \explode('-', $range, 2);
$rangeStart = $rangeChunks[0];
$rangeEnd = isset($rangeChunks[1]) ? $rangeChunks[1] : $rangeStart;
if ($rangeStart < $this->rangeStart || $rangeStart > $this->rangeEnd || $rangeStart > $rangeEnd) {
throw new \OutOfRangeException('Invalid range start requested');
}
if ($rangeEnd < $this->rangeStart || $rangeEnd > $this->rangeEnd || $rangeEnd < $rangeStart) {
throw new \OutOfRangeException('Invalid range end requested');
}
// Steps larger than the range need to wrap around and be handled
// slightly differently than smaller steps
// UPDATE - This is actually false. The C implementation will allow a
// larger step as valid syntax, it never wraps around. It will stop
// once it hits the end. Unfortunately this means in future versions
// we will not wrap around. However, because the logic exists today
// per the above documentation, fixing the bug from #89
if ($step > $this->rangeEnd) {
$thisRange = array($this->fullRange[$step % \count($this->fullRange)]);
} else {
if ($step > $rangeEnd - $rangeStart) {
$thisRange[$rangeStart] = (int) $rangeStart;
} else {
$thisRange = \range($rangeStart, $rangeEnd, (int) $step);
}
}
return \in_array($dateValue, $thisRange);
}
/**
* Returns a range of values for the given cron expression
*
* @param string $expression The expression to evaluate
* @param int $max Maximum offset for range
*
* @return array
*/
public function getRangeForExpression($expression, $max)
{
$values = array();
if ($this->isRange($expression) || $this->isIncrementsOfRanges($expression)) {
if (!$this->isIncrementsOfRanges($expression)) {
list($offset, $to) = \explode('-', $expression);
$stepSize = 1;
} else {
$range = \array_map('trim', \explode('/', $expression, 2));
$stepSize = isset($range[1]) ? $range[1] : 0;
$range = $range[0];
$range = \explode('-', $range, 2);
$offset = $range[0];
$to = isset($range[1]) ? $range[1] : $max;
}
$offset = $offset == '*' ? 0 : $offset;
for ($i = $offset; $i <= $to; $i += $stepSize) {
$values[] = $i;
}
\sort($values);
} else {
$values = array($expression);
}
return $values;
}
protected function convertLiterals($value)
{
if (\count($this->literals)) {
$key = \array_search($value, $this->literals);
if ($key !== \false) {
return $key;
}
}
return $value;
}
/**
* Checks to see if a value is valid for the field
*
* @param string $value
* @return bool
*/
public function validate($value)
{
$value = $this->convertLiterals($value);
// All fields allow * as a valid value
if ('*' === $value) {
return \true;
}
// You cannot have a range and a list at the same time
if (\strpos($value, ',') !== \false && \strpos($value, '-') !== \false) {
return \false;
}
if (\strpos($value, '/') !== \false) {
list($range, $step) = \explode('/', $value);
return $this->validate($range) && \filter_var($step, \FILTER_VALIDATE_INT);
}
if (\strpos($value, '-') !== \false) {
if (\substr_count($value, '-') > 1) {
return \false;
}
$chunks = \explode('-', $value);
$chunks[0] = $this->convertLiterals($chunks[0]);
$chunks[1] = $this->convertLiterals($chunks[1]);
if ('*' == $chunks[0] || '*' == $chunks[1]) {
return \false;
}
return $this->validate($chunks[0]) && $this->validate($chunks[1]);
}
// Validate each chunk of a list individually
if (\strpos($value, ',') !== \false) {
foreach (\explode(',', $value) as $listItem) {
if (!$this->validate($listItem)) {
return \false;
}
}
return \true;
}
// We should have a numeric by now, so coerce this into an integer
if (\filter_var($value, \FILTER_VALIDATE_INT) !== \false) {
$value = (int) $value;
}
return \in_array($value, $this->fullRange, \true);
}
}

View File

@@ -0,0 +1,345 @@
<?php
namespace VendorDuplicator\Cron;
use DateTime;
use DateTimeZone;
use Exception;
use InvalidArgumentException;
use RuntimeException;
/**
* CRON expression parser that can determine whether or not a CRON expression is
* due to run, the next run date and previous run date of a CRON expression.
* The determinations made by this class are accurate if checked run once per
* minute (seconds are dropped from date time comparisons).
*
* Schedule parts must map to:
* minute [0-59], hour [0-23], day of month, month [1-12|JAN-DEC], day of week
* [1-7|MON-SUN], and an optional year.
*
* @link http://en.wikipedia.org/wiki/Cron
*
* TG changes: replaced [] with array() and removed usage of DateTimeImmutable
*/
class CronExpression
{
const MINUTE = 0;
const HOUR = 1;
const DAY = 2;
const MONTH = 3;
const WEEKDAY = 4;
const YEAR = 5;
/**
* @var array CRON expression parts
*/
private $cronParts;
/**
* @var FieldFactory CRON field factory
*/
private $fieldFactory;
/**
* @var int Max iteration count when searching for next run date
*/
private $maxIterationCount = 1000;
/**
* @var array Order in which to test of cron parts
*/
private static $order = array(self::YEAR, self::MONTH, self::DAY, self::WEEKDAY, self::HOUR, self::MINUTE);
/**
* Factory method to create a new CronExpression.
*
* @param string $expression The CRON expression to create. There are
* several special predefined values which can be used to substitute the
* CRON expression:
*
* `@yearly`, `@annually` - Run once a year, midnight, Jan. 1 - 0 0 1 1 *
* `@monthly` - Run once a month, midnight, first of month - 0 0 1 * *
* `@weekly` - Run once a week, midnight on Sun - 0 0 * * 0
* `@daily` - Run once a day, midnight - 0 0 * * *
* `@hourly` - Run once an hour, first minute - 0 * * * *
* @param FieldFactory $fieldFactory Field factory to use
*
* @return CronExpression
*/
public static function factory($expression, FieldFactory $fieldFactory = null)
{
$mappings = array('@yearly' => '0 0 1 1 *', '@annually' => '0 0 1 1 *', '@monthly' => '0 0 1 * *', '@weekly' => '0 0 * * 0', '@daily' => '0 0 * * *', '@hourly' => '0 * * * *');
if (isset($mappings[$expression])) {
$expression = $mappings[$expression];
}
return new static($expression, $fieldFactory ?: new FieldFactory());
}
/**
* Validate a CronExpression.
*
* @param string $expression The CRON expression to validate.
*
* @return bool True if a valid CRON expression was passed. False if not.
* @see \Cron\CronExpression::factory
*/
public static function isValidExpression($expression)
{
try {
self::factory($expression);
} catch (InvalidArgumentException $e) {
return \false;
}
return \true;
}
/**
* Parse a CRON expression
*
* @param string $expression CRON expression (e.g. '8 * * * *')
* @param FieldFactory $fieldFactory Factory to create cron fields
*/
public function __construct($expression, FieldFactory $fieldFactory)
{
$this->fieldFactory = $fieldFactory;
$this->setExpression($expression);
}
/**
* Set or change the CRON expression
*
* @param string $value CRON expression (e.g. 8 * * * *)
*
* @return CronExpression
* @throws \InvalidArgumentException if not a valid CRON expression
*/
public function setExpression($value)
{
$this->cronParts = \preg_split('/\\s/', $value, -1, \PREG_SPLIT_NO_EMPTY);
if (\count($this->cronParts) < 5) {
throw new InvalidArgumentException($value . ' is not a valid CRON expression');
}
foreach ($this->cronParts as $position => $part) {
$this->setPart($position, $part);
}
return $this;
}
/**
* Set part of the CRON expression
*
* @param int $position The position of the CRON expression to set
* @param string $value The value to set
*
* @return CronExpression
* @throws \InvalidArgumentException if the value is not valid for the part
*/
public function setPart($position, $value)
{
if (!$this->fieldFactory->getField($position)->validate($value)) {
throw new InvalidArgumentException('Invalid CRON field value ' . $value . ' at position ' . $position);
}
$this->cronParts[$position] = $value;
return $this;
}
/**
* Set max iteration count for searching next run dates
*
* @param int $maxIterationCount Max iteration count when searching for next run date
*
* @return CronExpression
*/
public function setMaxIterationCount($maxIterationCount)
{
$this->maxIterationCount = $maxIterationCount;
return $this;
}
/**
* Get a next run date relative to the current date or a specific date
*
* @param string|\DateTime $currentTime Relative calculation date
* @param int $nth Number of matches to skip before returning a
* matching next run date. 0, the default, will return the current
* date and time if the next run date falls on the current date and
* time. Setting this value to 1 will skip the first match and go to
* the second match. Setting this value to 2 will skip the first 2
* matches and so on.
* @param bool $allowCurrentDate Set to TRUE to return the current date if
* it matches the cron expression.
* @param null|string $timeZone Timezone to use instead of the system default
*
* @return \DateTime
* @throws \RuntimeException on too many iterations
*/
public function getNextRunDate($currentTime = 'now', $nth = 0, $allowCurrentDate = \false, $timeZone = null)
{
return $this->getRunDate($currentTime, $nth, \false, $allowCurrentDate, $timeZone);
}
/**
* Get a previous run date relative to the current date or a specific date
*
* @param string|\DateTime $currentTime Relative calculation date
* @param int $nth Number of matches to skip before returning
* @param bool $allowCurrentDate Set to TRUE to return the
* current date if it matches the cron expression
* @param null|string $timeZone Timezone to use instead of the system default
*
* @return \DateTime
* @throws \RuntimeException on too many iterations
* @see \Cron\CronExpression::getNextRunDate
*/
public function getPreviousRunDate($currentTime = 'now', $nth = 0, $allowCurrentDate = \false, $timeZone = null)
{
return $this->getRunDate($currentTime, $nth, \true, $allowCurrentDate, $timeZone);
}
/**
* Get multiple run dates starting at the current date or a specific date
*
* @param int $total Set the total number of dates to calculate
* @param string|\DateTime $currentTime Relative calculation date
* @param bool $invert Set to TRUE to retrieve previous dates
* @param bool $allowCurrentDate Set to TRUE to return the
* current date if it matches the cron expression
* @param null|string $timeZone Timezone to use instead of the system default
*
* @return array Returns an array of run dates
*/
public function getMultipleRunDates($total, $currentTime = 'now', $invert = \false, $allowCurrentDate = \false, $timeZone = null)
{
$matches = array();
for ($i = 0; $i < \max(0, $total); $i++) {
try {
$matches[] = $this->getRunDate($currentTime, $i, $invert, $allowCurrentDate, $timeZone);
} catch (RuntimeException $e) {
break;
}
}
return $matches;
}
/**
* Get all or part of the CRON expression
*
* @param string $part Specify the part to retrieve or NULL to get the full
* cron schedule string.
*
* @return string|null Returns the CRON expression, a part of the
* CRON expression, or NULL if the part was specified but not found
*/
public function getExpression($part = null)
{
if (null === $part) {
return \implode(' ', $this->cronParts);
} elseif (\array_key_exists($part, $this->cronParts)) {
return $this->cronParts[$part];
}
return null;
}
/**
* Helper method to output the full expression.
*
* @return string Full CRON expression
*/
public function __toString()
{
return $this->getExpression();
}
/**
* Determine if the cron is due to run based on the current date or a
* specific date. This method assumes that the current number of
* seconds are irrelevant, and should be called once per minute.
*
* @param string|\DateTime $currentTime Relative calculation date
* @param null|string $timeZone Timezone to use instead of the system default
*
* @return bool Returns TRUE if the cron is due to run or FALSE if not
*/
public function isDue($currentTime = 'now', $timeZone = null)
{
if (\is_null($timeZone)) {
$timeZone = \date_default_timezone_get();
}
if ('now' === $currentTime) {
$currentDate = \date('Y-m-d H:i');
$currentTime = \strtotime($currentDate);
} elseif ($currentTime instanceof DateTime) {
$currentDate = clone $currentTime;
// Ensure time in 'current' timezone is used
$currentDate->setTimezone(new DateTimeZone($timeZone));
$currentDate = $currentDate->format('Y-m-d H:i');
$currentTime = \strtotime($currentDate);
} else {
$currentTime = new DateTime($currentTime);
$currentTime->setTime($currentTime->format('H'), $currentTime->format('i'), 0);
$currentDate = $currentTime->format('Y-m-d H:i');
$currentTime = $currentTime->getTimeStamp();
}
try {
return $this->getNextRunDate($currentDate, 0, \true)->getTimestamp() == $currentTime;
} catch (Exception $e) {
return \false;
}
}
/**
* Get the next or previous run date of the expression relative to a date
*
* @param string|\DateTime $currentTime Relative calculation date
* @param int $nth Number of matches to skip before returning
* @param bool $invert Set to TRUE to go backwards in time
* @param bool $allowCurrentDate Set to TRUE to return the
* current date if it matches the cron expression
* @param string|null $timeZone Timezone to use instead of the system default
*
* @return \DateTime
* @throws \RuntimeException on too many iterations
*/
protected function getRunDate($currentTime = null, $nth = 0, $invert = \false, $allowCurrentDate = \false, $timeZone = null)
{
if (\is_null($timeZone)) {
$timeZone = \date_default_timezone_get();
}
if ($currentTime instanceof DateTime) {
$currentDate = clone $currentTime;
} else {
$currentDate = new DateTime($currentTime ?: 'now');
$currentDate->setTimezone(new DateTimeZone($timeZone));
}
$currentDate->setTime($currentDate->format('H'), $currentDate->format('i'), 0);
$nextRun = clone $currentDate;
$nth = (int) $nth;
// We don't have to satisfy * or null fields
$parts = array();
$fields = array();
foreach (self::$order as $position) {
$part = $this->getExpression($position);
if (null === $part || '*' === $part) {
continue;
}
$parts[$position] = $part;
$fields[$position] = $this->fieldFactory->getField($position);
}
// Set a hard limit to bail on an impossible date
for ($i = 0; $i < $this->maxIterationCount; $i++) {
foreach ($parts as $position => $part) {
$satisfied = \false;
// Get the field object used to validate this part
$field = $fields[$position];
// Check if this is singular or a list
if (\strpos($part, ',') === \false) {
$satisfied = $field->isSatisfiedBy($nextRun, $part);
} else {
foreach (\array_map('trim', \explode(',', $part)) as $listPart) {
if ($field->isSatisfiedBy($nextRun, $listPart)) {
$satisfied = \true;
break;
}
}
}
// If the field is not satisfied, then start over
if (!$satisfied) {
$field->increment($nextRun, $invert, $part);
continue 2;
}
}
// Skip this match if needed
if (!$allowCurrentDate && $nextRun == $currentDate || --$nth > -1) {
$this->fieldFactory->getField(0)->increment($nextRun, $invert, isset($parts[0]) ? $parts[0] : null);
continue;
}
return $nextRun;
}
// @codeCoverageIgnoreStart
throw new RuntimeException('Impossible CRON expression');
// @codeCoverageIgnoreEnd
}
}

View File

@@ -0,0 +1,108 @@
<?php
namespace VendorDuplicator\Cron;
use DateTime;
/**
* Day of month field. Allows: * , / - ? L W
*
* 'L' stands for "last" and specifies the last day of the month.
*
* The 'W' character is used to specify the weekday (Monday-Friday) nearest the
* given day. As an example, if you were to specify "15W" as the value for the
* day-of-month field, the meaning is: "the nearest weekday to the 15th of the
* month". So if the 15th is a Saturday, the trigger will fire on Friday the
* 14th. If the 15th is a Sunday, the trigger will fire on Monday the 16th. If
* the 15th is a Tuesday, then it will fire on Tuesday the 15th. However if you
* specify "1W" as the value for day-of-month, and the 1st is a Saturday, the
* trigger will fire on Monday the 3rd, as it will not 'jump' over the boundary
* of a month's days. The 'W' character can only be specified when the
* day-of-month is a single day, not a range or list of days.
*
* @author Michael Dowling <mtdowling@gmail.com>
*/
class DayOfMonthField extends AbstractField
{
protected $rangeStart = 1;
protected $rangeEnd = 31;
/**
* Get the nearest day of the week for a given day in a month
*
* @param int $currentYear Current year
* @param int $currentMonth Current month
* @param int $targetDay Target day of the month
*
* @return \DateTime Returns the nearest date
*/
private static function getNearestWeekday($currentYear, $currentMonth, $targetDay)
{
$tday = \str_pad($targetDay, 2, '0', \STR_PAD_LEFT);
$target = DateTime::createFromFormat('Y-m-d', "{$currentYear}-{$currentMonth}-{$tday}");
$currentWeekday = (int) $target->format('N');
if ($currentWeekday < 6) {
return $target;
}
$lastDayOfMonth = $target->format('t');
foreach (array(-1, 1, -2, 2) as $i) {
$adjusted = $targetDay + $i;
if ($adjusted > 0 && $adjusted <= $lastDayOfMonth) {
$target->setDate($currentYear, $currentMonth, $adjusted);
if ($target->format('N') < 6 && $target->format('m') == $currentMonth) {
return $target;
}
}
}
}
public function isSatisfiedBy(DateTime $date, $value)
{
// ? states that the field value is to be skipped
if ($value == '?') {
return \true;
}
$fieldValue = $date->format('d');
// Check to see if this is the last day of the month
if ($value == 'L') {
return $fieldValue == $date->format('t');
}
// Check to see if this is the nearest weekday to a particular value
if (\strpos($value, 'W')) {
// Parse the target day
$targetDay = \substr($value, 0, \strpos($value, 'W'));
// Find out if the current day is the nearest day of the week
return $date->format('j') == self::getNearestWeekday($date->format('Y'), $date->format('m'), $targetDay)->format('j');
}
return $this->isSatisfied($date->format('d'), $value);
}
public function increment(DateTime $date, $invert = \false)
{
if ($invert) {
$date->modify('previous day');
$date->setTime(23, 59);
} else {
$date->modify('next day');
$date->setTime(0, 0);
}
return $this;
}
/**
* @inheritDoc
*/
public function validate($value)
{
$basicChecks = parent::validate($value);
// Validate that a list don't have W or L
if (\strpos($value, ',') !== \false && (\strpos($value, 'W') !== \false || \strpos($value, 'L') !== \false)) {
return \false;
}
if (!$basicChecks) {
if ($value === 'L') {
return \true;
}
if (\preg_match('/^(.*)W$/', $value, $matches)) {
return $this->validate($matches[1]);
}
return \false;
}
return $basicChecks;
}
}

View File

@@ -0,0 +1,140 @@
<?php
namespace VendorDuplicator\Cron;
use DateTime;
use InvalidArgumentException;
/**
* Day of week field. Allows: * / , - ? L #
*
* Days of the week can be represented as a number 0-7 (0|7 = Sunday)
* or as a three letter string: SUN, MON, TUE, WED, THU, FRI, SAT.
*
* 'L' stands for "last". It allows you to specify constructs such as
* "the last Friday" of a given month.
*
* '#' is allowed for the day-of-week field, and must be followed by a
* number between one and five. It allows you to specify constructs such as
* "the second Friday" of a given month.
*
* TG changes: replaced [] with array() everywhere
*/
class DayOfWeekField extends AbstractField
{
protected $rangeStart = 0;
protected $rangeEnd = 7;
protected $nthRange;
protected $literals = array(1 => 'MON', 2 => 'TUE', 3 => 'WED', 4 => 'THU', 5 => 'FRI', 6 => 'SAT', 7 => 'SUN');
public function __construct()
{
$this->nthRange = \range(1, 5);
parent::__construct();
}
public function isSatisfiedBy(DateTime $date, $value)
{
if ($value == '?') {
return \true;
}
// Convert text day of the week values to integers
$value = $this->convertLiterals($value);
$currentYear = $date->format('Y');
$currentMonth = $date->format('m');
$lastDayOfMonth = $date->format('t');
// Find out if this is the last specific weekday of the month
if (\strpos($value, 'L')) {
$weekday = \str_replace('7', '0', \substr($value, 0, \strpos($value, 'L')));
$tdate = clone $date;
$tdate->setDate($currentYear, $currentMonth, $lastDayOfMonth);
while ($tdate->format('w') != $weekday) {
$tdateClone = new DateTime();
$tdate = $tdateClone->setTimezone($tdate->getTimezone())->setDate($currentYear, $currentMonth, --$lastDayOfMonth);
}
return $date->format('j') == $lastDayOfMonth;
}
// Handle # hash tokens
if (\strpos($value, '#')) {
list($weekday, $nth) = \explode('#', $value);
if (!\is_numeric($nth)) {
throw new InvalidArgumentException("Hashed weekdays must be numeric, {$nth} given");
} else {
$nth = (int) $nth;
}
// 0 and 7 are both Sunday, however 7 matches date('N') format ISO-8601
if ($weekday === '0') {
$weekday = 7;
}
$weekday = $this->convertLiterals($weekday);
// Validate the hash fields
if ($weekday < 0 || $weekday > 7) {
throw new InvalidArgumentException("Weekday must be a value between 0 and 7. {$weekday} given");
}
if (!\in_array($nth, $this->nthRange)) {
throw new InvalidArgumentException("There are never more than 5 or less than 1 of a given weekday in a month, {$nth} given");
}
// The current weekday must match the targeted weekday to proceed
if ($date->format('N') != $weekday) {
return \false;
}
$tdate = clone $date;
$tdate->setDate($currentYear, $currentMonth, 1);
$dayCount = 0;
$currentDay = 1;
while ($currentDay < $lastDayOfMonth + 1) {
if ($tdate->format('N') == $weekday) {
if (++$dayCount >= $nth) {
break;
}
}
$tdate->setDate($currentYear, $currentMonth, ++$currentDay);
}
return $date->format('j') == $currentDay;
}
// Handle day of the week values
if (\strpos($value, '-')) {
$parts = \explode('-', $value);
if ($parts[0] == '7') {
$parts[0] = '0';
} elseif ($parts[1] == '0') {
$parts[1] = '7';
}
$value = \implode('-', $parts);
}
// Test to see which Sunday to use -- 0 == 7 == Sunday
$format = \in_array(7, \str_split($value)) ? 'N' : 'w';
$fieldValue = $date->format($format);
return $this->isSatisfied($fieldValue, $value);
}
public function increment(DateTime $date, $invert = \false)
{
if ($invert) {
$date->modify('-1 day');
$date->setTime(23, 59, 0);
} else {
$date->modify('+1 day');
$date->setTime(0, 0, 0);
}
return $this;
}
/**
* @inheritDoc
*/
public function validate($value)
{
$basicChecks = parent::validate($value);
if (!$basicChecks) {
// Handle the # value
if (\strpos($value, '#') !== \false) {
$chunks = \explode('#', $value);
$chunks[0] = $this->convertLiterals($chunks[0]);
if (parent::validate($chunks[0]) && \is_numeric($chunks[1]) && \in_array($chunks[1], $this->nthRange)) {
return \true;
}
}
if (\preg_match('/^(.*)L$/', $value, $matches)) {
return $this->validate($matches[1]);
}
return \false;
}
return $basicChecks;
}
}

View File

@@ -0,0 +1,50 @@
<?php
namespace VendorDuplicator\Cron;
use InvalidArgumentException;
/**
* CRON field factory implementing a flyweight factory
* @link http://en.wikipedia.org/wiki/Cron
* TG changes: replaced [] with array() everywhere
*/
class FieldFactory
{
/**
* @var array Cache of instantiated fields
*/
private $fields = array();
/**
* Get an instance of a field object for a cron expression position
*
* @param int $position CRON expression position value to retrieve
*
* @return FieldInterface
* @throws InvalidArgumentException if a position is not valid
*/
public function getField($position)
{
if (!isset($this->fields[$position])) {
switch ($position) {
case 0:
$this->fields[$position] = new MinutesField();
break;
case 1:
$this->fields[$position] = new HoursField();
break;
case 2:
$this->fields[$position] = new DayOfMonthField();
break;
case 3:
$this->fields[$position] = new MonthField();
break;
case 4:
$this->fields[$position] = new DayOfWeekField();
break;
default:
throw new InvalidArgumentException($position . ' is not a valid position');
}
}
return $this->fields[$position];
}
}

View File

@@ -0,0 +1,38 @@
<?php
namespace VendorDuplicator\Cron;
use DateTime;
/**
* CRON field interface
*/
interface FieldInterface
{
/**
* Check if the respective value of a DateTime field satisfies a CRON exp
*
* @param DateTime $date DateTime object to check
* @param string $value CRON expression to test against
*
* @return bool Returns TRUE if satisfied, FALSE otherwise
*/
public function isSatisfiedBy(DateTime $date, $value);
/**
* When a CRON expression is not satisfied, this method is used to increment
* or decrement a DateTime object by the unit of the cron field
*
* @param DateTime $date DateTime object to change
* @param bool $invert (optional) Set to TRUE to decrement
*
* @return FieldInterface
*/
public function increment(DateTime $date, $invert = \false);
/**
* Validates a CRON expression for a given field
*
* @param string $value CRON expression value to validate
*
* @return bool Returns TRUE if valid, FALSE otherwise
*/
public function validate($value);
}

View File

@@ -0,0 +1,59 @@
<?php
namespace VendorDuplicator\Cron;
use DateTime;
use DateTimeZone;
/**
* Hours field. Allows: * , / -
*/
class HoursField extends AbstractField
{
protected $rangeStart = 0;
protected $rangeEnd = 23;
public function isSatisfiedBy(DateTime $date, $value)
{
return $this->isSatisfied($date->format('H'), $value);
}
public function increment(DateTime $date, $invert = \false, $parts = null)
{
// Change timezone to UTC temporarily. This will
// allow us to go back or forwards and hour even
// if DST will be changed between the hours.
if (\is_null($parts) || $parts == '*') {
$timezone = $date->getTimezone();
$date->setTimezone(new DateTimeZone('UTC'));
if ($invert) {
$date->modify('-1 hour');
} else {
$date->modify('+1 hour');
}
$date->setTimezone($timezone);
$date->setTime($date->format('H'), $invert ? 59 : 0);
return $this;
}
$parts = \strpos($parts, ',') !== \false ? \explode(',', $parts) : array($parts);
$hours = array();
foreach ($parts as $part) {
$hours = \array_merge($hours, $this->getRangeForExpression($part, 23));
}
$current_hour = $date->format('H');
$position = $invert ? \count($hours) - 1 : 0;
if (\count($hours) > 1) {
for ($i = 0; $i < \count($hours) - 1; $i++) {
if (!$invert && $current_hour >= $hours[$i] && $current_hour < $hours[$i + 1] || $invert && $current_hour > $hours[$i] && $current_hour <= $hours[$i + 1]) {
$position = $invert ? $i : $i + 1;
break;
}
}
}
$hour = $hours[$position];
if (!$invert && $date->format('H') >= $hour || $invert && $date->format('H') <= $hour) {
$date->modify(($invert ? '-' : '+') . '1 day');
$date->setTime($invert ? 23 : 0, $invert ? 59 : 0);
} else {
$date->setTime($hour, $invert ? 59 : 0);
}
return $this;
}
}

View File

@@ -0,0 +1,50 @@
<?php
namespace VendorDuplicator\Cron;
use DateTime;
/**
* Minutes field. Allows: * , / -
*/
class MinutesField extends AbstractField
{
protected $rangeStart = 0;
protected $rangeEnd = 59;
public function isSatisfiedBy(DateTime $date, $value)
{
return $this->isSatisfied($date->format('i'), $value);
}
public function increment(DateTime $date, $invert = \false, $parts = null)
{
if (\is_null($parts)) {
if ($invert) {
$date->modify('-1 minute');
} else {
$date->modify('+1 minute');
}
return $this;
}
$parts = \strpos($parts, ',') !== \false ? \explode(',', $parts) : array($parts);
$minutes = array();
foreach ($parts as $part) {
$minutes = \array_merge($minutes, $this->getRangeForExpression($part, 59));
}
$current_minute = $date->format('i');
$position = $invert ? \count($minutes) - 1 : 0;
if (\count($minutes) > 1) {
for ($i = 0; $i < \count($minutes) - 1; $i++) {
if (!$invert && $current_minute >= $minutes[$i] && $current_minute < $minutes[$i + 1] || $invert && $current_minute > $minutes[$i] && $current_minute <= $minutes[$i + 1]) {
$position = $invert ? $i : $i + 1;
break;
}
}
}
if (!$invert && $current_minute >= $minutes[$position] || $invert && $current_minute <= $minutes[$position]) {
$date->modify(($invert ? '-' : '+') . '1 hour');
$date->setTime($date->format('H'), $invert ? 59 : 0);
} else {
$date->setTime($date->format('H'), $minutes[$position]);
}
return $this;
}
}

View File

@@ -0,0 +1,31 @@
<?php
namespace VendorDuplicator\Cron;
use DateTime;
/**
* Month field. Allows: * , / -
* TG changes: replaced [] with array() everywhere
*/
class MonthField extends AbstractField
{
protected $rangeStart = 1;
protected $rangeEnd = 12;
protected $literals = array(1 => 'JAN', 2 => 'FEB', 3 => 'MAR', 4 => 'APR', 5 => 'MAY', 6 => 'JUN', 7 => 'JUL', 8 => 'AUG', 9 => 'SEP', 10 => 'OCT', 11 => 'NOV', 12 => 'DEC');
public function isSatisfiedBy(DateTime $date, $value)
{
$value = $this->convertLiterals($value);
return $this->isSatisfied($date->format('m'), $value);
}
public function increment(DateTime $date, $invert = \false)
{
if ($invert) {
$date->modify('last day of previous month');
$date->setTime(23, 59);
} else {
$date->modify('first day of next month');
$date->setTime(0, 0);
}
return $this;
}
}

View File

@@ -0,0 +1,5 @@
<?php
namespace VendorDuplicator;
//Silent

View File

@@ -0,0 +1,40 @@
This is a class to encrypt and decrypt data using some algorithms and methods.
Actually it supports:
- Blowfish
- ECB, CBC (modes)
0. Install
Verify if the algorithm files is in the cipher.
1. How To:
To use this class you need to instanciate it, selecting the mode, algorithm and key, then you can call encrypt and decrypt methods.
Example:
require 'class.pcrypt.php';
/* MODE: MODE_ECB or MODE_CBC
ALGO: BLOWFISH
KEY: Your secret key :) (max lenght: 56)
*/
$crypt = new pcrypt(MODE_ECB, "BLOWFISH", "secretkey");
// to encrypt
$plaintext = "password";
$ciphertext = $crypt->encrypt($plaintext);
// to decrypt
$decrypted = $crypt->decrypt($ciphertext);
2. TODO
- Implement other algorithms and block modes
- Improve error handling function(s)
- Implement methods to discover automatically the ALGO used (maybe a header)
- Implement a method to change the key
- Compatible with mcrypt
- Correct bugs :)
That's all, if you get any trouble please contact.

View File

@@ -0,0 +1,267 @@
<?php
namespace VendorDuplicator;
\defined("ABSPATH") or die("");
// +----------------------------------------------------------------------+
// | Perfect Scripts blowfish.php |
// | Brazilian Organization |
// +----------------------------------------------------------------------+
// | Viva ao Linux! |
// | Porque n<>s amamos a liberdade! |
// +----------------------------------------------------------------------+
// | Class Perfect Crypt |
// | Created By Igor Ribeiro de Assis |
// | <igor21@terra.com.br> UIN: 71064682 |
// +----------------------------------------------------------------------+
// | http://ps.wmforce.com |
// +----------------------------------------------------------------------+
// | Under GPL |
// +----------------------------------------------------------------------+
// | This program is free software; you can redistribute it and/or modify |
// | it under the terms of the GNU General Public License as published |
// | by the Free Software Foundation; either version 2 of the License, |
// | or (at your option) any later version. |
// | |
// | This program is distributed in the hope that it will be useful, |
// | but WITHOUT ANY WARRANTY; without even the implied warranty of |
// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
// | GNU General Public License for more details. |
// | |
// | You should have received a copy of the GNU General Public License |
// | along with this program; if not, write to the Free Software |
// | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA |
// | 02111-1307 USA |
// +----------------------------------------------------------------------+
// | Mon Apr 12 17:01:55 BRT 2004 |
// +----------------------------------------------------------------------+
/**
* Class Blowfish extends PCrypt Class
* This class is a implementation of the Blowfish Crypt Algorithm to use with
* PCrypt Class.
* Based on Bruce Schneier Code in Applied Cryptography Book
*/
class pcrypt_blowfish
{
/** Attributes */
/**
* S-Boxes ($sbox0, $sbox1, $sbox2 and $sbox3)
*
* These are the subkeys boxes with 256 entries each.
*
* @access private
* @var array
*/
var $sbox0 = array(0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, 0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99, 0x24a19947, 0xb3916cf7, 0x801f2e2, 0x858efc16, 0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e, 0xd95748f, 0x728eb658, 0x718bcd58, 0x82154aee, 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013, 0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, 0x8e79dcb0, 0x603a180e, 0x6c9e0e8b, 0xb01e8a3e, 0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60, 0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440, 0x55ca396a, 0x2aab10b6, 0xb4cc5c34, 0x1141e8ce, 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a, 0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, 0xafd6ba33, 0x6c24cf5c, 0x7a325381, 0x28958677, 0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193, 0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032, 0xef845d5d, 0xe98575b1, 0xdc262302, 0xeb651b88, 0x23893e81, 0xd396acc5, 0xf6d6ff3, 0x83f44239, 0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, 0x21c66842, 0xf6e96c9a, 0x670c9c61, 0xabd388f0, 0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3, 0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98, 0xa1f1651d, 0x39af0176, 0x66ca593e, 0x82430e88, 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe, 0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, 0x4ed3aa62, 0x363f7706, 0x1bfedf72, 0x429b023d, 0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b, 0x75372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7, 0xe3fe501a, 0xb6794c3b, 0x976ce0bd, 0x4c006ba, 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463, 0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, 0x6dfc511f, 0x9b30952c, 0xcc814544, 0xaf5ebd09, 0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3, 0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb, 0x5579c0bd, 0x1a60320a, 0xd6a100c6, 0x402c7279, 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8, 0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, 0x323db5fa, 0xfd238760, 0x53317b48, 0x3e00df82, 0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db, 0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573, 0x695b27b0, 0xbbca58c8, 0xe1ffa35d, 0xb8f011a0, 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b, 0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, 0xe1ddf2da, 0xa4cb7e33, 0x62fb1341, 0xcee4c6e8, 0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4, 0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0, 0xd08ed1d0, 0xafc725e0, 0x8e3c5b2f, 0x8e7594b7, 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c, 0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, 0x2f2f2218, 0xbe0e1777, 0xea752dfe, 0x8b021fa1, 0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299, 0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9, 0x165fa266, 0x80957705, 0x93cc7314, 0x211a1477, 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf, 0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, 0x250e2d, 0x2071b35e, 0x226800bb, 0x57b8e0af, 0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa, 0x78c14389, 0xd95a537f, 0x207d5ba2, 0x2e5b9c5, 0x83260376, 0x6295cfa9, 0x11c81968, 0x4e734a41, 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915, 0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, 0x8ba6fb5, 0x571be91f, 0xf296ec6b, 0x2a0dd915, 0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664, 0x53b02d5d, 0xa99f8fa1, 0x8ba4799, 0x6e85076a);
var $sbox1 = array(0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, 0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266, 0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1, 0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e, 0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6, 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1, 0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x21ecc5e, 0x9686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1, 0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737, 0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8, 0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x200b3ff, 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd, 0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, 0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7, 0xa9446146, 0xfd0030e, 0xecc8c73e, 0xa4751e41, 0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331, 0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf, 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af, 0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, 0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87, 0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c, 0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2, 0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16, 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd, 0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, 0x43556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509, 0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e, 0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3, 0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f, 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a, 0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, 0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960, 0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66, 0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x18cff28, 0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802, 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84, 0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, 0x13cca830, 0xeb61bd96, 0x334fe1e, 0xaa0363cf, 0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14, 0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e, 0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50, 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7, 0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, 0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281, 0xe358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99, 0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696, 0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128, 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73, 0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, 0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0, 0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105, 0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250, 0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3, 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285, 0x95bbf00, 0xad19489d, 0x1462b174, 0x23820e00, 0x58428d2a, 0xc55f5ea, 0x1dadf43e, 0x233f7061, 0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb, 0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e, 0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735, 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc, 0x9e447a2e, 0xc3453484, 0xfdd56705, 0xe1e9ec9, 0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340, 0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20, 0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7);
var $sbox2 = array(0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, 0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068, 0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af, 0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840, 0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45, 0xbfbc09ec, 0x3bd9785, 0x7fac6dd0, 0x31cb8504, 0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a, 0x28507825, 0x530429f4, 0xa2c86da, 0xe9b66dfb, 0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee, 0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6, 0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42, 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b, 0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2, 0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb, 0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527, 0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b, 0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33, 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c, 0xfdf8e802, 0x4272f70, 0x80bb155c, 0x5282ce3, 0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc, 0x7f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17, 0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564, 0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b, 0xe12b4c2, 0x2e1329e, 0xaf664fd1, 0xcad18115, 0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, 0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728, 0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0, 0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e, 0xa476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37, 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d, 0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, 0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b, 0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3, 0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb, 0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d, 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c, 0x6a124237, 0xb79251e7, 0x6a1bbe6, 0x4bfb6350, 0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9, 0x44421659, 0xa121386, 0xd90cec6e, 0xd5abea2a, 0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe, 0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d, 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc, 0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f, 0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61, 0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2, 0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9, 0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2, 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c, 0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e, 0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633, 0xe85a1f02, 0x9f0be8c, 0x4a99a025, 0x1d6efe10, 0x1ab93d1d, 0xba5a4df, 0xa186f20f, 0x2868f169, 0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52, 0x50115e01, 0xa70683fa, 0xa002b5c4, 0xde6d027, 0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, 0xf0177a28, 0xc0f586e0, 0x6058aa, 0x30dc7d62, 0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634, 0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76, 0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24, 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc, 0xed545578, 0x8fca5b5, 0xd83d7cd3, 0x4dad0fc4, 0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c, 0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837, 0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0);
var $sbox3 = array(0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, 0x5cb0679e, 0x4fa33742, 0xd3822740, 0x99bc9bbe, 0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b, 0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4, 0x5748ab2f, 0xbc946e79, 0xc6a376d2, 0x6549c2c8, 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6, 0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, 0xa1fad5f0, 0x6a2d519a, 0x63ef8ce2, 0x9a86ee22, 0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4, 0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6, 0x2826a2f9, 0xa73a3ae1, 0x4ba99586, 0xef5562e9, 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59, 0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, 0xe990fd5a, 0x9e34d797, 0x2cf0b7d9, 0x22b8b51, 0x96d5ac3a, 0x17da67d, 0xd1cf3ed6, 0x7c7d2d28, 0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c, 0xe029ac71, 0xe019a5e6, 0x47b0acfd, 0xed93fa9b, 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28, 0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, 0x15056dd4, 0x88f46dba, 0x3a16125, 0x564f0bd, 0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a, 0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319, 0x7533d928, 0xb155fdf5, 0x3563482, 0x8aba3cbb, 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f, 0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, 0xea7a90c2, 0xfb3e7bce, 0x5121ce64, 0x774fbe32, 0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680, 0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x9072166, 0xb39a460a, 0x6445c0dd, 0x586cdecf, 0x1c20c8ae, 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb, 0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, 0x72eacea8, 0xfa6484bb, 0x8d6612ae, 0xbf3c6f47, 0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370, 0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d, 0x4040cb08, 0x4eb4e2cc, 0x34d2466a, 0x115af84, 0xe1b00428, 0x95983a1d, 0x6b89fb4, 0xce6ea048, 0x6f3f3b82, 0x3520ab82, 0x11a1d4b, 0x277227f8, 0x611560b1, 0xe7933fdc, 0xbb3a792b, 0x344525bd, 0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9, 0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7, 0x1a908749, 0xd44fbd9a, 0xd0dadecb, 0xd50ada38, 0x339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f, 0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, 0xbf97222c, 0x15e6fc2a, 0xf91fc71, 0x9b941525, 0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1, 0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442, 0xe0ec6e0e, 0x1698db3b, 0x4c98a0be, 0x3278e964, 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e, 0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, 0xdf359f8d, 0x9b992f2e, 0xe60b6f47, 0xfe3f11d, 0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f, 0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299, 0xf523f357, 0xa6327623, 0x93a83531, 0x56cccd02, 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc, 0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, 0xe6c6c7bd, 0x327a140a, 0x45e1d006, 0xc3f27b9a, 0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6, 0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b, 0x53113ec0, 0x1640e3d3, 0x38abbd60, 0x2547adf0, 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060, 0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, 0x1948c25c, 0x2fb8a8c, 0x1c36ae4, 0xd6ebe1f9, 0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f, 0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6);
/** P-Array consists of 18 32-bit subkeys
*
* @var array $parray
* @access private
*/
var $parray = array(0x243f6a88, 0x85a308d3, 0x13198a2e, 0x3707344, 0xa4093822, 0x299f31d0, 0x82efa98, 0xec4e6c89, 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c, 0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, 0x9216d5d9, 0x8979fb1b);
/** Block size in bytes
*
* @access public
* @var int $blocksize
*/
var $blocksize = 8;
//bytes
public $bctx = array();
/** Methods */
/** The Constructor of the class.
*
* This class make a copy of the $sboxs and $parray and init the subkeys.
*
* @access public
* @param string $key the key used to encrypt and decrypt
* @return void
*/
function __construct($key)
{
$this->bctx = array('p' => $this->parray, 'sb' => array($this->sbox0, $this->sbox1, $this->sbox2, $this->sbox3));
$this->_init($key);
}
/** This functions encrypt the block.
*
* @access private
* @param int $Xl left uInt32 part of the block
* @param int $Xr right uInt32 part of the block
* @return void
*/
function _blowfish_crypt(&$Xl, &$Xr)
{
for ($i = 0; $i < 16; $i++) {
$Xl = $Xl ^ $this->bctx['p'][$i];
$Xr = $this->_F($Xl) ^ $Xr;
// Swap $Xl and $Xr
$tmp = $Xl;
$Xl = $Xr;
$Xr = $tmp;
}
// Undo last swap
$tmp = $Xl;
$Xl = $Xr;
$Xr = $tmp;
$Xr = $Xr ^ $this->bctx['p'][16];
$Xl = $Xl ^ $this->bctx['p'][17];
}
/** This method decrypt the block.
*
* @access private
* @param int $Xl left uInt32 part of the block
* @param int $Xr right uInt32 part of the block
* @return void
*/
function _blowfish_decrypt(&$Xl, &$Xr)
{
for ($i = 17; $i >= 2; $i--) {
$Xl = $Xl ^ $this->bctx['p'][$i];
$Xr = $this->_F($Xl) ^ $Xr;
// Swap $Xl and $Xr
$tmp = $Xl;
$Xl = $Xr;
$Xr = $tmp;
}
// Undo last swap
$tmp = $Xl;
$Xl = $Xr;
$Xr = $tmp;
$Xr = $Xr ^ $this->bctx['p'][1];
$Xl = $Xl ^ $this->bctx['p'][0];
}
/** The F function defined in Blowfish paper.
*
* Divide the block in 4 parts and execute the function
*
* @access private
* @param int $x the block
* @return int $y the new block
*/
function _F($x)
{
$d = $x & 0xff;
$x = $x >> 8;
$c = $x & 0xff;
$x = $x >> 8;
$b = $x & 0xff;
$x = $x >> 8;
$a = $x & 0xff;
$y = $this->bctx['sb'][0][$a] + $this->bctx['sb'][1][$b];
$y = ($y ^ $this->bctx['sb'][2][$c]) + $this->bctx['sb'][3][$d];
return $y;
}
/** This function initialize the subkeys.
*
* @access public
* @param string $key the key used to encrypt and decrypt
* @return void
*/
function _init($key)
{
// unpack binary string in unsigned chars
$key = \array_values(\unpack("C*", $key));
$keyl = \count($key);
$j = 0;
for ($i = 0; $i < 18; $i++) {
// xor P1 with the first 32-bits of the key, xor P2 with the second 32-bits ...
$data = 0;
for ($k = 0; $k < 4; $k++) {
$data = $data << 8 | $key[$j];
$j++;
if ($j >= $keyl) {
$j = 0;
}
}
$this->bctx['p'][$i] = $this->parray[$i] ^ $data;
}
// encrypt the zero-string, replace P1 and P2 with the encrypted data, encrypt P3 and P4 with the new P1 and P2, do it with all P-array and subkeys
$datal = 0;
$datar = 0;
for ($i = 0; $i < 18; $i += 2) {
$this->_blowfish_crypt($datal, $datar);
$this->bctx['p'][$i] = $datal;
$this->bctx['p'][$i + 1] = $datar;
}
for ($i = 0; $i < 4; $i++) {
for ($j = 0; $j < 256; $j += 2) {
$this->_blowfish_crypt($datal, $datar);
$this->bctx['sb'][$i][$j] = $datal;
$this->bctx['sb'][$i][$j + 1] = $datar;
}
}
}
/** This method is called by pcrypt class.
*
* This method encrypt the block and return the new block.
*
* @access public
* @param string $block the block to be encrypted
* @return string the block encrypted
*/
function _encrypt($block)
{
// unpack the block in unsigned long ints (uInt32)
$data = \array_values(\unpack('N*', $block));
// encrypt the block and return the block packed into string
$this->_blowfish_crypt($data[0], $data[1]);
return \pack('N*', $data[0], $data[1]);
}
/** This method is called by pcrypt class.
*
* This method decrypt the cipher block and return the new.
*
* @access public
* @param string $block the encrypted block to be decrypted
* @return string the plain text block
*/
function _decrypt($block)
{
// unpack the block in unsigned long ints (uInt32)
$data = \array_values(\unpack('N*', $block));
// decrypt the block and return the block packed into string
$this->_blowfish_decrypt($data[0], $data[1]);
return \pack('N*', $data[0], $data[1]);
}
}
// +----------------------------------------------------------------------+
// | Perfect Scripts blowfish.php |
// | Brazilian Organization |
// +----------------------------------------------------------------------+
// | Viva ao Linux! |
// | Porque n<>s amamos a liberdade! |
// +----------------------------------------------------------------------+
// | Class Perfect Crypt |
// | Created By Igor Ribeiro de Assis |
// | <igor21@terra.com.br> UIN: 71064682 |
// +----------------------------------------------------------------------+
// | http://ps.wmforce.com |
// +----------------------------------------------------------------------+
// | Under GPL |
// +----------------------------------------------------------------------+
// | This program is free software; you can redistribute it and/or modify |
// | it under the terms of the GNU General Public License as published |
// | by the Free Software Foundation; either version 2 of the License, |
// | or (at your option) any later version. |
// | |
// | This program is distributed in the hope that it will be useful, |
// | but WITHOUT ANY WARRANTY; without even the implied warranty of |
// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
// | GNU General Public License for more details. |
// | |
// | You should have received a copy of the GNU General Public License |
// | along with this program; if not, write to the Free Software |
// | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA |
// | 02111-1307 USA |
// +----------------------------------------------------------------------+
// | Mon Apr 12 17:01:55 BRT 2004 |
// +----------------------------------------------------------------------+
/**
* Class Blowfish extends PCrypt Class
* This class is a implementation of the Blowfish Crypt Algorithm to use with
* PCrypt Class.
* Based on Bruce Schneier Code in Applied Cryptography Book
*/
\class_alias('VendorDuplicator\\pcrypt_blowfish', 'pcrypt_blowfish', \false);

View File

@@ -0,0 +1,5 @@
<?php
namespace VendorDuplicator;
//silent

View File

@@ -0,0 +1,290 @@
<?php
namespace VendorDuplicator;
\defined("ABSPATH") or die("");
// +----------------------------------------------------------------------+
// | Perfect Scripts class.pcrypt.php |
// | Brazilian Organization |
// +----------------------------------------------------------------------+
// | Viva ao Linux! |
// | Porque n<>s amamos a liberdade! |
// +----------------------------------------------------------------------+
// | Class Perfect Crypt |
// | Created By Igor Ribeiro de Assis |
// | <igor21@terra.com.br> UIN: 71064682 |
// +----------------------------------------------------------------------+
// | http://ps.wmforce.com |
// +----------------------------------------------------------------------+
// | Under GPL |
// +----------------------------------------------------------------------+
// | This program is free software; you can redistribute it and/or modify |
// | it under the terms of the GNU General Public License as published |
// | by the Free Software Foundation; either version 2 of the License, |
// | or (at your option) any later version. |
// | |
// | This program is distributed in the hope that it will be useful, |
// | but WITHOUT ANY WARRANTY; without even the implied warranty of |
// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
// | GNU General Public License for more details. |
// | |
// | You should have received a copy of the GNU General Public License |
// | along with this program; if not, write to the Free Software |
// | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA |
// | 02111-1307 USA |
// +----------------------------------------------------------------------+
/**
* Encryption Block Mode constants
*
* @const MODE_ECB ecb mode
* @const MODE_CBC cbc mode
*/
\define("MODE_ECB", 0);
\define("MODE_CBC", 1);
/**
* An abstract layer class to encrypt data.
*
* This class is class is used to encrypt and decrypt data using different algorithms
* and modes.
*
* @author Igor Ribeiro de Assis <igor21@terra.com.br>
* @version 1.0-beta
* @access public
* @package Perfect Crypt
*/
class pcrypt
{
/** Encryption Block Mode: ECB, CBC actually.
*
* @var int the mode used
* @access private
*/
var $blockmode = \MODE_ECB;
/** Key for Encryption
*
* @var string the key used in encryption and decryption
* @access public
*/
var $key = null;
/** IV - Initialization Vector String
*
* @var string initialization vector for some modes (CBC)
* @access public
*/
var $iv = "z4c8e7gh";
public $cipher = null;
/** Methods */
/** Constructor of the class.
*
* The constructor initialize some important vars and include the algorithm
* file.
*
* @access public
* @param int $blockmode the blockmode to use
* @param string $cipher the algorithm used to crypt
* @param string $key the ley used to crypt
*
* @return void
*/
//rsrfunction pcrypt($blockmode = MODE_ECB, $cipher = 'BLOWFISH', $key = null)
function __construct($blockmode = \MODE_ECB, $cipher = 'BLOWFISH', $key = null)
{
// Include cipher_class file
$cipher = \strtolower($cipher);
if (!\file_exists(\dirname(__FILE__) . "/cipher/" . $cipher . ".php")) {
$this->error("Unknown Cipher " . $cipher);
}
include_once \dirname(__FILE__) . "/cipher/" . $cipher . ".php";
// Load cipher_class
if (!\class_exists("pcrypt_" . $cipher)) {
$this->error("Class pcrypt_" . $cipher . " doesn't exists");
}
$class = "pcrypt_" . $cipher;
$this->cipher = new $class($key);
// Initialize Vars
$this->blockmode = $blockmode;
$this->key = $key;
}
/** Crypt data using the selected algorithm
*
* This method encrypt data using the selected algorithm and mode:
* Algorithms: Blowfish
* Modes: ECB, CBC
* For a description about algorithms and modes see:
* Applied Cryptography by Bruce Schneier
*
* @access public
* @param string $plain the plain text to be encrypted
* @return string $cipher the plain text encrypted
*/
function encrypt($plain)
{
if (empty($plain)) {
$this->error("Empty Plain Text");
}
// Encrypt using the correct mode
switch ($this->blockmode) {
case \MODE_ECB:
$cipher = $this->_ecb_encrypt($plain);
break;
case \MODE_CBC:
$cipher = $this->_cbc_encrypt($plain);
break;
default:
$this->error("Invalid mode " . $this->blockmode);
}
return $cipher;
}
/** Decrypt using the selected algorithm
*
* This method decrypt data using the selected algorithm and mode.
* TODO: Discover the algorithm and mode auto
*
* @access public
* @param string $cipher the crypted data to be decrypted
* @return string $plain the cipher text decrypted
*/
function decrypt($cipher)
{
if (empty($cipher)) {
$this->error("Invalid Cipher Text");
}
// Decrypt with the correct mode
switch ($this->blockmode) {
case \MODE_ECB:
$plain = $this->_ecb_decrypt($cipher);
break;
case \MODE_CBC:
$plain = $this->_cbc_decrypt($cipher);
break;
default:
$this->error("Invalid mode " . $this->blockmode);
}
return $plain;
}
/** Method to encrypt using ECB mode.
*
* In ECB mode the blocks are encrypted independently
*
* @access private
* @param string $plain the plain text to be encrypted
* @return string $cipher the plain text encrypted
*/
function _ecb_encrypt($plain)
{
$blocksize = $this->cipher->blocksize;
$plainsize = \strlen($plain);
$cipher = '';
for ($i = 0; $i < $plainsize; $i = $i + $blocksize) {
$block = \substr($plain, $i, $blocksize);
if (\strlen($block) < $blocksize) {
// pad block with '\0'
$block = \str_pad($block, $blocksize, "\x00", \STR_PAD_LEFT);
}
$cipher .= $this->cipher->_encrypt($block);
}
return $cipher;
}
/** Method to decrypt using ECB mode.
*
* @access private
* @param string $cipher the cipher text
* @return string $plain the cipher text decrypted
*/
function _ecb_decrypt($cipher)
{
$blocksize = $this->cipher->blocksize;
$ciphersize = \strlen($cipher);
$plain = '';
for ($i = 0; $i < $ciphersize; $i = $i + $blocksize) {
$block = \substr($cipher, $i, $blocksize);
$block = $this->cipher->_decrypt($block);
// Remove padded chars
while (\substr($block, 0, 1) == "\x00") {
$block = \substr($block, 1);
}
$plain .= $block;
}
return $plain;
}
/** This method encrypt using CBC mode.
*
* In CBC mode each block is xored with the last. This function use $iv as
* first block.
*
* @access private
* @param string $plain the plain text to be decrypted
* @return string $cipher the plain text encrypted
*/
function _cbc_encrypt($plain)
{
$blocksize = $this->cipher->blocksize;
$plainsize = \strlen($plain);
$cipher = '';
$lcipher = $this->iv;
// encrypt each block
for ($i = 0; $i < $plainsize; $i = $i + $blocksize) {
$block = \substr($plain, $i, $blocksize);
if (\strlen($block) < $blocksize) {
// pad block with '\0'
$block = \str_pad($block, $blocksize, "\x00", \STR_PAD_LEFT);
}
// crypt the block xored with the last cipher block
$lcipher = $this->cipher->_encrypt($block ^ $lcipher);
$cipher .= $lcipher;
}
return $cipher;
}
/** This method decrypt using CBC.
*
* @access private
* @param string $cipher the cipher text
* @return string $plain the cipher text decrypted
*/
function _cbc_decrypt($cipher)
{
// get the block size of the cipher
$blocksize = $this->cipher->blocksize;
$ciphersize = \strlen($cipher);
$plain = '';
$lcipher = $this->iv;
for ($i = 0; $i < $ciphersize; $i = $i + $blocksize) {
$block = \substr($cipher, $i, $blocksize);
// xor the block with the last cipher block
$dblock = $lcipher ^ $this->cipher->_decrypt($block);
$lcipher = $block;
// Remove padded chars
while (\substr($dblock, 0, 1) == "\x00") {
$dblock = \substr($dblock, 1);
}
$plain .= $dblock;
}
return $plain;
}
/**
* A simple function for error handling.
*
* TODO: Improve the error handling of the class
*
* @access private
* @param string $message erro message
* @return boolean true
*/
function error($message)
{
echo "Error: " . $message . "<br>";
return 1;
}
}
/**
* An abstract layer class to encrypt data.
*
* This class is class is used to encrypt and decrypt data using different algorithms
* and modes.
*
* @author Igor Ribeiro de Assis <igor21@terra.com.br>
* @version 1.0-beta
* @access public
* @package Perfect Crypt
*/
\class_alias('VendorDuplicator\\pcrypt', 'pcrypt', \false);

View File

@@ -0,0 +1,17 @@
<?php
namespace VendorDuplicator;
require 'class.pcrypt.php';
/*
MODE: MODE_ECB or MODE_CBC
ALGO: BLOWFISH
KEY: Your secret key :) (max lenght: 56)
*/
$crypt = new pcrypt(\MODE_ECB, "BLOWFISH", "secretkey");
// to encrypt
$plaintext = "password";
$ciphertext = $crypt->encrypt($plaintext);
// to decrypt
$decrypted = $crypt->decrypt($ciphertext);
echo $plaintext . "<br />" . $ciphertext . "<br />" . $decrypted;

View File

@@ -0,0 +1,341 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.

View File

@@ -0,0 +1,5 @@
<?php
namespace VendorDuplicator;
//silent

View File

@@ -0,0 +1,10 @@
<?xml version="1.0"?>
<psalm
name="Example Psalm config with recommended defaults"
useDocblockTypes="true"
totallyTyped="false"
>
<projectFiles>
<directory name="src" />
</projectFiles>
</psalm>

View File

@@ -0,0 +1,324 @@
<?php
namespace VendorDuplicator\ParagonIE\ConstantTime;
/**
* Copyright (c) 2016 - 2017 Paragon Initiative Enterprises.
* Copyright (c) 2014 Steve "Sc00bz" Thomas (steve at tobtu dot com)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* Class Base32
* [A-Z][2-7]
*
* @package VendorDuplicator\ParagonIE\ConstantTime
*/
abstract class Base32 implements EncoderInterface
{
/**
* Decode a Base32-encoded string into raw binary
*
* @param string $encoded_string
* @param bool $strictPadding
* @return string
*/
public static function decode($encoded_string, $strictPadding = \false)
{
return static::doDecode($encoded_string, \false, $strictPadding);
}
/**
* Decode an uppercase Base32-encoded string into raw binary
*
* @param string $src
* @param bool $strictPadding
* @return string
*/
public static function decodeUpper($src, $strictPadding = \false)
{
return static::doDecode($src, \true, $strictPadding);
}
/**
* Encode into Base32 (RFC 4648)
*
* @param string $bin_string
* @return string
*/
public static function encode($bin_string)
{
return static::doEncode($bin_string, \false);
}
/**
* Encode into Base32 (RFC 4648)
*
* @param string $src
* @return string
* @throws \TypeError
*/
public static function encodeUnpadded($src)
{
return static::doEncode($src, \false, \false);
}
/**
* Encode into uppercase Base32 (RFC 4648)
*
* @param string $src
* @return string
*/
public static function encodeUpper($src)
{
return static::doEncode($src, \true);
}
/**
* Encode into uppercase Base32 (RFC 4648)
*
* @param string $src
* @return string
* @throws \TypeError
*/
public static function encodeUpperUnpadded($src)
{
return static::doEncode($src, \true, \false);
}
/**
* Uses bitwise operators instead of table-lookups to turn 5-bit integers
* into 8-bit integers.
*
* @param int $src
* @return int
*/
protected static function decode5Bits($src)
{
$ret = -1;
// if ($src > 96 && $src < 123) $ret += $src - 97 + 1; // -64
$ret += (0x60 - $src & $src - 0x7b) >> 8 & $src - 96;
// if ($src > 0x31 && $src < 0x38) $ret += $src - 24 + 1; // -23
$ret += (0x31 - $src & $src - 0x38) >> 8 & $src - 23;
return $ret;
}
/**
* Uses bitwise operators instead of table-lookups to turn 5-bit integers
* into 8-bit integers.
*
* Uppercase variant.
*
* @param int $src
* @return int
*/
protected static function decode5BitsUpper($src)
{
$ret = -1;
// if ($src > 64 && $src < 91) $ret += $src - 65 + 1; // -64
$ret += (0x40 - $src & $src - 0x5b) >> 8 & $src - 64;
// if ($src > 0x31 && $src < 0x38) $ret += $src - 24 + 1; // -23
$ret += (0x31 - $src & $src - 0x38) >> 8 & $src - 23;
return $ret;
}
/**
* Uses bitwise operators instead of table-lookups to turn 8-bit integers
* into 5-bit integers.
*
* @param int $src
* @return string
*/
protected static function encode5Bits($src)
{
$diff = 0x61;
// if ($src > 25) $ret -= 72;
$diff -= 25 - $src >> 8 & 73;
return \pack('C', $src + $diff);
}
/**
* Uses bitwise operators instead of table-lookups to turn 8-bit integers
* into 5-bit integers.
*
* Uppercase variant.
*
* @param int $src
* @return string
*/
protected static function encode5BitsUpper($src)
{
$diff = 0x41;
// if ($src > 25) $ret -= 40;
$diff -= 25 - $src >> 8 & 41;
return \pack('C', $src + $diff);
}
/**
* Base32 decoding
*
* @param string $src
* @param bool $upper
* @param bool $strictPadding
* @return string
*/
protected static function doDecode($src, $upper = \false, $strictPadding = \true)
{
// We do this to reduce code duplication:
$method = $upper ? 'decode5BitsUpper' : 'decode5Bits';
// Remove padding
$srcLen = Binary::safeStrlen($src);
if ($srcLen === 0) {
return '';
}
if ($strictPadding) {
if (($srcLen & 7) === 0) {
for ($j = 0; $j < 7; ++$j) {
if ($src[$srcLen - 1] === '=') {
$srcLen--;
} else {
break;
}
}
}
if (($srcLen & 7) === 1) {
throw new \RangeException('Incorrect padding');
}
} else {
$src = \rtrim($src, '=');
$srcLen = Binary::safeStrlen($src);
}
$err = 0;
$dest = '';
// Main loop (no padding):
for ($i = 0; $i + 8 <= $srcLen; $i += 8) {
$chunk = \unpack('C*', Binary::safeSubstr($src, $i, 8));
$c0 = static::$method($chunk[1]);
$c1 = static::$method($chunk[2]);
$c2 = static::$method($chunk[3]);
$c3 = static::$method($chunk[4]);
$c4 = static::$method($chunk[5]);
$c5 = static::$method($chunk[6]);
$c6 = static::$method($chunk[7]);
$c7 = static::$method($chunk[8]);
$dest .= \pack('CCCCC', ($c0 << 3 | $c1 >> 2) & 0xff, ($c1 << 6 | $c2 << 1 | $c3 >> 4) & 0xff, ($c3 << 4 | $c4 >> 1) & 0xff, ($c4 << 7 | $c5 << 2 | $c6 >> 3) & 0xff, ($c6 << 5 | $c7) & 0xff);
$err |= ($c0 | $c1 | $c2 | $c3 | $c4 | $c5 | $c6 | $c7) >> 8;
}
// The last chunk, which may have padding:
if ($i < $srcLen) {
$chunk = \unpack('C*', Binary::safeSubstr($src, $i, $srcLen - $i));
$c0 = static::$method($chunk[1]);
if ($i + 6 < $srcLen) {
$c1 = static::$method($chunk[2]);
$c2 = static::$method($chunk[3]);
$c3 = static::$method($chunk[4]);
$c4 = static::$method($chunk[5]);
$c5 = static::$method($chunk[6]);
$c6 = static::$method($chunk[7]);
$dest .= \pack('CCCC', ($c0 << 3 | $c1 >> 2) & 0xff, ($c1 << 6 | $c2 << 1 | $c3 >> 4) & 0xff, ($c3 << 4 | $c4 >> 1) & 0xff, ($c4 << 7 | $c5 << 2 | $c6 >> 3) & 0xff);
$err |= ($c0 | $c1 | $c2 | $c3 | $c4 | $c5 | $c6) >> 8;
} elseif ($i + 5 < $srcLen) {
$c1 = static::$method($chunk[2]);
$c2 = static::$method($chunk[3]);
$c3 = static::$method($chunk[4]);
$c4 = static::$method($chunk[5]);
$c5 = static::$method($chunk[6]);
$dest .= \pack('CCCC', ($c0 << 3 | $c1 >> 2) & 0xff, ($c1 << 6 | $c2 << 1 | $c3 >> 4) & 0xff, ($c3 << 4 | $c4 >> 1) & 0xff, ($c4 << 7 | $c5 << 2) & 0xff);
$err |= ($c0 | $c1 | $c2 | $c3 | $c4 | $c5) >> 8;
} elseif ($i + 4 < $srcLen) {
$c1 = static::$method($chunk[2]);
$c2 = static::$method($chunk[3]);
$c3 = static::$method($chunk[4]);
$c4 = static::$method($chunk[5]);
$dest .= \pack('CCC', ($c0 << 3 | $c1 >> 2) & 0xff, ($c1 << 6 | $c2 << 1 | $c3 >> 4) & 0xff, ($c3 << 4 | $c4 >> 1) & 0xff);
$err |= ($c0 | $c1 | $c2 | $c3 | $c4) >> 8;
} elseif ($i + 3 < $srcLen) {
$c1 = static::$method($chunk[2]);
$c2 = static::$method($chunk[3]);
$c3 = static::$method($chunk[4]);
$dest .= \pack('CC', ($c0 << 3 | $c1 >> 2) & 0xff, ($c1 << 6 | $c2 << 1 | $c3 >> 4) & 0xff);
$err |= ($c0 | $c1 | $c2 | $c3) >> 8;
} elseif ($i + 2 < $srcLen) {
$c1 = static::$method($chunk[2]);
$c2 = static::$method($chunk[3]);
$dest .= \pack('CC', ($c0 << 3 | $c1 >> 2) & 0xff, ($c1 << 6 | $c2 << 1) & 0xff);
$err |= ($c0 | $c1 | $c2) >> 8;
} elseif ($i + 1 < $srcLen) {
$c1 = static::$method($chunk[2]);
$dest .= \pack('C', ($c0 << 3 | $c1 >> 2) & 0xff);
$err |= ($c0 | $c1) >> 8;
} else {
$dest .= \pack('C', $c0 << 3 & 0xff);
$err |= $c0 >> 8;
}
}
if ($err !== 0) {
throw new \RangeException('Base32::doDecode() only expects characters in the correct base32 alphabet');
}
return $dest;
}
/**
* Base32 Decoding
*
* @param string $src
* @param bool $upper
* @param bool $pad
* @return string
*/
protected static function doEncode($src, $upper = \false, $pad = \true)
{
// We do this to reduce code duplication:
$method = $upper ? 'encode5BitsUpper' : 'encode5Bits';
$dest = '';
$srcLen = Binary::safeStrlen($src);
// Main loop (no padding):
for ($i = 0; $i + 5 <= $srcLen; $i += 5) {
$chunk = \unpack('C*', Binary::safeSubstr($src, $i, 5));
$b0 = $chunk[1];
$b1 = $chunk[2];
$b2 = $chunk[3];
$b3 = $chunk[4];
$b4 = $chunk[5];
$dest .= static::$method($b0 >> 3 & 31) . static::$method(($b0 << 2 | $b1 >> 6) & 31) . static::$method($b1 >> 1 & 31) . static::$method(($b1 << 4 | $b2 >> 4) & 31) . static::$method(($b2 << 1 | $b3 >> 7) & 31) . static::$method($b3 >> 2 & 31) . static::$method(($b3 << 3 | $b4 >> 5) & 31) . static::$method($b4 & 31);
}
// The last chunk, which may have padding:
if ($i < $srcLen) {
$chunk = \unpack('C*', Binary::safeSubstr($src, $i, $srcLen - $i));
$b0 = $chunk[1];
if ($i + 3 < $srcLen) {
$b1 = $chunk[2];
$b2 = $chunk[3];
$b3 = $chunk[4];
$dest .= static::$method($b0 >> 3 & 31) . static::$method(($b0 << 2 | $b1 >> 6) & 31) . static::$method($b1 >> 1 & 31) . static::$method(($b1 << 4 | $b2 >> 4) & 31) . static::$method(($b2 << 1 | $b3 >> 7) & 31) . static::$method($b3 >> 2 & 31) . static::$method($b3 << 3 & 31);
if ($pad) {
$dest .= '=';
}
} elseif ($i + 2 < $srcLen) {
$b1 = $chunk[2];
$b2 = $chunk[3];
$dest .= static::$method($b0 >> 3 & 31) . static::$method(($b0 << 2 | $b1 >> 6) & 31) . static::$method($b1 >> 1 & 31) . static::$method(($b1 << 4 | $b2 >> 4) & 31) . static::$method($b2 << 1 & 31);
if ($pad) {
$dest .= '===';
}
} elseif ($i + 1 < $srcLen) {
$b1 = $chunk[2];
$dest .= static::$method($b0 >> 3 & 31) . static::$method(($b0 << 2 | $b1 >> 6) & 31) . static::$method($b1 >> 1 & 31) . static::$method($b1 << 4 & 31);
if ($pad) {
$dest .= '====';
}
} else {
$dest .= static::$method($b0 >> 3 & 31) . static::$method($b0 << 2 & 31);
if ($pad) {
$dest .= '======';
}
}
}
return $dest;
}
}

View File

@@ -0,0 +1,97 @@
<?php
namespace VendorDuplicator\ParagonIE\ConstantTime;
/**
* Copyright (c) 2016 - 2017 Paragon Initiative Enterprises.
* Copyright (c) 2014 Steve "Sc00bz" Thomas (steve at tobtu dot com)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* Class Base32Hex
* [0-9][A-V]
*
* @package VendorDuplicator\ParagonIE\ConstantTime
*/
abstract class Base32Hex extends Base32
{
/**
* Uses bitwise operators instead of table-lookups to turn 5-bit integers
* into 8-bit integers.
*
* @param int $src
* @return int
*/
protected static function decode5Bits($src)
{
$ret = -1;
// if ($src > 0x30 && $src < 0x3a) ret += $src - 0x2e + 1; // -47
$ret += (0x2f - $src & $src - 0x3a) >> 8 & $src - 47;
// if ($src > 0x60 && $src < 0x77) ret += $src - 0x61 + 10 + 1; // -86
$ret += (0x60 - $src & $src - 0x77) >> 8 & $src - 86;
return $ret;
}
/**
* Uses bitwise operators instead of table-lookups to turn 5-bit integers
* into 8-bit integers.
*
* @param int $src
* @return int
*/
protected static function decode5BitsUpper($src)
{
$ret = -1;
// if ($src > 0x30 && $src < 0x3a) ret += $src - 0x2e + 1; // -47
$ret += (0x2f - $src & $src - 0x3a) >> 8 & $src - 47;
// if ($src > 0x40 && $src < 0x57) ret += $src - 0x41 + 10 + 1; // -54
$ret += (0x40 - $src & $src - 0x57) >> 8 & $src - 54;
return $ret;
}
/**
* Uses bitwise operators instead of table-lookups to turn 8-bit integers
* into 5-bit integers.
*
* @param int $src
* @return string
*/
protected static function encode5Bits($src)
{
$src += 0x30;
// if ($src > 0x39) $src += 0x61 - 0x3a; // 39
$src += 0x39 - $src >> 8 & 39;
return \pack('C', $src);
}
/**
* Uses bitwise operators instead of table-lookups to turn 8-bit integers
* into 5-bit integers.
*
* Uppercase variant.
*
* @param int $src
* @return string
*/
protected static function encode5BitsUpper($src)
{
$src += 0x30;
// if ($src > 0x39) $src += 0x41 - 0x3a; // 7
$src += 0x39 - $src >> 8 & 7;
return \pack('C', $src);
}
}

View File

@@ -0,0 +1,208 @@
<?php
namespace VendorDuplicator\ParagonIE\ConstantTime;
/**
* Copyright (c) 2016 - 2017 Paragon Initiative Enterprises.
* Copyright (c) 2014 Steve "Sc00bz" Thomas (steve at tobtu dot com)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* Class Base64
* [A-Z][a-z][0-9]+/
*
* @package VendorDuplicator\ParagonIE\ConstantTime
*/
abstract class Base64 implements EncoderInterface
{
/**
* Encode into Base64
*
* Base64 character set "[A-Z][a-z][0-9]+/"
*
* @param string $bin_string
* @return string
*/
public static function encode($bin_string)
{
return static::doEncode($bin_string, \true);
}
/**
* Encode into Base64, no = padding
*
* Base64 character set "[A-Z][a-z][0-9]+/"
*
* @param string $src
* @return string
*/
public static function encodeUnpadded($src)
{
return static::doEncode($src, \false);
}
/**
* @param string $src
* @param bool $pad Include = padding?
* @return string
*/
protected static function doEncode($src, $pad = \true)
{
$dest = '';
$srcLen = Binary::safeStrlen($src);
// Main loop (no padding):
for ($i = 0; $i + 3 <= $srcLen; $i += 3) {
$chunk = \unpack('C*', Binary::safeSubstr($src, $i, 3));
$b0 = $chunk[1];
$b1 = $chunk[2];
$b2 = $chunk[3];
$dest .= static::encode6Bits($b0 >> 2) . static::encode6Bits(($b0 << 4 | $b1 >> 4) & 63) . static::encode6Bits(($b1 << 2 | $b2 >> 6) & 63) . static::encode6Bits($b2 & 63);
}
// The last chunk, which may have padding:
if ($i < $srcLen) {
$chunk = \unpack('C*', Binary::safeSubstr($src, $i, $srcLen - $i));
$b0 = $chunk[1];
if ($i + 1 < $srcLen) {
$b1 = $chunk[2];
$dest .= static::encode6Bits($b0 >> 2) . static::encode6Bits(($b0 << 4 | $b1 >> 4) & 63) . static::encode6Bits($b1 << 2 & 63);
if ($pad) {
$dest .= '=';
}
} else {
$dest .= static::encode6Bits($b0 >> 2) . static::encode6Bits($b0 << 4 & 63);
if ($pad) {
$dest .= '==';
}
}
}
return $dest;
}
/**
* decode from base64 into binary
*
* Base64 character set "./[A-Z][a-z][0-9]"
*
* @param string $encoded_string
* @param bool $strictPadding
* @return string
* @throws \RangeException
*/
public static function decode($encoded_string, $strictPadding = \false)
{
// Remove padding
$srcLen = Binary::safeStrlen($encoded_string);
if ($srcLen === 0) {
return '';
}
if ($strictPadding) {
if (($srcLen & 3) === 0) {
if ($encoded_string[$srcLen - 1] === '=') {
$srcLen--;
if ($encoded_string[$srcLen - 1] === '=') {
$srcLen--;
}
}
}
if (($srcLen & 3) === 1) {
throw new \RangeException('Incorrect padding');
}
} else {
$encoded_string = \rtrim($encoded_string, '=');
$srcLen = Binary::safeStrlen($encoded_string);
}
$err = 0;
$dest = '';
// Main loop (no padding):
for ($i = 0; $i + 4 <= $srcLen; $i += 4) {
$chunk = \unpack('C*', Binary::safeSubstr($encoded_string, $i, 4));
$c0 = static::decode6Bits($chunk[1]);
$c1 = static::decode6Bits($chunk[2]);
$c2 = static::decode6Bits($chunk[3]);
$c3 = static::decode6Bits($chunk[4]);
$dest .= \pack('CCC', ($c0 << 2 | $c1 >> 4) & 0xff, ($c1 << 4 | $c2 >> 2) & 0xff, ($c2 << 6 | $c3) & 0xff);
$err |= ($c0 | $c1 | $c2 | $c3) >> 8;
}
// The last chunk, which may have padding:
if ($i < $srcLen) {
$chunk = \unpack('C*', Binary::safeSubstr($encoded_string, $i, $srcLen - $i));
$c0 = static::decode6Bits($chunk[1]);
if ($i + 2 < $srcLen) {
$c1 = static::decode6Bits($chunk[2]);
$c2 = static::decode6Bits($chunk[3]);
$dest .= \pack('CC', ($c0 << 2 | $c1 >> 4) & 0xff, ($c1 << 4 | $c2 >> 2) & 0xff);
$err |= ($c0 | $c1 | $c2) >> 8;
} elseif ($i + 1 < $srcLen) {
$c1 = static::decode6Bits($chunk[2]);
$dest .= \pack('C', ($c0 << 2 | $c1 >> 4) & 0xff);
$err |= ($c0 | $c1) >> 8;
} elseif ($i < $srcLen && $strictPadding) {
$err |= 1;
}
}
if ($err !== 0) {
throw new \RangeException('Base64::decode() only expects characters in the correct base64 alphabet');
}
return $dest;
}
/**
* Uses bitwise operators instead of table-lookups to turn 6-bit integers
* into 8-bit integers.
*
* Base64 character set:
* [A-Z] [a-z] [0-9] + /
* 0x41-0x5a, 0x61-0x7a, 0x30-0x39, 0x2b, 0x2f
*
* @param int $src
* @return int
*/
protected static function decode6Bits($src)
{
$ret = -1;
// if ($src > 0x40 && $src < 0x5b) $ret += $src - 0x41 + 1; // -64
$ret += (0x40 - $src & $src - 0x5b) >> 8 & $src - 64;
// if ($src > 0x60 && $src < 0x7b) $ret += $src - 0x61 + 26 + 1; // -70
$ret += (0x60 - $src & $src - 0x7b) >> 8 & $src - 70;
// if ($src > 0x2f && $src < 0x3a) $ret += $src - 0x30 + 52 + 1; // 5
$ret += (0x2f - $src & $src - 0x3a) >> 8 & $src + 5;
// if ($src == 0x2b) $ret += 62 + 1;
$ret += (0x2a - $src & $src - 0x2c) >> 8 & 63;
// if ($src == 0x2f) ret += 63 + 1;
$ret += (0x2e - $src & $src - 0x30) >> 8 & 64;
return $ret;
}
/**
* Uses bitwise operators instead of table-lookups to turn 8-bit integers
* into 6-bit integers.
*
* @param int $src
* @return string
*/
protected static function encode6Bits($src)
{
$diff = 0x41;
// if ($src > 25) $diff += 0x61 - 0x41 - 26; // 6
$diff += 25 - $src >> 8 & 6;
// if ($src > 51) $diff += 0x30 - 0x61 - 26; // -75
$diff -= 51 - $src >> 8 & 75;
// if ($src > 61) $diff += 0x2b - 0x30 - 10; // -15
$diff -= 61 - $src >> 8 & 15;
// if ($src > 62) $diff += 0x2f - 0x2b - 1; // 3
$diff += 62 - $src >> 8 & 3;
return \pack('C', $src + $diff);
}
}

View File

@@ -0,0 +1,77 @@
<?php
namespace VendorDuplicator\ParagonIE\ConstantTime;
/**
* Copyright (c) 2016 - 2017 Paragon Initiative Enterprises.
* Copyright (c) 2014 Steve "Sc00bz" Thomas (steve at tobtu dot com)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* Class Base64DotSlash
* ./[A-Z][a-z][0-9]
*
* @package VendorDuplicator\ParagonIE\ConstantTime
*/
abstract class Base64DotSlash extends Base64
{
/**
* Uses bitwise operators instead of table-lookups to turn 6-bit integers
* into 8-bit integers.
*
* Base64 character set:
* ./ [A-Z] [a-z] [0-9]
* 0x2e-0x2f, 0x41-0x5a, 0x61-0x7a, 0x30-0x39
*
* @param int $src
* @return int
*/
protected static function decode6Bits($src)
{
$ret = -1;
// if ($src > 0x2d && $src < 0x30) ret += $src - 0x2e + 1; // -45
$ret += (0x2d - $src & $src - 0x30) >> 8 & $src - 45;
// if ($src > 0x40 && $src < 0x5b) ret += $src - 0x41 + 2 + 1; // -62
$ret += (0x40 - $src & $src - 0x5b) >> 8 & $src - 62;
// if ($src > 0x60 && $src < 0x7b) ret += $src - 0x61 + 28 + 1; // -68
$ret += (0x60 - $src & $src - 0x7b) >> 8 & $src - 68;
// if ($src > 0x2f && $src < 0x3a) ret += $src - 0x30 + 54 + 1; // 7
$ret += (0x2f - $src & $src - 0x3a) >> 8 & $src + 7;
return $ret;
}
/**
* Uses bitwise operators instead of table-lookups to turn 8-bit integers
* into 6-bit integers.
*
* @param int $src
* @return string
*/
protected static function encode6Bits($src)
{
$src += 0x2e;
// if ($src > 0x2f) $src += 0x41 - 0x30; // 17
$src += 0x2f - $src >> 8 & 17;
// if ($src > 0x5a) $src += 0x61 - 0x5b; // 6
$src += 0x5a - $src >> 8 & 6;
// if ($src > 0x7a) $src += 0x30 - 0x7b; // -75
$src -= 0x7a - $src >> 8 & 75;
return \pack('C', $src);
}
}

View File

@@ -0,0 +1,73 @@
<?php
namespace VendorDuplicator\ParagonIE\ConstantTime;
/**
* Copyright (c) 2016 - 2017 Paragon Initiative Enterprises.
* Copyright (c) 2014 Steve "Sc00bz" Thomas (steve at tobtu dot com)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* Class Base64DotSlashOrdered
* ./[0-9][A-Z][a-z]
*
* @package VendorDuplicator\ParagonIE\ConstantTime
*/
abstract class Base64DotSlashOrdered extends Base64
{
/**
* Uses bitwise operators instead of table-lookups to turn 6-bit integers
* into 8-bit integers.
*
* Base64 character set:
* [.-9] [A-Z] [a-z]
* 0x2e-0x39, 0x41-0x5a, 0x61-0x7a
*
* @param int $src
* @return int
*/
protected static function decode6Bits($src)
{
$ret = -1;
// if ($src > 0x2d && $src < 0x3a) ret += $src - 0x2e + 1; // -45
$ret += (0x2d - $src & $src - 0x3a) >> 8 & $src - 45;
// if ($src > 0x40 && $src < 0x5b) ret += $src - 0x41 + 12 + 1; // -52
$ret += (0x40 - $src & $src - 0x5b) >> 8 & $src - 52;
// if ($src > 0x60 && $src < 0x7b) ret += $src - 0x61 + 38 + 1; // -58
$ret += (0x60 - $src & $src - 0x7b) >> 8 & $src - 58;
return $ret;
}
/**
* Uses bitwise operators instead of table-lookups to turn 8-bit integers
* into 6-bit integers.
*
* @param int $src
* @return string
*/
protected static function encode6Bits($src)
{
$src += 0x2e;
// if ($src > 0x39) $src += 0x41 - 0x3a; // 7
$src += 0x39 - $src >> 8 & 7;
// if ($src > 0x5a) $src += 0x61 - 0x5b; // 6
$src += 0x5a - $src >> 8 & 6;
return \pack('C', $src);
}
}

View File

@@ -0,0 +1,81 @@
<?php
namespace VendorDuplicator\ParagonIE\ConstantTime;
/**
* Copyright (c) 2016 - 2017 Paragon Initiative Enterprises.
* Copyright (c) 2014 Steve "Sc00bz" Thomas (steve at tobtu dot com)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* Class Base64DotSlash
* ./[A-Z][a-z][0-9]
*
* @package VendorDuplicator\ParagonIE\ConstantTime
*/
abstract class Base64UrlSafe extends Base64
{
/**
* Uses bitwise operators instead of table-lookups to turn 6-bit integers
* into 8-bit integers.
*
* Base64 character set:
* [A-Z] [a-z] [0-9] - _
* 0x41-0x5a, 0x61-0x7a, 0x30-0x39, 0x2d, 0x5f
*
* @param int $src
* @return int
*/
protected static function decode6Bits($src)
{
$ret = -1;
// if ($src > 0x40 && $src < 0x5b) $ret += $src - 0x41 + 1; // -64
$ret += (0x40 - $src & $src - 0x5b) >> 8 & $src - 64;
// if ($src > 0x60 && $src < 0x7b) $ret += $src - 0x61 + 26 + 1; // -70
$ret += (0x60 - $src & $src - 0x7b) >> 8 & $src - 70;
// if ($src > 0x2f && $src < 0x3a) $ret += $src - 0x30 + 52 + 1; // 5
$ret += (0x2f - $src & $src - 0x3a) >> 8 & $src + 5;
// if ($src == 0x2c) $ret += 62 + 1;
$ret += (0x2c - $src & $src - 0x2e) >> 8 & 63;
// if ($src == 0x5f) ret += 63 + 1;
$ret += (0x5e - $src & $src - 0x60) >> 8 & 64;
return $ret;
}
/**
* Uses bitwise operators instead of table-lookups to turn 8-bit integers
* into 6-bit integers.
*
* @param int $src
* @return string
*/
protected static function encode6Bits($src)
{
$diff = 0x41;
// if ($src > 25) $diff += 0x61 - 0x41 - 26; // 6
$diff += 25 - $src >> 8 & 6;
// if ($src > 51) $diff += 0x30 - 0x61 - 26; // -75
$diff -= 51 - $src >> 8 & 75;
// if ($src > 61) $diff += 0x2d - 0x30 - 10; // -13
$diff -= 61 - $src >> 8 & 13;
// if ($src > 62) $diff += 0x5f - 0x2b - 1; // 3
$diff += 62 - $src >> 8 & 49;
return \pack('C', $src + $diff);
}
}

View File

@@ -0,0 +1,93 @@
<?php
namespace VendorDuplicator\ParagonIE\ConstantTime;
/**
* Copyright (c) 2016 - 2017 Paragon Initiative Enterprises.
* Copyright (c) 2014 Steve "Sc00bz" Thomas (steve at tobtu dot com)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* Class Binary
*
* Binary string operators that don't choke on
* mbstring.func_overload
*
* @package VendorDuplicator\ParagonIE\ConstantTime
*/
abstract class Binary
{
/**
* Safe string length
*
* @ref mbstring.func_overload
*
* @param string $str
* @return int
*/
public static function safeStrlen($str)
{
if (\function_exists('mb_strlen')) {
return \mb_strlen($str, '8bit');
} else {
return \strlen($str);
}
}
/**
* Safe substring
*
* @ref mbstring.func_overload
*
* @staticvar boolean $exists
* @param string $str
* @param int $start
* @param int $length
* @return string
* @throws \TypeError
*/
public static function safeSubstr($str, $start = 0, $length = \null)
{
if (\function_exists('mb_substr')) {
// mb_substr($str, 0, null, '8bit') returns an empty string on PHP
// 5.3, so we have to find the length ourselves.
if (\is_null($length)) {
if ($start >= 0) {
$length = self::safeStrlen($str) - $start;
} else {
$length = -$start;
}
}
// $length calculation above might result in a 0-length string
if ($length === 0) {
return '';
}
return \mb_substr($str, $start, $length, '8bit');
}
if ($length === 0) {
return '';
}
// Unlike mb_substr(), substr() doesn't accept null for length
if (!\is_null($length)) {
return \substr($str, $start, $length);
} else {
return \substr($str, $start);
}
}
}

View File

@@ -0,0 +1,49 @@
<?php
namespace VendorDuplicator\ParagonIE\ConstantTime;
/**
* Copyright (c) 2016 - 2017 Paragon Initiative Enterprises.
* Copyright (c) 2014 Steve "Sc00bz" Thomas (steve at tobtu dot com)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* Interface EncoderInterface
* @package VendorDuplicator\ParagonIE\ConstantTime
*/
interface EncoderInterface
{
/**
* Convert a binary string into a hexadecimal string without cache-timing
* leaks
*
* @param string $bin_string (raw binary)
* @return string
*/
public static function encode($bin_string);
/**
* Convert a binary string into a hexadecimal string without cache-timing
* leaks
*
* @param string $encoded_string
* @return string (raw binary)
*/
public static function decode($encoded_string);
}

View File

@@ -0,0 +1,226 @@
<?php
namespace VendorDuplicator\ParagonIE\ConstantTime;
/**
* Copyright (c) 2016 - 2017 Paragon Initiative Enterprises.
* Copyright (c) 2014 Steve "Sc00bz" Thomas (steve at tobtu dot com)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* Class Encoding
* @package VendorDuplicator\ParagonIE\ConstantTime
*/
abstract class Encoding
{
/**
* RFC 4648 Base32 encoding
*
* @param string $str
* @return string
*/
public static function base32Encode($str)
{
return Base32::encode($str);
}
/**
* RFC 4648 Base32 encoding
*
* @param string $str
* @return string
*/
public static function base32EncodeUpper($str)
{
return Base32::encodeUpper($str);
}
/**
* RFC 4648 Base32 decoding
*
* @param string $str
* @return string
*/
public static function base32Decode($str)
{
return Base32::decode($str);
}
/**
* RFC 4648 Base32 decoding
*
* @param string $str
* @return string
*/
public static function base32DecodeUpper($str)
{
return Base32::decodeUpper($str);
}
/**
* RFC 4648 Base32 encoding
*
* @param string $str
* @return string
*/
public static function base32HexEncode($str)
{
return Base32Hex::encode($str);
}
/**
* RFC 4648 Base32 encoding
*
* @param string $str
* @return string
*/
public static function base32HexEncodeUpper($str)
{
return Base32Hex::encodeUpper($str);
}
/**
* RFC 4648 Base32 decoding
*
* @param string $str
* @return string
*/
public static function base32HexDecode($str)
{
return Base32Hex::decode($str);
}
/**
* RFC 4648 Base32 decoding
*
* @param string $str
* @return string
*/
public static function base32HexDecodeUpper($str)
{
return Base32Hex::decodeUpper($str);
}
/**
* RFC 4648 Base64 encoding
*
* @param string $str
* @return string
*/
public static function base64Encode($str)
{
return Base64::encode($str);
}
/**
* RFC 4648 Base32 decoding
*
* @param string $str
* @return string
*/
public static function base64Decode($str)
{
return Base64::decode($str);
}
/**
* Encode into Base64
*
* Base64 character set "./[A-Z][a-z][0-9]"
* @param string $src
* @return string
*/
public static function base64EncodeDotSlash($src)
{
return Base64DotSlash::encode($src);
}
/**
* Decode from base64 to raw binary
*
* Base64 character set "./[A-Z][a-z][0-9]"
*
* @param string $src
* @return string
* @throws \RangeException
*/
public static function base64DecodeDotSlash($src)
{
return Base64DotSlash::decode($src);
}
/**
* Encode into Base64
*
* Base64 character set "[.-9][A-Z][a-z]" or "./[0-9][A-Z][a-z]"
* @param string $src
* @return string
*/
public static function base64EncodeDotSlashOrdered($src)
{
return Base64DotSlashOrdered::encode($src);
}
/**
* Decode from base64 to raw binary
*
* Base64 character set "[.-9][A-Z][a-z]" or "./[0-9][A-Z][a-z]"
*
* @param string $src
* @return string
* @throws \RangeException
*/
public static function base64DecodeDotSlashOrdered($src)
{
return Base64DotSlashOrdered::decode($src);
}
/**
* Convert a binary string into a hexadecimal string without cache-timing
* leaks
*
* @param string $bin_string (raw binary)
* @return string
*/
public static function hexEncode($bin_string)
{
return Hex::encode($bin_string);
}
/**
* Convert a hexadecimal string into a binary string without cache-timing
* leaks
*
* @param string $hex_string
* @return string (raw binary)
* @throws \RangeException
*/
public static function hexDecode($hex_string)
{
return Hex::decode($hex_string);
}
/**
* Convert a binary string into a hexadecimal string without cache-timing
* leaks
*
* @param string $bin_string (raw binary)
* @return string
*/
public static function hexEncodeUpper($bin_string)
{
return Hex::encodeUpper($bin_string);
}
/**
* Convert a binary string into a hexadecimal string without cache-timing
* leaks
*
* @param string $bin_string (raw binary)
* @return string
*/
public static function hexDecodeUpper($bin_string)
{
return Hex::decode($bin_string);
}
}

View File

@@ -0,0 +1,110 @@
<?php
namespace VendorDuplicator\ParagonIE\ConstantTime;
/**
* Copyright (c) 2016 - 2017 Paragon Initiative Enterprises.
* Copyright (c) 2014 Steve "Sc00bz" Thomas (steve at tobtu dot com)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* Class Hex
* @package VendorDuplicator\ParagonIE\ConstantTime
*/
abstract class Hex implements EncoderInterface
{
/**
* Convert a binary string into a hexadecimal string without cache-timing
* leaks
*
* @param string $bin_string (raw binary)
* @return string
*/
public static function encode($bin_string)
{
$hex = '';
$len = Binary::safeStrlen($bin_string);
for ($i = 0; $i < $len; ++$i) {
$chunk = \unpack('C', Binary::safeSubstr($bin_string, $i, 2));
$c = $chunk[1] & 0xf;
$b = $chunk[1] >> 4;
$hex .= \pack('CC', 87 + $b + ($b - 10 >> 8 & ~38), 87 + $c + ($c - 10 >> 8 & ~38));
}
return $hex;
}
/**
* Convert a binary string into a hexadecimal string without cache-timing
* leaks, returning uppercase letters (as per RFC 4648)
*
* @param string $bin_string (raw binary)
* @return string
*/
public static function encodeUpper($bin_string)
{
$hex = '';
$len = Binary::safeStrlen($bin_string);
for ($i = 0; $i < $len; ++$i) {
$chunk = \unpack('C', Binary::safeSubstr($bin_string, $i, 2));
$c = $chunk[1] & 0xf;
$b = $chunk[1] >> 4;
$hex .= \pack('CC', 55 + $b + ($b - 10 >> 8 & ~6), 55 + $c + ($c - 10 >> 8 & ~6));
}
return $hex;
}
/**
* Convert a hexadecimal string into a binary string without cache-timing
* leaks
*
* @param string $encoded_string
* @return string (raw binary)
* @throws \RangeException
*/
public static function decode($encoded_string)
{
$hex_pos = 0;
$bin = '';
$c_acc = 0;
$hex_len = Binary::safeStrlen($encoded_string);
$state = 0;
if (($hex_len & 1) !== 0) {
throw new \RangeException('Expected an even number of hexadecimal characters');
}
$chunk = \unpack('C*', $encoded_string);
while ($hex_pos < $hex_len) {
++$hex_pos;
$c = $chunk[$hex_pos];
$c_num = $c ^ 48;
$c_num0 = $c_num - 10 >> 8;
$c_alpha = ($c & ~32) - 55;
$c_alpha0 = ($c_alpha - 10 ^ $c_alpha - 16) >> 8;
if (($c_num0 | $c_alpha0) === 0) {
throw new \RangeException('hexEncode() only expects hexadecimal characters');
}
$c_val = $c_num0 & $c_num | $c_alpha & $c_alpha0;
if ($state === 0) {
$c_acc = $c_val * 16;
} else {
$bin .= \pack('C', $c_acc | $c_val);
}
$state ^= 1;
}
return $bin;
}
}

View File

@@ -0,0 +1,156 @@
<?php
namespace VendorDuplicator\ParagonIE\ConstantTime;
/**
* Copyright (c) 2016 - 2017 Paragon Initiative Enterprises.
* Copyright (c) 2014 Steve "Sc00bz" Thomas (steve at tobtu dot com)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* Class RFC4648
*
* This class conforms strictly to the RFC
*
* @package VendorDuplicator\ParagonIE\ConstantTime
*/
abstract class RFC4648
{
/**
* RFC 4648 Base64 encoding
*
* "foo" -> "Zm9v"
*
* @param string $str
* @return string
*/
public function base64Encode($str)
{
return Base64::encode($str);
}
/**
* RFC 4648 Base64 decoding
*
* "Zm9v" -> "foo"
*
* @param string $str
* @return string
*/
public function base64Decode($str)
{
return Base64::decode($str);
}
/**
* RFC 4648 Base64 (URL Safe) encoding
*
* "foo" -> "Zm9v"
*
* @param string $str
* @return string
*/
public function base64UrlSafeEncode($str)
{
return Base64UrlSafe::encode($str);
}
/**
* RFC 4648 Base64 (URL Safe) decoding
*
* "Zm9v" -> "foo"
*
* @param string $str
* @return string
*/
public function base64UrlSafeDecode($str)
{
return Base64UrlSafe::decode($str);
}
/**
* RFC 4648 Base32 encoding
*
* "foo" -> "MZXW6==="
*
* @param string $str
* @return string
*/
public function base32Encode($str)
{
return Base32::encodeUpper($str);
}
/**
* RFC 4648 Base32 encoding
*
* "MZXW6===" -> "foo"
*
* @param string $str
* @return string
*/
public function base32Decode($str)
{
return Base32::decodeUpper($str);
}
/**
* RFC 4648 Base32-Hex encoding
*
* "foo" -> "CPNMU==="
*
* @param string $str
* @return string
*/
public function base32HexEncode($str)
{
return Base32::encodeUpper($str);
}
/**
* RFC 4648 Base32-Hex decoding
*
* "CPNMU===" -> "foo"
*
* @param string $str
* @return string
*/
public function base32HexDecode($str)
{
return Base32::decodeUpper($str);
}
/**
* RFC 4648 Base16 decoding
*
* "foo" -> "666F6F"
*
* @param string $str
* @return string
*/
public function base16Encode($str)
{
return Hex::encodeUpper($str);
}
/**
* RFC 4648 Base16 decoding
*
* "666F6F" -> "foo"
*
* @param string $str
* @return string
*/
public function base16Decode($str)
{
return Hex::decode($str);
}
}

View File

@@ -0,0 +1,5 @@
-----BEGIN PUBLIC KEY-----
MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEEd+wCqJDrx5B4OldM0dQE0ZMX+lx1ZWm
pui0SUqD4G29L3NGsz9UhJ/0HjBdbnkhIK5xviT0X5vtjacF6ajgcCArbTB+ds+p
+h7Q084NuSuIpNb6YPfoUFgC/CL9kAoc
-----END PUBLIC KEY-----

View File

@@ -0,0 +1,11 @@
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.22 (MingW32)
iQEcBAABAgAGBQJWtW1hAAoJEGuXocKCZATaJf0H+wbZGgskK1dcRTsuVJl9IWip
QwGw/qIKI280SD6/ckoUMxKDCJiFuPR14zmqnS36k7N5UNPnpdTJTS8T11jttSpg
1LCmgpbEIpgaTah+cELDqFCav99fS+bEiAL5lWDAHBTE/XPjGVCqeehyPYref4IW
NDBIEsvnHPHPLsn6X5jq4+Yj5oUixgxaMPiR+bcO4Sh+RzOVB6i2D0upWfRXBFXA
NNnsg9/zjvoC7ZW73y9uSH+dPJTt/Vgfeiv52/v41XliyzbUyLalf02GNPY+9goV
JHG1ulEEBJOCiUD9cE1PUIJwHA/HqyhHIvV350YoEFiHl8iSwm7SiZu5kPjaq74=
=B6+8
-----END PGP SIGNATURE-----

View File

@@ -0,0 +1,147 @@
<?php
namespace VendorDuplicator;
/**
* Random_* Compatibility Library
* for using the new PHP 7 random_* API in PHP 5 projects
*
* The MIT License (MIT)
*
* Copyright (c) 2015 - 2018 Paragon Initiative Enterprises
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
if (!\is_callable('VendorDuplicator\\RandomCompat_strlen')) {
if (\defined('MB_OVERLOAD_STRING') && (int) \ini_get('mbstring.func_overload') & \MB_OVERLOAD_STRING) {
/**
* strlen() implementation that isn't brittle to mbstring.func_overload
*
* This version uses mb_strlen() in '8bit' mode to treat strings as raw
* binary rather than UTF-8, ISO-8859-1, etc
*
* @param string $binary_string
*
* @throws TypeError
*
* @return int
*/
function RandomCompat_strlen($binary_string)
{
if (!\is_string($binary_string)) {
throw new \TypeError('RandomCompat_strlen() expects a string');
}
return (int) \mb_strlen($binary_string, '8bit');
}
} else {
/**
* strlen() implementation that isn't brittle to mbstring.func_overload
*
* This version just used the default strlen()
*
* @param string $binary_string
*
* @throws TypeError
*
* @return int
*/
function RandomCompat_strlen($binary_string)
{
if (!\is_string($binary_string)) {
throw new \TypeError('RandomCompat_strlen() expects a string');
}
return (int) \strlen($binary_string);
}
}
}
if (!\is_callable('VendorDuplicator\\RandomCompat_substr')) {
if (\defined('MB_OVERLOAD_STRING') && (int) \ini_get('mbstring.func_overload') & \MB_OVERLOAD_STRING) {
/**
* substr() implementation that isn't brittle to mbstring.func_overload
*
* This version uses mb_substr() in '8bit' mode to treat strings as raw
* binary rather than UTF-8, ISO-8859-1, etc
*
* @param string $binary_string
* @param int $start
* @param int|null $length (optional)
*
* @throws TypeError
*
* @return string
*/
function RandomCompat_substr($binary_string, $start, $length = null)
{
if (!\is_string($binary_string)) {
throw new \TypeError('RandomCompat_substr(): First argument should be a string');
}
if (!\is_int($start)) {
throw new \TypeError('RandomCompat_substr(): Second argument should be an integer');
}
if ($length === null) {
/**
* mb_substr($str, 0, NULL, '8bit') returns an empty string on
* PHP 5.3, so we have to find the length ourselves.
*/
/** @var int $length */
$length = RandomCompat_strlen($binary_string) - $start;
} elseif (!\is_int($length)) {
throw new \TypeError('RandomCompat_substr(): Third argument should be an integer, or omitted');
}
// Consistency with PHP's behavior
if ($start === RandomCompat_strlen($binary_string) && $length === 0) {
return '';
}
if ($start > RandomCompat_strlen($binary_string)) {
return '';
}
return (string) \mb_substr((string) $binary_string, (int) $start, (int) $length, '8bit');
}
} else {
/**
* substr() implementation that isn't brittle to mbstring.func_overload
*
* This version just uses the default substr()
*
* @param string $binary_string
* @param int $start
* @param int|null $length (optional)
*
* @throws TypeError
*
* @return string
*/
function RandomCompat_substr($binary_string, $start, $length = null)
{
if (!\is_string($binary_string)) {
throw new \TypeError('RandomCompat_substr(): First argument should be a string');
}
if (!\is_int($start)) {
throw new \TypeError('RandomCompat_substr(): Second argument should be an integer');
}
if ($length !== null) {
if (!\is_int($length)) {
throw new \TypeError('RandomCompat_substr(): Third argument should be an integer, or omitted');
}
return (string) \substr((string) $binary_string, (int) $start, (int) $length);
}
return (string) \substr((string) $binary_string, (int) $start);
}
}
}

View File

@@ -0,0 +1,68 @@
<?php
namespace VendorDuplicator;
/**
* Random_* Compatibility Library
* for using the new PHP 7 random_* API in PHP 5 projects
*
* The MIT License (MIT)
*
* Copyright (c) 2015 - 2018 Paragon Initiative Enterprises
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
if (!\is_callable('VendorDuplicator\\RandomCompat_intval')) {
/**
* Cast to an integer if we can, safely.
*
* If you pass it a float in the range (~PHP_INT_MAX, PHP_INT_MAX)
* (non-inclusive), it will sanely cast it to an int. If you it's equal to
* ~PHP_INT_MAX or PHP_INT_MAX, we let it fail as not an integer. Floats
* lose precision, so the <= and => operators might accidentally let a float
* through.
*
* @param int|float $number The number we want to convert to an int
* @param bool $fail_open Set to true to not throw an exception
*
* @return float|int
* @psalm-suppress InvalidReturnType
*
* @throws TypeError
*/
function RandomCompat_intval($number, $fail_open = \false)
{
if (\is_int($number) || \is_float($number)) {
$number += 0;
} elseif (\is_numeric($number)) {
/** @psalm-suppress InvalidOperand */
$number += 0;
}
/** @var int|float $number */
if (\is_float($number) && $number > ~\PHP_INT_MAX && $number < \PHP_INT_MAX) {
$number = (int) $number;
}
if (\is_int($number)) {
return (int) $number;
} elseif (!$fail_open) {
throw new \TypeError('Expected an integer.');
}
return $number;
}
}

View File

@@ -0,0 +1,47 @@
<?php
namespace VendorDuplicator;
/**
* Random_* Compatibility Library
* for using the new PHP 7 random_* API in PHP 5 projects
*
* The MIT License (MIT)
*
* Copyright (c) 2015 - 2018 Paragon Initiative Enterprises
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
if (!\class_exists('Error', \false)) {
// We can't really avoid making this extend Exception in PHP 5.
class Error extends \Exception
{
}
}
if (!\class_exists('TypeError', \false)) {
if (\is_subclass_of('Error', 'Exception')) {
class TypeError extends \Error
{
}
} else {
class TypeError extends \Exception
{
}
}
}

View File

@@ -0,0 +1,172 @@
<?php
namespace VendorDuplicator;
/**
* Random_* Compatibility Library
* for using the new PHP 7 random_* API in PHP 5 projects
*
* @version 2.0.17
* @released 2018-07-04
*
* The MIT License (MIT)
*
* Copyright (c) 2015 - 2018 Paragon Initiative Enterprises
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
if (!\defined('PHP_VERSION_ID')) {
// This constant was introduced in PHP 5.2.7
$RandomCompatversion = \array_map('intval', \explode('.', \PHP_VERSION));
\define('PHP_VERSION_ID', $RandomCompatversion[0] * 10000 + $RandomCompatversion[1] * 100 + $RandomCompatversion[2]);
$RandomCompatversion = null;
}
/**
* PHP 7.0.0 and newer have these functions natively.
*/
if (\PHP_VERSION_ID >= 70000) {
return;
}
if (!\defined('RANDOM_COMPAT_READ_BUFFER')) {
\define('RANDOM_COMPAT_READ_BUFFER', 8);
}
$RandomCompatDIR = \dirname(__FILE__);
require_once $RandomCompatDIR . \DIRECTORY_SEPARATOR . 'byte_safe_strings.php';
require_once $RandomCompatDIR . \DIRECTORY_SEPARATOR . 'cast_to_int.php';
require_once $RandomCompatDIR . \DIRECTORY_SEPARATOR . 'error_polyfill.php';
if (!\is_callable('VendorDuplicator\\random_bytes')) {
/**
* PHP 5.2.0 - 5.6.x way to implement random_bytes()
*
* We use conditional statements here to define the function in accordance
* to the operating environment. It's a micro-optimization.
*
* In order of preference:
* 1. Use libsodium if available.
* 2. fread() /dev/urandom if available (never on Windows)
* 3. mcrypt_create_iv($bytes, MCRYPT_DEV_URANDOM)
* 4. COM('CAPICOM.Utilities.1')->GetRandom()
*
* See RATIONALE.md for our reasoning behind this particular order
*/
if (\extension_loaded('libsodium')) {
// See random_bytes_libsodium.php
if (\PHP_VERSION_ID >= 50300 && \is_callable('VendorDuplicator\\Sodium\\randombytes_buf')) {
require_once $RandomCompatDIR . \DIRECTORY_SEPARATOR . 'random_bytes_libsodium.php';
} elseif (\method_exists('Sodium', 'randombytes_buf')) {
require_once $RandomCompatDIR . \DIRECTORY_SEPARATOR . 'random_bytes_libsodium_legacy.php';
}
}
/**
* Reading directly from /dev/urandom:
*/
if (\DIRECTORY_SEPARATOR === '/') {
// DIRECTORY_SEPARATOR === '/' on Unix-like OSes -- this is a fast
// way to exclude Windows.
$RandomCompatUrandom = \true;
$RandomCompat_basedir = \ini_get('open_basedir');
if (!empty($RandomCompat_basedir)) {
$RandomCompat_open_basedir = \explode(\PATH_SEPARATOR, \strtolower($RandomCompat_basedir));
$RandomCompatUrandom = array() !== \array_intersect(array('/dev', '/dev/', '/dev/urandom'), $RandomCompat_open_basedir);
$RandomCompat_open_basedir = null;
}
if (!\is_callable('VendorDuplicator\\random_bytes') && $RandomCompatUrandom && @\is_readable('/dev/urandom')) {
// Error suppression on is_readable() in case of an open_basedir
// or safe_mode failure. All we care about is whether or not we
// can read it at this point. If the PHP environment is going to
// panic over trying to see if the file can be read in the first
// place, that is not helpful to us here.
// See random_bytes_dev_urandom.php
require_once $RandomCompatDIR . \DIRECTORY_SEPARATOR . 'random_bytes_dev_urandom.php';
}
// Unset variables after use
$RandomCompat_basedir = null;
} else {
$RandomCompatUrandom = \false;
}
/**
* mcrypt_create_iv()
*
* We only want to use mcypt_create_iv() if:
*
* - random_bytes() hasn't already been defined
* - the mcrypt extensions is loaded
* - One of these two conditions is true:
* - We're on Windows (DIRECTORY_SEPARATOR !== '/')
* - We're not on Windows and /dev/urandom is readabale
* (i.e. we're not in a chroot jail)
* - Special case:
* - If we're not on Windows, but the PHP version is between
* 5.6.10 and 5.6.12, we don't want to use mcrypt. It will
* hang indefinitely. This is bad.
* - If we're on Windows, we want to use PHP >= 5.3.7 or else
* we get insufficient entropy errors.
*/
if (!\is_callable('VendorDuplicator\\random_bytes') && (\DIRECTORY_SEPARATOR === '/' || \PHP_VERSION_ID >= 50307) && (\DIRECTORY_SEPARATOR !== '/' || (\PHP_VERSION_ID <= 50609 || \PHP_VERSION_ID >= 50613)) && \extension_loaded('mcrypt')) {
// See random_bytes_mcrypt.php
require_once $RandomCompatDIR . \DIRECTORY_SEPARATOR . 'random_bytes_mcrypt.php';
}
$RandomCompatUrandom = null;
/**
* This is a Windows-specific fallback, for when the mcrypt extension
* isn't loaded.
*/
if (!\is_callable('VendorDuplicator\\random_bytes') && \extension_loaded('com_dotnet') && \class_exists('COM')) {
$RandomCompat_disabled_classes = \preg_split('#\\s*,\\s*#', \strtolower(\ini_get('disable_classes')));
if (!\in_array('com', $RandomCompat_disabled_classes)) {
try {
$RandomCompatCOMtest = new \COM('CAPICOM.Utilities.1');
/** @psalm-suppress TypeDoesNotContainType */
if (\is_callable(array($RandomCompatCOMtest, 'GetRandom'))) {
// See random_bytes_com_dotnet.php
require_once $RandomCompatDIR . \DIRECTORY_SEPARATOR . 'random_bytes_com_dotnet.php';
}
} catch (\com_exception $e) {
// Don't try to use it.
}
}
$RandomCompat_disabled_classes = null;
$RandomCompatCOMtest = null;
}
/**
* throw new Exception
*/
if (!\is_callable('VendorDuplicator\\random_bytes')) {
/**
* We don't have any more options, so let's throw an exception right now
* and hope the developer won't let it fail silently.
*
* @param mixed $length
* @psalm-suppress InvalidReturnType
* @throws Exception
* @return string
*/
function random_bytes($length)
{
unset($length);
// Suppress "variable not used" warnings.
throw new \Exception('There is no suitable CSPRNG installed on your system');
return '';
}
}
}
if (!\is_callable('VendorDuplicator\\random_int')) {
require_once $RandomCompatDIR . \DIRECTORY_SEPARATOR . 'random_int.php';
}
$RandomCompatDIR = null;

View File

@@ -0,0 +1,81 @@
<?php
namespace VendorDuplicator;
/**
* Random_* Compatibility Library
* for using the new PHP 7 random_* API in PHP 5 projects
*
* The MIT License (MIT)
*
* Copyright (c) 2015 - 2018 Paragon Initiative Enterprises
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
if (!\is_callable('VendorDuplicator\\random_bytes')) {
/**
* Windows with PHP < 5.3.0 will not have the function
* openssl_random_pseudo_bytes() available, so let's use
* CAPICOM to work around this deficiency.
*
* @param int $bytes
*
* @throws Exception
*
* @return string
*/
function random_bytes($bytes)
{
try {
/** @var int $bytes */
$bytes = RandomCompat_intval($bytes);
} catch (\TypeError $ex) {
throw new \TypeError('random_bytes(): $bytes must be an integer');
}
if ($bytes < 1) {
throw new \Error('Length must be greater than 0');
}
/** @var string $buf */
$buf = '';
if (!\class_exists('COM')) {
throw new \Error('COM does not exist');
}
/** @var COM $util */
$util = new \COM('CAPICOM.Utilities.1');
$execCount = 0;
/**
* Let's not let it loop forever. If we run N times and fail to
* get N bytes of random data, then CAPICOM has failed us.
*/
do {
$buf .= \base64_decode((string) $util->GetRandom($bytes, 0));
if (RandomCompat_strlen($buf) >= $bytes) {
/**
* Return our random entropy buffer here:
*/
return (string) RandomCompat_substr($buf, 0, $bytes);
}
++$execCount;
} while ($execCount < $bytes);
/**
* If we reach here, PHP has failed us.
*/
throw new \Exception('Could not gather sufficient random data');
}
}

View File

@@ -0,0 +1,173 @@
<?php
namespace VendorDuplicator;
/**
* Random_* Compatibility Library
* for using the new PHP 7 random_* API in PHP 5 projects
*
* The MIT License (MIT)
*
* Copyright (c) 2015 - 2018 Paragon Initiative Enterprises
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
if (!\defined('RANDOM_COMPAT_READ_BUFFER')) {
\define('RANDOM_COMPAT_READ_BUFFER', 8);
}
if (!\is_callable('VendorDuplicator\\random_bytes')) {
/**
* Unless open_basedir is enabled, use /dev/urandom for
* random numbers in accordance with best practices
*
* Why we use /dev/urandom and not /dev/random
* @ref https://www.2uo.de/myths-about-urandom
* @ref http://sockpuppet.org/blog/2014/02/25/safely-generate-random-numbers
*
* @param int $bytes
*
* @throws Exception
*
* @return string
*/
function random_bytes($bytes)
{
/** @var resource $fp */
static $fp = null;
/**
* This block should only be run once
*/
if (empty($fp)) {
/**
* We don't want to ever read C:\dev\random, only /dev/urandom on
* Unix-like operating systems. While we guard against this
* condition in random.php, it doesn't hurt to be defensive in depth
* here.
*
* To that end, we only try to open /dev/urandom if we're on a Unix-
* like operating system (which means the directory separator is set
* to "/" not "\".
*/
if (\DIRECTORY_SEPARATOR === '/') {
if (!\is_readable('/dev/urandom')) {
throw new \Exception('Environment misconfiguration: ' . '/dev/urandom cannot be read.');
}
/**
* We use /dev/urandom if it is a char device.
* We never fall back to /dev/random
*/
/** @var resource|bool $fp */
$fp = \fopen('/dev/urandom', 'rb');
if (\is_resource($fp)) {
/** @var array<string, int> $st */
$st = \fstat($fp);
if (($st['mode'] & 0170000) !== 020000) {
\fclose($fp);
$fp = \false;
}
}
}
if (\is_resource($fp)) {
/**
* stream_set_read_buffer() does not exist in HHVM
*
* If we don't set the stream's read buffer to 0, PHP will
* internally buffer 8192 bytes, which can waste entropy
*
* stream_set_read_buffer returns 0 on success
*/
if (\is_callable('VendorDuplicator\\stream_set_read_buffer')) {
\stream_set_read_buffer($fp, \RANDOM_COMPAT_READ_BUFFER);
}
if (\is_callable('VendorDuplicator\\stream_set_chunk_size')) {
\stream_set_chunk_size($fp, \RANDOM_COMPAT_READ_BUFFER);
}
}
}
try {
/** @var int $bytes */
$bytes = RandomCompat_intval($bytes);
} catch (\TypeError $ex) {
throw new \TypeError('random_bytes(): $bytes must be an integer');
}
if ($bytes < 1) {
throw new \Error('Length must be greater than 0');
}
/**
* This if() block only runs if we managed to open a file handle
*
* It does not belong in an else {} block, because the above
* if (empty($fp)) line is logic that should only be run once per
* page load.
*/
if (\is_resource($fp)) {
/**
* @var int
*/
$remaining = $bytes;
/**
* @var string|bool
*/
$buf = '';
/**
* We use fread() in a loop to protect against partial reads
*/
do {
/**
* @var string|bool
*/
$read = \fread($fp, $remaining);
if (!\is_string($read)) {
/**
* We cannot safely read from the file. Exit the
* do-while loop and trigger the exception condition
*
* @var string|bool
*/
$buf = \false;
break;
}
/**
* Decrease the number of bytes returned from remaining
*/
$remaining -= RandomCompat_strlen($read);
/**
* @var string $buf
*/
$buf .= $read;
} while ($remaining > 0);
/**
* Is our result valid?
* @var string|bool $buf
*/
if (\is_string($buf)) {
if (RandomCompat_strlen($buf) === $bytes) {
/**
* Return our random entropy buffer here:
*/
return $buf;
}
}
}
/**
* If we reach here, PHP has failed us.
*/
throw new \Exception('Error reading from source device');
}
}

View File

@@ -0,0 +1,81 @@
<?php
namespace VendorDuplicator;
/**
* Random_* Compatibility Library
* for using the new PHP 7 random_* API in PHP 5 projects
*
* The MIT License (MIT)
*
* Copyright (c) 2015 - 2018 Paragon Initiative Enterprises
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
if (!\is_callable('VendorDuplicator\\random_bytes')) {
/**
* If the libsodium PHP extension is loaded, we'll use it above any other
* solution.
*
* libsodium-php project:
* @ref https://github.com/jedisct1/libsodium-php
*
* @param int $bytes
*
* @throws Exception
*
* @return string
*/
function random_bytes($bytes)
{
try {
/** @var int $bytes */
$bytes = RandomCompat_intval($bytes);
} catch (\TypeError $ex) {
throw new \TypeError('random_bytes(): $bytes must be an integer');
}
if ($bytes < 1) {
throw new \Error('Length must be greater than 0');
}
/**
* \Sodium\randombytes_buf() doesn't allow more than 2147483647 bytes to be
* generated in one invocation.
*/
/** @var string|bool $buf */
if ($bytes > 2147483647) {
$buf = '';
for ($i = 0; $i < $bytes; $i += 1073741824) {
$n = $bytes - $i > 1073741824 ? 1073741824 : $bytes - $i;
$buf .= \Sodium\randombytes_buf($n);
}
} else {
/** @var string|bool $buf */
$buf = \Sodium\randombytes_buf($bytes);
}
if (\is_string($buf)) {
if (RandomCompat_strlen($buf) === $bytes) {
return $buf;
}
}
/**
* If we reach here, PHP has failed us.
*/
throw new \Exception('Could not gather sufficient random data');
}
}

View File

@@ -0,0 +1,82 @@
<?php
namespace VendorDuplicator;
/**
* Random_* Compatibility Library
* for using the new PHP 7 random_* API in PHP 5 projects
*
* The MIT License (MIT)
*
* Copyright (c) 2015 - 2018 Paragon Initiative Enterprises
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
if (!\is_callable('VendorDuplicator\\random_bytes')) {
/**
* If the libsodium PHP extension is loaded, we'll use it above any other
* solution.
*
* libsodium-php project:
* @ref https://github.com/jedisct1/libsodium-php
*
* @param int $bytes
*
* @throws Exception
*
* @return string
*/
function random_bytes($bytes)
{
try {
/** @var int $bytes */
$bytes = RandomCompat_intval($bytes);
} catch (\TypeError $ex) {
throw new \TypeError('random_bytes(): $bytes must be an integer');
}
if ($bytes < 1) {
throw new \Error('Length must be greater than 0');
}
/**
* @var string
*/
$buf = '';
/**
* \Sodium\randombytes_buf() doesn't allow more than 2147483647 bytes to be
* generated in one invocation.
*/
if ($bytes > 2147483647) {
for ($i = 0; $i < $bytes; $i += 1073741824) {
$n = $bytes - $i > 1073741824 ? 1073741824 : $bytes - $i;
$buf .= Sodium::randombytes_buf((int) $n);
}
} else {
$buf .= Sodium::randombytes_buf((int) $bytes);
}
if (\is_string($buf)) {
if (RandomCompat_strlen($buf) === $bytes) {
return $buf;
}
}
/**
* If we reach here, PHP has failed us.
*/
throw new \Exception('Could not gather sufficient random data');
}
}

View File

@@ -0,0 +1,68 @@
<?php
namespace VendorDuplicator;
/**
* Random_* Compatibility Library
* for using the new PHP 7 random_* API in PHP 5 projects
*
* The MIT License (MIT)
*
* Copyright (c) 2015 - 2018 Paragon Initiative Enterprises
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
if (!\is_callable('VendorDuplicator\\random_bytes')) {
/**
* Powered by ext/mcrypt (and thankfully NOT libmcrypt)
*
* @ref https://bugs.php.net/bug.php?id=55169
* @ref https://github.com/php/php-src/blob/c568ffe5171d942161fc8dda066bce844bdef676/ext/mcrypt/mcrypt.c#L1321-L1386
*
* @param int $bytes
*
* @throws Exception
*
* @return string
*/
function random_bytes($bytes)
{
try {
/** @var int $bytes */
$bytes = RandomCompat_intval($bytes);
} catch (\TypeError $ex) {
throw new \TypeError('random_bytes(): $bytes must be an integer');
}
if ($bytes < 1) {
throw new \Error('Length must be greater than 0');
}
/** @var string|bool $buf */
$buf = @\mcrypt_create_iv((int) $bytes, (int) \MCRYPT_DEV_URANDOM);
if (\is_string($buf) && RandomCompat_strlen($buf) === $bytes) {
/**
* Return our random entropy buffer here:
*/
return $buf;
}
/**
* If we reach here, PHP has failed us.
*/
throw new \Exception('Could not gather sufficient random data');
}
}

View File

@@ -0,0 +1,181 @@
<?php
namespace VendorDuplicator;
if (!\is_callable('VendorDuplicator\\random_int')) {
/**
* Random_* Compatibility Library
* for using the new PHP 7 random_* API in PHP 5 projects
*
* The MIT License (MIT)
*
* Copyright (c) 2015 - 2018 Paragon Initiative Enterprises
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* Fetch a random integer between $min and $max inclusive
*
* @param int $min
* @param int $max
*
* @throws Exception
*
* @return int
*/
function random_int($min, $max)
{
/**
* Type and input logic checks
*
* If you pass it a float in the range (~PHP_INT_MAX, PHP_INT_MAX)
* (non-inclusive), it will sanely cast it to an int. If you it's equal to
* ~PHP_INT_MAX or PHP_INT_MAX, we let it fail as not an integer. Floats
* lose precision, so the <= and => operators might accidentally let a float
* through.
*/
try {
/** @var int $min */
$min = RandomCompat_intval($min);
} catch (\TypeError $ex) {
throw new \TypeError('random_int(): $min must be an integer');
}
try {
/** @var int $max */
$max = RandomCompat_intval($max);
} catch (\TypeError $ex) {
throw new \TypeError('random_int(): $max must be an integer');
}
/**
* Now that we've verified our weak typing system has given us an integer,
* let's validate the logic then we can move forward with generating random
* integers along a given range.
*/
if ($min > $max) {
throw new \Error('Minimum value must be less than or equal to the maximum value');
}
if ($max === $min) {
return (int) $min;
}
/**
* Initialize variables to 0
*
* We want to store:
* $bytes => the number of random bytes we need
* $mask => an integer bitmask (for use with the &) operator
* so we can minimize the number of discards
*/
$attempts = $bits = $bytes = $mask = $valueShift = 0;
/** @var int $attempts */
/** @var int $bits */
/** @var int $bytes */
/** @var int $mask */
/** @var int $valueShift */
/**
* At this point, $range is a positive number greater than 0. It might
* overflow, however, if $max - $min > PHP_INT_MAX. PHP will cast it to
* a float and we will lose some precision.
*
* @var int|float $range
*/
$range = $max - $min;
/**
* Test for integer overflow:
*/
if (!\is_int($range)) {
/**
* Still safely calculate wider ranges.
* Provided by @CodesInChaos, @oittaa
*
* @ref https://gist.github.com/CodesInChaos/03f9ea0b58e8b2b8d435
*
* We use ~0 as a mask in this case because it generates all 1s
*
* @ref https://eval.in/400356 (32-bit)
* @ref http://3v4l.org/XX9r5 (64-bit)
*/
$bytes = \PHP_INT_SIZE;
/** @var int $mask */
$mask = ~0;
} else {
/**
* $bits is effectively ceil(log($range, 2)) without dealing with
* type juggling
*/
while ($range > 0) {
if ($bits % 8 === 0) {
++$bytes;
}
++$bits;
$range >>= 1;
/** @var int $mask */
$mask = $mask << 1 | 1;
}
$valueShift = $min;
}
/** @var int $val */
$val = 0;
/**
* Now that we have our parameters set up, let's begin generating
* random integers until one falls between $min and $max
*/
/** @psalm-suppress RedundantCondition */
do {
/**
* The rejection probability is at most 0.5, so this corresponds
* to a failure probability of 2^-128 for a working RNG
*/
if ($attempts > 128) {
throw new \Exception('random_int: RNG is broken - too many rejections');
}
/**
* Let's grab the necessary number of random bytes
*/
$randomByteString = \random_bytes($bytes);
/**
* Let's turn $randomByteString into an integer
*
* This uses bitwise operators (<< and |) to build an integer
* out of the values extracted from ord()
*
* Example: [9F] | [6D] | [32] | [0C] =>
* 159 + 27904 + 3276800 + 201326592 =>
* 204631455
*/
$val &= 0;
for ($i = 0; $i < $bytes; ++$i) {
$val |= \ord($randomByteString[$i]) << $i * 8;
}
/** @var int $val */
/**
* Apply mask
*/
$val &= $mask;
$val += $valueShift;
++$attempts;
/**
* If $val overflows to a floating point number,
* ... or is larger than $max,
* ... or smaller than $min,
* then try again.
*/
} while (!\is_int($val) || $val > $max || $val < $min);
return (int) $val;
}
}

View File

@@ -0,0 +1,7 @@
phpseclib Lead Developer: TerraFrost (Jim Wigginton)
phpseclib Developers: monnerat (Patrick Monnerat)
bantu (Andreas Fischer)
petrich (Hans-Jürgen Petrich)
GrahamCampbell (Graham Campbell)
hc-jworman

View File

@@ -0,0 +1,454 @@
<?php
/**
* Common String Functions
*
* PHP version 5
*
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2016 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net
*/
namespace VendorDuplicator\phpseclib3\Common\Functions;
use VendorDuplicator\ParagonIE\ConstantTime\Base64;
use VendorDuplicator\ParagonIE\ConstantTime\Base64UrlSafe;
use VendorDuplicator\ParagonIE\ConstantTime\Hex;
use VendorDuplicator\phpseclib3\Math\BigInteger;
use VendorDuplicator\phpseclib3\Math\Common\FiniteField;
/**
* Common String Functions
*
* @author Jim Wigginton <terrafrost@php.net>
*/
abstract class Strings
{
/**
* String Shift
*
* Inspired by array_shift
*
* @param string $string
* @param int $index
* @return string
*/
public static function shift(&$string, $index = 1)
{
$substr = \substr($string, 0, $index);
$string = \substr($string, $index);
return $substr;
}
/**
* String Pop
*
* Inspired by array_pop
*
* @param string $string
* @param int $index
* @return string
*/
public static function pop(&$string, $index = 1)
{
$substr = \substr($string, -$index);
$string = \substr($string, 0, -$index);
return $substr;
}
/**
* Parse SSH2-style string
*
* Returns either an array or a boolean if $data is malformed.
*
* Valid characters for $format are as follows:
*
* C = byte
* b = boolean (true/false)
* N = uint32
* Q = uint64
* s = string
* i = mpint
* L = name-list
*
* uint64 is not supported.
*
* @param string $format
* @param string $data
* @return mixed
*/
public static function unpackSSH2($format, &$data)
{
$format = self::formatPack($format);
$result = [];
for ($i = 0; $i < \strlen($format); $i++) {
switch ($format[$i]) {
case 'C':
case 'b':
if (!\strlen($data)) {
throw new \LengthException('At least one byte needs to be present for successful C / b decodes');
}
break;
case 'N':
case 'i':
case 's':
case 'L':
if (\strlen($data) < 4) {
throw new \LengthException('At least four byte needs to be present for successful N / i / s / L decodes');
}
break;
case 'Q':
if (\strlen($data) < 8) {
throw new \LengthException('At least eight byte needs to be present for successful N / i / s / L decodes');
}
break;
default:
throw new \InvalidArgumentException('$format contains an invalid character');
}
switch ($format[$i]) {
case 'C':
$result[] = \ord(self::shift($data));
continue 2;
case 'b':
$result[] = \ord(self::shift($data)) != 0;
continue 2;
case 'N':
list(, $temp) = \unpack('N', self::shift($data, 4));
$result[] = $temp;
continue 2;
case 'Q':
// pack() added support for Q in PHP 5.6.3 and PHP 5.6 is phpseclib 3's minimum version
// so in theory we could support this BUT, "64-bit format codes are not available for
// 32-bit versions" and phpseclib works on 32-bit installs. on 32-bit installs
// 64-bit floats can be used to get larger numbers then 32-bit signed ints would allow
// for. sure, you're not gonna get the full precision of 64-bit numbers but just because
// you need > 32-bit precision doesn't mean you need the full 64-bit precision
\extract(\unpack('Nupper/Nlower', self::shift($data, 8)));
$temp = $upper ? 4294967296 * $upper : 0;
$temp += $lower < 0 ? ($lower & 0x7ffffffff) + 0x80000000 : $lower;
// $temp = hexdec(bin2hex(self::shift($data, 8)));
$result[] = $temp;
continue 2;
}
list(, $length) = \unpack('N', self::shift($data, 4));
if (\strlen($data) < $length) {
throw new \LengthException("{$length} bytes needed; " . \strlen($data) . ' bytes available');
}
$temp = self::shift($data, $length);
switch ($format[$i]) {
case 'i':
$result[] = new BigInteger($temp, -256);
break;
case 's':
$result[] = $temp;
break;
case 'L':
$result[] = \explode(',', $temp);
}
}
return $result;
}
/**
* Create SSH2-style string
*
* @param string $format
* @param string|int|float|array|bool ...$elements
* @return string
*/
public static function packSSH2($format, ...$elements)
{
$format = self::formatPack($format);
if (\strlen($format) != \count($elements)) {
throw new \InvalidArgumentException('There must be as many arguments as there are characters in the $format string');
}
$result = '';
for ($i = 0; $i < \strlen($format); $i++) {
$element = $elements[$i];
switch ($format[$i]) {
case 'C':
if (!\is_int($element)) {
throw new \InvalidArgumentException('Bytes must be represented as an integer between 0 and 255, inclusive.');
}
$result .= \pack('C', $element);
break;
case 'b':
if (!\is_bool($element)) {
throw new \InvalidArgumentException('A boolean parameter was expected.');
}
$result .= $element ? "\x01" : "\x00";
break;
case 'Q':
if (!\is_int($element) && !\is_float($element)) {
throw new \InvalidArgumentException('An integer was expected.');
}
// 4294967296 == 1 << 32
$result .= \pack('NN', $element / 4294967296, $element);
break;
case 'N':
if (\is_float($element)) {
$element = (int) $element;
}
if (!\is_int($element)) {
throw new \InvalidArgumentException('An integer was expected.');
}
$result .= \pack('N', $element);
break;
case 's':
if (!self::is_stringable($element)) {
throw new \InvalidArgumentException('A string was expected.');
}
$result .= \pack('Na*', \strlen($element), $element);
break;
case 'i':
if (!$element instanceof BigInteger && !$element instanceof FiniteField\Integer) {
throw new \InvalidArgumentException('A phpseclib3\\Math\\BigInteger or phpseclib3\\Math\\Common\\FiniteField\\Integer object was expected.');
}
$element = $element->toBytes(\true);
$result .= \pack('Na*', \strlen($element), $element);
break;
case 'L':
if (!\is_array($element)) {
throw new \InvalidArgumentException('An array was expected.');
}
$element = \implode(',', $element);
$result .= \pack('Na*', \strlen($element), $element);
break;
default:
throw new \InvalidArgumentException('$format contains an invalid character');
}
}
return $result;
}
/**
* Expand a pack string
*
* Converts C5 to CCCCC, for example.
*
* @param string $format
* @return string
*/
private static function formatPack($format)
{
$parts = \preg_split('#(\\d+)#', $format, -1, \PREG_SPLIT_DELIM_CAPTURE);
$format = '';
for ($i = 1; $i < \count($parts); $i += 2) {
$format .= \substr($parts[$i - 1], 0, -1) . \str_repeat(\substr($parts[$i - 1], -1), $parts[$i]);
}
$format .= $parts[$i - 1];
return $format;
}
/**
* Convert binary data into bits
*
* bin2hex / hex2bin refer to base-256 encoded data as binary, whilst
* decbin / bindec refer to base-2 encoded data as binary. For the purposes
* of this function, bin refers to base-256 encoded data whilst bits refers
* to base-2 encoded data
*
* @param string $x
* @return string
*/
public static function bits2bin($x)
{
/*
// the pure-PHP approach is faster than the GMP approach
if (function_exists('gmp_export')) {
return strlen($x) ? gmp_export(gmp_init($x, 2)) : gmp_init(0);
}
*/
if (\preg_match('#[^01]#', $x)) {
throw new \RuntimeException('The only valid characters are 0 and 1');
}
if (!\defined('PHP_INT_MIN')) {
\define('PHP_INT_MIN', ~\PHP_INT_MAX);
}
$length = \strlen($x);
if (!$length) {
return '';
}
$block_size = \PHP_INT_SIZE << 3;
$pad = $block_size - $length % $block_size;
if ($pad != $block_size) {
$x = \str_repeat('0', $pad) . $x;
}
$parts = \str_split($x, $block_size);
$str = '';
foreach ($parts as $part) {
$xor = $part[0] == '1' ? \PHP_INT_MIN : 0;
$part[0] = '0';
$str .= \pack(\PHP_INT_SIZE == 4 ? 'N' : 'J', $xor ^ eval('return 0b' . $part . ';'));
}
return \ltrim($str, "\x00");
}
/**
* Convert bits to binary data
*
* @param string $x
* @return string
*/
public static function bin2bits($x, $trim = \true)
{
/*
// the pure-PHP approach is slower than the GMP approach BUT
// i want to the pure-PHP version to be easily unit tested as well
if (function_exists('gmp_import')) {
return gmp_strval(gmp_import($x), 2);
}
*/
$len = \strlen($x);
$mod = $len % \PHP_INT_SIZE;
if ($mod) {
$x = \str_pad($x, $len + \PHP_INT_SIZE - $mod, "\x00", \STR_PAD_LEFT);
}
$bits = '';
if (\PHP_INT_SIZE == 4) {
$digits = \unpack('N*', $x);
foreach ($digits as $digit) {
$bits .= \sprintf('%032b', $digit);
}
} else {
$digits = \unpack('J*', $x);
foreach ($digits as $digit) {
$bits .= \sprintf('%064b', $digit);
}
}
return $trim ? \ltrim($bits, '0') : $bits;
}
/**
* Switch Endianness Bit Order
*
* @param string $x
* @return string
*/
public static function switchEndianness($x)
{
$r = '';
for ($i = \strlen($x) - 1; $i >= 0; $i--) {
$b = \ord($x[$i]);
if (\PHP_INT_SIZE === 8) {
// 3 operations
// from http://graphics.stanford.edu/~seander/bithacks.html#ReverseByteWith64BitsDiv
$r .= \chr(($b * 0x202020202 & 0x10884422010) % 1023);
} else {
// 7 operations
// from http://graphics.stanford.edu/~seander/bithacks.html#ReverseByteWith32Bits
$p1 = $b * 0x802 & 0x22110;
$p2 = $b * 0x8020 & 0x88440;
$r .= \chr(($p1 | $p2) * 0x10101 >> 16);
}
}
return $r;
}
/**
* Increment the current string
*
* @param string $var
* @return string
*/
public static function increment_str(&$var)
{
if (\function_exists('sodium_increment')) {
$var = \strrev($var);
\sodium_increment($var);
$var = \strrev($var);
return $var;
}
for ($i = 4; $i <= \strlen($var); $i += 4) {
$temp = \substr($var, -$i, 4);
switch ($temp) {
case "\xff\xff\xff\xff":
$var = \substr_replace($var, "\x00\x00\x00\x00", -$i, 4);
break;
case "\xff\xff\xff":
$var = \substr_replace($var, "\x80\x00\x00\x00", -$i, 4);
return $var;
default:
$temp = \unpack('Nnum', $temp);
$var = \substr_replace($var, \pack('N', $temp['num'] + 1), -$i, 4);
return $var;
}
}
$remainder = \strlen($var) % 4;
if ($remainder == 0) {
return $var;
}
$temp = \unpack('Nnum', \str_pad(\substr($var, 0, $remainder), 4, "\x00", \STR_PAD_LEFT));
$temp = \substr(\pack('N', $temp['num'] + 1), -$remainder);
$var = \substr_replace($var, $temp, 0, $remainder);
return $var;
}
/**
* Find whether the type of a variable is string (or could be converted to one)
*
* @param mixed $var
* @return bool
* @psalm-assert-if-true string|\Stringable $var
*/
public static function is_stringable($var)
{
return \is_string($var) || \is_object($var) && \method_exists($var, '__toString');
}
/**
* Constant Time Base64-decoding
*
* ParagoneIE\ConstantTime doesn't use libsodium if it's available so we'll do so
* ourselves. see https://github.com/paragonie/constant_time_encoding/issues/39
*
* @param string $data
* @return string
*/
public static function base64_decode($data)
{
return \function_exists('sodium_base642bin') ? \sodium_base642bin($data, \SODIUM_BASE64_VARIANT_ORIGINAL_NO_PADDING, '=') : Base64::decode($data);
}
/**
* Constant Time Base64-decoding (URL safe)
*
* @param string $data
* @return string
*/
public static function base64url_decode($data)
{
// return self::base64_decode(str_replace(['-', '_'], ['+', '/'], $data));
return \function_exists('sodium_base642bin') ? \sodium_base642bin($data, \SODIUM_BASE64_VARIANT_URLSAFE_NO_PADDING, '=') : Base64UrlSafe::decode($data);
}
/**
* Constant Time Base64-encoding
*
* @param string $data
* @return string
*/
public static function base64_encode($data)
{
return \function_exists('sodium_bin2base64') ? \sodium_bin2base64($data, \SODIUM_BASE64_VARIANT_ORIGINAL) : Base64::encode($data);
}
/**
* Constant Time Base64-encoding (URL safe)
*
* @param string $data
* @return string
*/
public static function base64url_encode($data)
{
// return str_replace(['+', '/'], ['-', '_'], self::base64_encode($data));
return \function_exists('sodium_bin2base64') ? \sodium_bin2base64($data, \SODIUM_BASE64_VARIANT_URLSAFE) : Base64UrlSafe::encode($data);
}
/**
* Constant Time Hex Decoder
*
* @param string $data
* @return string
*/
public static function hex2bin($data)
{
return \function_exists('sodium_hex2bin') ? \sodium_hex2bin($data) : Hex::decode($data);
}
/**
* Constant Time Hex Encoder
*
* @param string $data
* @return string
*/
public static function bin2hex($data)
{
return \function_exists('sodium_bin2hex') ? \sodium_bin2hex($data) : Hex::encode($data);
}
}

View File

@@ -0,0 +1,112 @@
<?php
/**
* Pure-PHP implementation of AES.
*
* Uses mcrypt, if available/possible, and an internal implementation, otherwise.
*
* PHP version 5
*
* NOTE: Since AES.php is (for compatibility and phpseclib-historical reasons) virtually
* just a wrapper to Rijndael.php you may consider using Rijndael.php instead of
* to save one include_once().
*
* If {@link self::setKeyLength() setKeyLength()} isn't called, it'll be calculated from
* {@link self::setKey() setKey()}. ie. if the key is 128-bits, the key length will be 128-bits. If it's 136-bits
* it'll be null-padded to 192-bits and 192 bits will be the key length until {@link self::setKey() setKey()}
* is called, again, at which point, it'll be recalculated.
*
* Since \phpseclib3\Crypt\AES extends \phpseclib3\Crypt\Rijndael, some functions are available to be called that, in the context of AES, don't
* make a whole lot of sense. {@link self::setBlockLength() setBlockLength()}, for instance. Calling that function,
* however possible, won't do anything (AES has a fixed block length whereas Rijndael has a variable one).
*
* Here's a short example of how to use this library:
* <code>
* <?php
* include 'vendor/autoload.php';
*
* $aes = new \phpseclib3\Crypt\AES('ctr');
*
* $aes->setKey('abcdefghijklmnop');
*
* $size = 10 * 1024;
* $plaintext = '';
* for ($i = 0; $i < $size; $i++) {
* $plaintext.= 'a';
* }
*
* echo $aes->decrypt($aes->encrypt($plaintext));
* ?>
* </code>
*
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2008 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net
*/
namespace VendorDuplicator\phpseclib3\Crypt;
/**
* Pure-PHP implementation of AES.
*
* @author Jim Wigginton <terrafrost@php.net>
*/
class AES extends Rijndael
{
/**
* Dummy function
*
* Since \phpseclib3\Crypt\AES extends \phpseclib3\Crypt\Rijndael, this function is, technically, available, but it doesn't do anything.
*
* @see \VendorDuplicator\phpseclib3\Crypt\Rijndael::setBlockLength()
* @param int $length
* @throws \BadMethodCallException anytime it's called
*/
public function setBlockLength($length)
{
throw new \BadMethodCallException('The block length cannot be set for AES.');
}
/**
* Sets the key length
*
* Valid key lengths are 128, 192, and 256. Set the link to bool(false) to disable a fixed key length
*
* @see \VendorDuplicator\phpseclib3\Crypt\Rijndael:setKeyLength()
* @param int $length
* @throws \LengthException if the key length isn't supported
*/
public function setKeyLength($length)
{
switch ($length) {
case 128:
case 192:
case 256:
break;
default:
throw new \LengthException('Key of size ' . $length . ' not supported by this algorithm. Only keys of sizes 128, 192 or 256 supported');
}
parent::setKeyLength($length);
}
/**
* Sets the key.
*
* Rijndael supports five different key lengths, AES only supports three.
*
* @see \VendorDuplicator\phpseclib3\Crypt\Rijndael:setKey()
* @see setKeyLength()
* @param string $key
* @throws \LengthException if the key length isn't supported
*/
public function setKey($key)
{
switch (\strlen($key)) {
case 16:
case 24:
case 32:
break;
default:
throw new \LengthException('Key of size ' . \strlen($key) . ' not supported by this algorithm. Only keys of sizes 16, 24 or 32 supported');
}
parent::setKey($key);
}
}

View File

@@ -0,0 +1,660 @@
<?php
/**
* Pure-PHP implementation of Blowfish.
*
* Uses mcrypt, if available, and an internal implementation, otherwise.
*
* PHP version 5
*
* Useful resources are as follows:
*
* - {@link http://en.wikipedia.org/wiki/Blowfish_(cipher) Wikipedia description of Blowfish}
*
* # An overview of bcrypt vs Blowfish
*
* OpenSSH private keys use a customized version of bcrypt. Specifically, instead of
* encrypting OrpheanBeholderScryDoubt 64 times OpenSSH's bcrypt variant encrypts
* OxychromaticBlowfishSwatDynamite 64 times. so we can't use crypt().
*
* bcrypt is basically Blowfish but instead of performing the key expansion once it performs
* the expansion 129 times for each round, with the first key expansion interleaving the salt
* and password. This renders OpenSSL unusable and forces us to use a pure-PHP implementation
* of blowfish.
*
* # phpseclib's four different _encryptBlock() implementations
*
* When using Blowfish as an encryption algorithm, _encryptBlock() is called 9 + 512 +
* (the number of blocks in the plaintext) times.
*
* Each of the first 9 calls to _encryptBlock() modify the P-array. Each of the next 512
* calls modify the S-boxes. The remaining _encryptBlock() calls operate on the plaintext to
* produce the ciphertext. In the pure-PHP implementation of Blowfish these remaining
* _encryptBlock() calls are highly optimized through the use of eval(). Among other things,
* P-array lookups are eliminated by hard-coding the key-dependent P-array values, and thus we
* have explained 2 of the 4 different _encryptBlock() implementations.
*
* With bcrypt things are a bit different. _encryptBlock() is called 1,079,296 times,
* assuming 16 rounds (which is what OpenSSH's bcrypt defaults to). The eval()-optimized
* _encryptBlock() isn't as beneficial because the P-array values are not constant. Well, they
* are constant, but only for, at most, 777 _encryptBlock() calls, which is equivalent to ~6KB
* of data. The average length of back to back _encryptBlock() calls with a fixed P-array is
* 514.12, which is ~4KB of data. Creating an eval()-optimized _encryptBlock() has an upfront
* cost, which is CPU dependent and is probably not going to be worth it for just ~4KB of
* data. Conseqeuently, bcrypt does not benefit from the eval()-optimized _encryptBlock().
*
* The regular _encryptBlock() does unpack() and pack() on every call, as well, and that can
* begin to add up after one million function calls.
*
* In theory, one might think that it might be beneficial to rewrite all block ciphers so
* that, instead of passing strings to _encryptBlock(), you convert the string to an array of
* integers and then pass successive subarrays of that array to _encryptBlock. This, however,
* kills PHP's memory use. Like let's say you have a 1MB long string. After doing
* $in = str_repeat('a', 1024 * 1024); PHP's memory utilization jumps up by ~1MB. After doing
* $blocks = str_split($in, 4); it jumps up by an additional ~16MB. After
* $blocks = array_map(fn($x) => unpack('N*', $x), $blocks); it jumps up by an additional
* ~90MB, yielding a 106x increase in memory usage. Consequently, it bcrypt calls a different
* _encryptBlock() then the regular Blowfish does. That said, the Blowfish _encryptBlock() is
* basically just a thin wrapper around the bcrypt _encryptBlock(), so there's that.
*
* This explains 3 of the 4 _encryptBlock() implementations. the last _encryptBlock()
* implementation can best be understood by doing Ctrl + F and searching for where
* self::$use_reg_intval is defined.
*
* # phpseclib's three different _setupKey() implementations
*
* Every bcrypt round is the equivalent of encrypting 512KB of data. Since OpenSSH uses 16
* rounds by default that's ~8MB of data that's essentially being encrypted whenever
* you use bcrypt. That's a lot of data, however, bcrypt operates within tighter constraints
* than regular Blowfish, so we can use that to our advantage. In particular, whereas Blowfish
* supports variable length keys, in bcrypt, the initial "key" is the sha512 hash of the
* password. sha512 hashes are 512 bits or 64 bytes long and thus the bcrypt keys are of a
* fixed length whereas Blowfish keys are not of a fixed length.
*
* bcrypt actually has two different key expansion steps. The first one (expandstate) is
* constantly XOR'ing every _encryptBlock() parameter against the salt prior _encryptBlock()'s
* being called. The second one (expand0state) is more similar to Blowfish's _setupKey()
* but it can still use the fixed length key optimization discussed above and can do away with
* the pack() / unpack() calls.
*
* I suppose _setupKey() could be made to be a thin wrapper around expandstate() but idk it's
* just a lot of work for very marginal benefits as _setupKey() is only called once for
* regular Blowfish vs the 128 times it's called --per round-- with bcrypt.
*
* # blowfish + bcrypt in the same class
*
* Altho there's a lot of Blowfish code that bcrypt doesn't re-use, bcrypt does re-use the
* initial S-boxes, the initial P-array and the int-only _encryptBlock() implementation.
*
* # Credit
*
* phpseclib's bcrypt implementation is based losely off of OpenSSH's implementation:
*
* https://github.com/openssh/openssh-portable/blob/master/openbsd-compat/bcrypt_pbkdf.c
*
* Here's a short example of how to use this library:
* <code>
* <?php
* include 'vendor/autoload.php';
*
* $blowfish = new \phpseclib3\Crypt\Blowfish('ctr');
*
* $blowfish->setKey('12345678901234567890123456789012');
*
* $plaintext = str_repeat('a', 1024);
*
* echo $blowfish->decrypt($blowfish->encrypt($plaintext));
* ?>
* </code>
*
* @author Jim Wigginton <terrafrost@php.net>
* @author Hans-Juergen Petrich <petrich@tronic-media.com>
* @copyright 2007 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net
*/
namespace VendorDuplicator\phpseclib3\Crypt;
use VendorDuplicator\phpseclib3\Crypt\Common\BlockCipher;
/**
* Pure-PHP implementation of Blowfish.
*
* @author Jim Wigginton <terrafrost@php.net>
* @author Hans-Juergen Petrich <petrich@tronic-media.com>
*/
class Blowfish extends BlockCipher
{
/**
* Block Length of the cipher
*
* @see \VendorDuplicator\phpseclib3\Crypt\Common\SymmetricKey::block_size
* @var int
*/
protected $block_size = 8;
/**
* The mcrypt specific name of the cipher
*
* @see \VendorDuplicator\phpseclib3\Crypt\Common\SymmetricKey::cipher_name_mcrypt
* @var string
*/
protected $cipher_name_mcrypt = 'blowfish';
/**
* Optimizing value while CFB-encrypting
*
* @see \VendorDuplicator\phpseclib3\Crypt\Common\SymmetricKey::cfb_init_len
* @var int
*/
protected $cfb_init_len = 500;
/**
* The fixed subkeys boxes ($sbox0 - $sbox3) with 256 entries each
*
* S-Box 0
*
* @var array
*/
private static $sbox0 = [0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, 0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99, 0x24a19947, 0xb3916cf7, 0x801f2e2, 0x858efc16, 0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e, 0xd95748f, 0x728eb658, 0x718bcd58, 0x82154aee, 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013, 0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, 0x8e79dcb0, 0x603a180e, 0x6c9e0e8b, 0xb01e8a3e, 0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60, 0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440, 0x55ca396a, 0x2aab10b6, 0xb4cc5c34, 0x1141e8ce, 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a, 0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, 0xafd6ba33, 0x6c24cf5c, 0x7a325381, 0x28958677, 0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193, 0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032, 0xef845d5d, 0xe98575b1, 0xdc262302, 0xeb651b88, 0x23893e81, 0xd396acc5, 0xf6d6ff3, 0x83f44239, 0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, 0x21c66842, 0xf6e96c9a, 0x670c9c61, 0xabd388f0, 0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3, 0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98, 0xa1f1651d, 0x39af0176, 0x66ca593e, 0x82430e88, 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe, 0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, 0x4ed3aa62, 0x363f7706, 0x1bfedf72, 0x429b023d, 0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b, 0x75372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7, 0xe3fe501a, 0xb6794c3b, 0x976ce0bd, 0x4c006ba, 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463, 0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, 0x6dfc511f, 0x9b30952c, 0xcc814544, 0xaf5ebd09, 0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3, 0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb, 0x5579c0bd, 0x1a60320a, 0xd6a100c6, 0x402c7279, 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8, 0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, 0x323db5fa, 0xfd238760, 0x53317b48, 0x3e00df82, 0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db, 0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573, 0x695b27b0, 0xbbca58c8, 0xe1ffa35d, 0xb8f011a0, 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b, 0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, 0xe1ddf2da, 0xa4cb7e33, 0x62fb1341, 0xcee4c6e8, 0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4, 0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0, 0xd08ed1d0, 0xafc725e0, 0x8e3c5b2f, 0x8e7594b7, 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c, 0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, 0x2f2f2218, 0xbe0e1777, 0xea752dfe, 0x8b021fa1, 0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299, 0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9, 0x165fa266, 0x80957705, 0x93cc7314, 0x211a1477, 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf, 0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, 0x250e2d, 0x2071b35e, 0x226800bb, 0x57b8e0af, 0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa, 0x78c14389, 0xd95a537f, 0x207d5ba2, 0x2e5b9c5, 0x83260376, 0x6295cfa9, 0x11c81968, 0x4e734a41, 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915, 0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, 0x8ba6fb5, 0x571be91f, 0xf296ec6b, 0x2a0dd915, 0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664, 0x53b02d5d, 0xa99f8fa1, 0x8ba4799, 0x6e85076a];
/**
* S-Box 1
*
* @var array
*/
private static $sbox1 = [0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, 0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266, 0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1, 0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e, 0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6, 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1, 0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x21ecc5e, 0x9686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1, 0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737, 0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8, 0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x200b3ff, 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd, 0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, 0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7, 0xa9446146, 0xfd0030e, 0xecc8c73e, 0xa4751e41, 0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331, 0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf, 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af, 0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, 0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87, 0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c, 0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2, 0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16, 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd, 0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, 0x43556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509, 0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e, 0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3, 0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f, 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a, 0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, 0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960, 0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66, 0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x18cff28, 0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802, 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84, 0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, 0x13cca830, 0xeb61bd96, 0x334fe1e, 0xaa0363cf, 0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14, 0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e, 0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50, 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7, 0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, 0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281, 0xe358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99, 0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696, 0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128, 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73, 0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, 0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0, 0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105, 0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250, 0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3, 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285, 0x95bbf00, 0xad19489d, 0x1462b174, 0x23820e00, 0x58428d2a, 0xc55f5ea, 0x1dadf43e, 0x233f7061, 0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb, 0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e, 0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735, 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc, 0x9e447a2e, 0xc3453484, 0xfdd56705, 0xe1e9ec9, 0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340, 0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20, 0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7];
/**
* S-Box 2
*
* @var array
*/
private static $sbox2 = [0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, 0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068, 0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af, 0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840, 0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45, 0xbfbc09ec, 0x3bd9785, 0x7fac6dd0, 0x31cb8504, 0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a, 0x28507825, 0x530429f4, 0xa2c86da, 0xe9b66dfb, 0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee, 0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6, 0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42, 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b, 0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2, 0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb, 0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527, 0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b, 0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33, 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c, 0xfdf8e802, 0x4272f70, 0x80bb155c, 0x5282ce3, 0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc, 0x7f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17, 0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564, 0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b, 0xe12b4c2, 0x2e1329e, 0xaf664fd1, 0xcad18115, 0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, 0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728, 0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0, 0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e, 0xa476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37, 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d, 0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, 0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b, 0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3, 0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb, 0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d, 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c, 0x6a124237, 0xb79251e7, 0x6a1bbe6, 0x4bfb6350, 0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9, 0x44421659, 0xa121386, 0xd90cec6e, 0xd5abea2a, 0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe, 0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d, 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc, 0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f, 0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61, 0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2, 0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9, 0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2, 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c, 0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e, 0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633, 0xe85a1f02, 0x9f0be8c, 0x4a99a025, 0x1d6efe10, 0x1ab93d1d, 0xba5a4df, 0xa186f20f, 0x2868f169, 0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52, 0x50115e01, 0xa70683fa, 0xa002b5c4, 0xde6d027, 0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, 0xf0177a28, 0xc0f586e0, 0x6058aa, 0x30dc7d62, 0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634, 0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76, 0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24, 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc, 0xed545578, 0x8fca5b5, 0xd83d7cd3, 0x4dad0fc4, 0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c, 0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837, 0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0];
/**
* S-Box 3
*
* @var array
*/
private static $sbox3 = [0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, 0x5cb0679e, 0x4fa33742, 0xd3822740, 0x99bc9bbe, 0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b, 0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4, 0x5748ab2f, 0xbc946e79, 0xc6a376d2, 0x6549c2c8, 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6, 0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, 0xa1fad5f0, 0x6a2d519a, 0x63ef8ce2, 0x9a86ee22, 0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4, 0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6, 0x2826a2f9, 0xa73a3ae1, 0x4ba99586, 0xef5562e9, 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59, 0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, 0xe990fd5a, 0x9e34d797, 0x2cf0b7d9, 0x22b8b51, 0x96d5ac3a, 0x17da67d, 0xd1cf3ed6, 0x7c7d2d28, 0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c, 0xe029ac71, 0xe019a5e6, 0x47b0acfd, 0xed93fa9b, 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28, 0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, 0x15056dd4, 0x88f46dba, 0x3a16125, 0x564f0bd, 0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a, 0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319, 0x7533d928, 0xb155fdf5, 0x3563482, 0x8aba3cbb, 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f, 0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, 0xea7a90c2, 0xfb3e7bce, 0x5121ce64, 0x774fbe32, 0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680, 0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x9072166, 0xb39a460a, 0x6445c0dd, 0x586cdecf, 0x1c20c8ae, 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb, 0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, 0x72eacea8, 0xfa6484bb, 0x8d6612ae, 0xbf3c6f47, 0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370, 0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d, 0x4040cb08, 0x4eb4e2cc, 0x34d2466a, 0x115af84, 0xe1b00428, 0x95983a1d, 0x6b89fb4, 0xce6ea048, 0x6f3f3b82, 0x3520ab82, 0x11a1d4b, 0x277227f8, 0x611560b1, 0xe7933fdc, 0xbb3a792b, 0x344525bd, 0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9, 0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7, 0x1a908749, 0xd44fbd9a, 0xd0dadecb, 0xd50ada38, 0x339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f, 0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, 0xbf97222c, 0x15e6fc2a, 0xf91fc71, 0x9b941525, 0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1, 0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442, 0xe0ec6e0e, 0x1698db3b, 0x4c98a0be, 0x3278e964, 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e, 0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, 0xdf359f8d, 0x9b992f2e, 0xe60b6f47, 0xfe3f11d, 0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f, 0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299, 0xf523f357, 0xa6327623, 0x93a83531, 0x56cccd02, 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc, 0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, 0xe6c6c7bd, 0x327a140a, 0x45e1d006, 0xc3f27b9a, 0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6, 0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b, 0x53113ec0, 0x1640e3d3, 0x38abbd60, 0x2547adf0, 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060, 0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, 0x1948c25c, 0x2fb8a8c, 0x1c36ae4, 0xd6ebe1f9, 0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f, 0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6];
/**
* P-Array consists of 18 32-bit subkeys
*
* @var array
*/
private static $parray = [0x243f6a88, 0x85a308d3, 0x13198a2e, 0x3707344, 0xa4093822, 0x299f31d0, 0x82efa98, 0xec4e6c89, 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c, 0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, 0x9216d5d9, 0x8979fb1b];
/**
* The BCTX-working Array
*
* Holds the expanded key [p] and the key-depended s-boxes [sb]
*
* @var array
*/
private $bctx;
/**
* Holds the last used key
*
* @var array
*/
private $kl;
/**
* The Key Length (in bytes)
* {@internal The max value is 256 / 8 = 32, the min value is 128 / 8 = 16. Exists in conjunction with $Nk
* because the encryption / decryption / key schedule creation requires this number and not $key_length. We could
* derive this from $key_length or vice versa, but that'd mean we'd have to do multiple shift operations, so in lieu
* of that, we'll just precompute it once.}
*
* @see \VendorDuplicator\phpseclib3\Crypt\Common\SymmetricKey::setKeyLength()
* @var int
*/
protected $key_length = 16;
/**
* Default Constructor.
*
* @param string $mode
* @throws \InvalidArgumentException if an invalid / unsupported mode is provided
*/
public function __construct($mode)
{
parent::__construct($mode);
if ($this->mode == self::MODE_STREAM) {
throw new \InvalidArgumentException('Block ciphers cannot be ran in stream mode');
}
}
/**
* Sets the key length.
*
* Key lengths can be between 32 and 448 bits.
*
* @param int $length
*/
public function setKeyLength($length)
{
if ($length < 32 || $length > 448) {
throw new \LengthException('Key size of ' . $length . ' bits is not supported by this algorithm. Only keys of sizes between 32 and 448 bits are supported');
}
$this->key_length = $length >> 3;
parent::setKeyLength($length);
}
/**
* Test for engine validity
*
* This is mainly just a wrapper to set things up for \phpseclib3\Crypt\Common\SymmetricKey::isValidEngine()
*
* @see \VendorDuplicator\phpseclib3\Crypt\Common\SymmetricKey::isValidEngine()
* @param int $engine
* @return bool
*/
protected function isValidEngineHelper($engine)
{
if ($engine == self::ENGINE_OPENSSL) {
if ($this->key_length < 16) {
return \false;
}
// quoting https://www.openssl.org/news/openssl-3.0-notes.html, OpenSSL 3.0.1
// "Moved all variations of the EVP ciphers CAST5, BF, IDEA, SEED, RC2, RC4, RC5, and DES to the legacy provider"
// in theory openssl_get_cipher_methods() should catch this but, on GitHub Actions, at least, it does not
if (\defined('OPENSSL_VERSION_TEXT') && \version_compare(\preg_replace('#OpenSSL (\\d+\\.\\d+\\.\\d+) .*#', '$1', \OPENSSL_VERSION_TEXT), '3.0.1', '>=')) {
return \false;
}
$this->cipher_name_openssl_ecb = 'bf-ecb';
$this->cipher_name_openssl = 'bf-' . $this->openssl_translate_mode();
}
return parent::isValidEngineHelper($engine);
}
/**
* Setup the key (expansion)
*
* @see \VendorDuplicator\phpseclib3\Crypt\Common\SymmetricKey::_setupKey()
*/
protected function setupKey()
{
if (isset($this->kl['key']) && $this->key === $this->kl['key']) {
// already expanded
return;
}
$this->kl = ['key' => $this->key];
/* key-expanding p[] and S-Box building sb[] */
$this->bctx = ['p' => [], 'sb' => [self::$sbox0, self::$sbox1, self::$sbox2, self::$sbox3]];
// unpack binary string in unsigned chars
$key = \array_values(\unpack('C*', $this->key));
$keyl = \count($key);
// with bcrypt $keyl will always be 16 (because the key is the sha512 of the key you provide)
for ($j = 0, $i = 0; $i < 18; ++$i) {
// xor P1 with the first 32-bits of the key, xor P2 with the second 32-bits ...
for ($data = 0, $k = 0; $k < 4; ++$k) {
$data = $data << 8 | $key[$j];
if (++$j >= $keyl) {
$j = 0;
}
}
$this->bctx['p'][] = self::$parray[$i] ^ \intval($data);
}
// encrypt the zero-string, replace P1 and P2 with the encrypted data,
// encrypt P3 and P4 with the new P1 and P2, do it with all P-array and subkeys
$data = "\x00\x00\x00\x00\x00\x00\x00\x00";
for ($i = 0; $i < 18; $i += 2) {
list($l, $r) = \array_values(\unpack('N*', $data = $this->encryptBlock($data)));
$this->bctx['p'][$i] = $l;
$this->bctx['p'][$i + 1] = $r;
}
for ($i = 0; $i < 4; ++$i) {
for ($j = 0; $j < 256; $j += 2) {
list($l, $r) = \array_values(\unpack('N*', $data = $this->encryptBlock($data)));
$this->bctx['sb'][$i][$j] = $l;
$this->bctx['sb'][$i][$j + 1] = $r;
}
}
}
/**
* Initialize Static Variables
*/
protected static function initialize_static_variables()
{
if (\is_float(self::$sbox2[0])) {
self::$sbox0 = \array_map('intval', self::$sbox0);
self::$sbox1 = \array_map('intval', self::$sbox1);
self::$sbox2 = \array_map('intval', self::$sbox2);
self::$sbox3 = \array_map('intval', self::$sbox3);
self::$parray = \array_map('intval', self::$parray);
}
parent::initialize_static_variables();
}
/**
* bcrypt
*
* @param string $sha2pass
* @param string $sha2salt
* @access private
* @return string
*/
private static function bcrypt_hash($sha2pass, $sha2salt)
{
$p = self::$parray;
$sbox0 = self::$sbox0;
$sbox1 = self::$sbox1;
$sbox2 = self::$sbox2;
$sbox3 = self::$sbox3;
$cdata = \array_values(\unpack('N*', 'OxychromaticBlowfishSwatDynamite'));
$sha2pass = \array_values(\unpack('N*', $sha2pass));
$sha2salt = \array_values(\unpack('N*', $sha2salt));
self::expandstate($sha2salt, $sha2pass, $sbox0, $sbox1, $sbox2, $sbox3, $p);
for ($i = 0; $i < 64; $i++) {
self::expand0state($sha2salt, $sbox0, $sbox1, $sbox2, $sbox3, $p);
self::expand0state($sha2pass, $sbox0, $sbox1, $sbox2, $sbox3, $p);
}
for ($i = 0; $i < 64; $i++) {
for ($j = 0; $j < 8; $j += 2) {
// count($cdata) == 8
list($cdata[$j], $cdata[$j + 1]) = self::encryptBlockHelperFast($cdata[$j], $cdata[$j + 1], $sbox0, $sbox1, $sbox2, $sbox3, $p);
}
}
return \pack('L*', ...$cdata);
}
/**
* Performs OpenSSH-style bcrypt
*
* @param string $pass
* @param string $salt
* @param int $keylen
* @param int $rounds
* @access public
* @return string
*/
public static function bcrypt_pbkdf($pass, $salt, $keylen, $rounds)
{
self::initialize_static_variables();
if (\PHP_INT_SIZE == 4) {
throw new \RuntimeException('bcrypt is far too slow to be practical on 32-bit versions of PHP');
}
$sha2pass = \hash('sha512', $pass, \true);
$results = [];
$count = 1;
while (32 * \count($results) < $keylen) {
$countsalt = $salt . \pack('N', $count++);
$sha2salt = \hash('sha512', $countsalt, \true);
$out = $tmpout = self::bcrypt_hash($sha2pass, $sha2salt);
for ($i = 1; $i < $rounds; $i++) {
$sha2salt = \hash('sha512', $tmpout, \true);
$tmpout = self::bcrypt_hash($sha2pass, $sha2salt);
$out ^= $tmpout;
}
$results[] = $out;
}
$output = '';
for ($i = 0; $i < 32; $i++) {
foreach ($results as $result) {
$output .= $result[$i];
}
}
return \substr($output, 0, $keylen);
}
/**
* Key expansion without salt
*
* @access private
* @param int[] $key
* @param int[] $sbox0
* @param int[] $sbox1
* @param int[] $sbox2
* @param int[] $sbox3
* @param int[] $p
* @see self::_bcrypt_hash()
*/
private static function expand0state(array $key, array &$sbox0, array &$sbox1, array &$sbox2, array &$sbox3, array &$p)
{
// expand0state is basically the same thing as this:
//return self::expandstate(array_fill(0, 16, 0), $key);
// but this separate function eliminates a bunch of XORs and array lookups
$p = [$p[0] ^ $key[0], $p[1] ^ $key[1], $p[2] ^ $key[2], $p[3] ^ $key[3], $p[4] ^ $key[4], $p[5] ^ $key[5], $p[6] ^ $key[6], $p[7] ^ $key[7], $p[8] ^ $key[8], $p[9] ^ $key[9], $p[10] ^ $key[10], $p[11] ^ $key[11], $p[12] ^ $key[12], $p[13] ^ $key[13], $p[14] ^ $key[14], $p[15] ^ $key[15], $p[16] ^ $key[0], $p[17] ^ $key[1]];
// @codingStandardsIgnoreStart
list($p[0], $p[1]) = self::encryptBlockHelperFast(0, 0, $sbox0, $sbox1, $sbox2, $sbox3, $p);
list($p[2], $p[3]) = self::encryptBlockHelperFast($p[0], $p[1], $sbox0, $sbox1, $sbox2, $sbox3, $p);
list($p[4], $p[5]) = self::encryptBlockHelperFast($p[2], $p[3], $sbox0, $sbox1, $sbox2, $sbox3, $p);
list($p[6], $p[7]) = self::encryptBlockHelperFast($p[4], $p[5], $sbox0, $sbox1, $sbox2, $sbox3, $p);
list($p[8], $p[9]) = self::encryptBlockHelperFast($p[6], $p[7], $sbox0, $sbox1, $sbox2, $sbox3, $p);
list($p[10], $p[11]) = self::encryptBlockHelperFast($p[8], $p[9], $sbox0, $sbox1, $sbox2, $sbox3, $p);
list($p[12], $p[13]) = self::encryptBlockHelperFast($p[10], $p[11], $sbox0, $sbox1, $sbox2, $sbox3, $p);
list($p[14], $p[15]) = self::encryptBlockHelperFast($p[12], $p[13], $sbox0, $sbox1, $sbox2, $sbox3, $p);
list($p[16], $p[17]) = self::encryptBlockHelperFast($p[14], $p[15], $sbox0, $sbox1, $sbox2, $sbox3, $p);
// @codingStandardsIgnoreEnd
list($sbox0[0], $sbox0[1]) = self::encryptBlockHelperFast($p[16], $p[17], $sbox0, $sbox1, $sbox2, $sbox3, $p);
for ($i = 2; $i < 256; $i += 2) {
list($sbox0[$i], $sbox0[$i + 1]) = self::encryptBlockHelperFast($sbox0[$i - 2], $sbox0[$i - 1], $sbox0, $sbox1, $sbox2, $sbox3, $p);
}
list($sbox1[0], $sbox1[1]) = self::encryptBlockHelperFast($sbox0[254], $sbox0[255], $sbox0, $sbox1, $sbox2, $sbox3, $p);
for ($i = 2; $i < 256; $i += 2) {
list($sbox1[$i], $sbox1[$i + 1]) = self::encryptBlockHelperFast($sbox1[$i - 2], $sbox1[$i - 1], $sbox0, $sbox1, $sbox2, $sbox3, $p);
}
list($sbox2[0], $sbox2[1]) = self::encryptBlockHelperFast($sbox1[254], $sbox1[255], $sbox0, $sbox1, $sbox2, $sbox3, $p);
for ($i = 2; $i < 256; $i += 2) {
list($sbox2[$i], $sbox2[$i + 1]) = self::encryptBlockHelperFast($sbox2[$i - 2], $sbox2[$i - 1], $sbox0, $sbox1, $sbox2, $sbox3, $p);
}
list($sbox3[0], $sbox3[1]) = self::encryptBlockHelperFast($sbox2[254], $sbox2[255], $sbox0, $sbox1, $sbox2, $sbox3, $p);
for ($i = 2; $i < 256; $i += 2) {
list($sbox3[$i], $sbox3[$i + 1]) = self::encryptBlockHelperFast($sbox3[$i - 2], $sbox3[$i - 1], $sbox0, $sbox1, $sbox2, $sbox3, $p);
}
}
/**
* Key expansion with salt
*
* @access private
* @param int[] $data
* @param int[] $key
* @param int[] $sbox0
* @param int[] $sbox1
* @param int[] $sbox2
* @param int[] $sbox3
* @param int[] $p
* @see self::_bcrypt_hash()
*/
private static function expandstate(array $data, array $key, array &$sbox0, array &$sbox1, array &$sbox2, array &$sbox3, array &$p)
{
$p = [$p[0] ^ $key[0], $p[1] ^ $key[1], $p[2] ^ $key[2], $p[3] ^ $key[3], $p[4] ^ $key[4], $p[5] ^ $key[5], $p[6] ^ $key[6], $p[7] ^ $key[7], $p[8] ^ $key[8], $p[9] ^ $key[9], $p[10] ^ $key[10], $p[11] ^ $key[11], $p[12] ^ $key[12], $p[13] ^ $key[13], $p[14] ^ $key[14], $p[15] ^ $key[15], $p[16] ^ $key[0], $p[17] ^ $key[1]];
// @codingStandardsIgnoreStart
list($p[0], $p[1]) = self::encryptBlockHelperFast($data[0], $data[1], $sbox0, $sbox1, $sbox2, $sbox3, $p);
list($p[2], $p[3]) = self::encryptBlockHelperFast($data[2] ^ $p[0], $data[3] ^ $p[1], $sbox0, $sbox1, $sbox2, $sbox3, $p);
list($p[4], $p[5]) = self::encryptBlockHelperFast($data[4] ^ $p[2], $data[5] ^ $p[3], $sbox0, $sbox1, $sbox2, $sbox3, $p);
list($p[6], $p[7]) = self::encryptBlockHelperFast($data[6] ^ $p[4], $data[7] ^ $p[5], $sbox0, $sbox1, $sbox2, $sbox3, $p);
list($p[8], $p[9]) = self::encryptBlockHelperFast($data[8] ^ $p[6], $data[9] ^ $p[7], $sbox0, $sbox1, $sbox2, $sbox3, $p);
list($p[10], $p[11]) = self::encryptBlockHelperFast($data[10] ^ $p[8], $data[11] ^ $p[9], $sbox0, $sbox1, $sbox2, $sbox3, $p);
list($p[12], $p[13]) = self::encryptBlockHelperFast($data[12] ^ $p[10], $data[13] ^ $p[11], $sbox0, $sbox1, $sbox2, $sbox3, $p);
list($p[14], $p[15]) = self::encryptBlockHelperFast($data[14] ^ $p[12], $data[15] ^ $p[13], $sbox0, $sbox1, $sbox2, $sbox3, $p);
list($p[16], $p[17]) = self::encryptBlockHelperFast($data[0] ^ $p[14], $data[1] ^ $p[15], $sbox0, $sbox1, $sbox2, $sbox3, $p);
// @codingStandardsIgnoreEnd
list($sbox0[0], $sbox0[1]) = self::encryptBlockHelperFast($data[2] ^ $p[16], $data[3] ^ $p[17], $sbox0, $sbox1, $sbox2, $sbox3, $p);
for ($i = 2, $j = 4; $i < 256; $i += 2, $j = ($j + 2) % 16) {
// instead of 16 maybe count($data) would be better?
list($sbox0[$i], $sbox0[$i + 1]) = self::encryptBlockHelperFast($data[$j] ^ $sbox0[$i - 2], $data[$j + 1] ^ $sbox0[$i - 1], $sbox0, $sbox1, $sbox2, $sbox3, $p);
}
list($sbox1[0], $sbox1[1]) = self::encryptBlockHelperFast($data[2] ^ $sbox0[254], $data[3] ^ $sbox0[255], $sbox0, $sbox1, $sbox2, $sbox3, $p);
for ($i = 2, $j = 4; $i < 256; $i += 2, $j = ($j + 2) % 16) {
list($sbox1[$i], $sbox1[$i + 1]) = self::encryptBlockHelperFast($data[$j] ^ $sbox1[$i - 2], $data[$j + 1] ^ $sbox1[$i - 1], $sbox0, $sbox1, $sbox2, $sbox3, $p);
}
list($sbox2[0], $sbox2[1]) = self::encryptBlockHelperFast($data[2] ^ $sbox1[254], $data[3] ^ $sbox1[255], $sbox0, $sbox1, $sbox2, $sbox3, $p);
for ($i = 2, $j = 4; $i < 256; $i += 2, $j = ($j + 2) % 16) {
list($sbox2[$i], $sbox2[$i + 1]) = self::encryptBlockHelperFast($data[$j] ^ $sbox2[$i - 2], $data[$j + 1] ^ $sbox2[$i - 1], $sbox0, $sbox1, $sbox2, $sbox3, $p);
}
list($sbox3[0], $sbox3[1]) = self::encryptBlockHelperFast($data[2] ^ $sbox2[254], $data[3] ^ $sbox2[255], $sbox0, $sbox1, $sbox2, $sbox3, $p);
for ($i = 2, $j = 4; $i < 256; $i += 2, $j = ($j + 2) % 16) {
list($sbox3[$i], $sbox3[$i + 1]) = self::encryptBlockHelperFast($data[$j] ^ $sbox3[$i - 2], $data[$j + 1] ^ $sbox3[$i - 1], $sbox0, $sbox1, $sbox2, $sbox3, $p);
}
}
/**
* Encrypts a block
*
* @param string $in
* @return string
*/
protected function encryptBlock($in)
{
$p = $this->bctx['p'];
// extract($this->bctx['sb'], EXTR_PREFIX_ALL, 'sb'); // slower
$sb_0 = $this->bctx['sb'][0];
$sb_1 = $this->bctx['sb'][1];
$sb_2 = $this->bctx['sb'][2];
$sb_3 = $this->bctx['sb'][3];
$in = \unpack('N*', $in);
$l = $in[1];
$r = $in[2];
list($r, $l) = \PHP_INT_SIZE == 4 ? self::encryptBlockHelperSlow($l, $r, $sb_0, $sb_1, $sb_2, $sb_3, $p) : self::encryptBlockHelperFast($l, $r, $sb_0, $sb_1, $sb_2, $sb_3, $p);
return \pack("N*", $r, $l);
}
/**
* Fast helper function for block encryption
*
* @access private
* @param int $x0
* @param int $x1
* @param int[] $sbox0
* @param int[] $sbox1
* @param int[] $sbox2
* @param int[] $sbox3
* @param int[] $p
* @return int[]
*/
private static function encryptBlockHelperFast($x0, $x1, array $sbox0, array $sbox1, array $sbox2, array $sbox3, array $p)
{
$x0 ^= $p[0];
$x1 ^= ($sbox0[($x0 & 0xff000000) >> 24] + $sbox1[($x0 & 0xff0000) >> 16] ^ $sbox2[($x0 & 0xff00) >> 8]) + $sbox3[$x0 & 0xff] ^ $p[1];
$x0 ^= ($sbox0[($x1 & 0xff000000) >> 24] + $sbox1[($x1 & 0xff0000) >> 16] ^ $sbox2[($x1 & 0xff00) >> 8]) + $sbox3[$x1 & 0xff] ^ $p[2];
$x1 ^= ($sbox0[($x0 & 0xff000000) >> 24] + $sbox1[($x0 & 0xff0000) >> 16] ^ $sbox2[($x0 & 0xff00) >> 8]) + $sbox3[$x0 & 0xff] ^ $p[3];
$x0 ^= ($sbox0[($x1 & 0xff000000) >> 24] + $sbox1[($x1 & 0xff0000) >> 16] ^ $sbox2[($x1 & 0xff00) >> 8]) + $sbox3[$x1 & 0xff] ^ $p[4];
$x1 ^= ($sbox0[($x0 & 0xff000000) >> 24] + $sbox1[($x0 & 0xff0000) >> 16] ^ $sbox2[($x0 & 0xff00) >> 8]) + $sbox3[$x0 & 0xff] ^ $p[5];
$x0 ^= ($sbox0[($x1 & 0xff000000) >> 24] + $sbox1[($x1 & 0xff0000) >> 16] ^ $sbox2[($x1 & 0xff00) >> 8]) + $sbox3[$x1 & 0xff] ^ $p[6];
$x1 ^= ($sbox0[($x0 & 0xff000000) >> 24] + $sbox1[($x0 & 0xff0000) >> 16] ^ $sbox2[($x0 & 0xff00) >> 8]) + $sbox3[$x0 & 0xff] ^ $p[7];
$x0 ^= ($sbox0[($x1 & 0xff000000) >> 24] + $sbox1[($x1 & 0xff0000) >> 16] ^ $sbox2[($x1 & 0xff00) >> 8]) + $sbox3[$x1 & 0xff] ^ $p[8];
$x1 ^= ($sbox0[($x0 & 0xff000000) >> 24] + $sbox1[($x0 & 0xff0000) >> 16] ^ $sbox2[($x0 & 0xff00) >> 8]) + $sbox3[$x0 & 0xff] ^ $p[9];
$x0 ^= ($sbox0[($x1 & 0xff000000) >> 24] + $sbox1[($x1 & 0xff0000) >> 16] ^ $sbox2[($x1 & 0xff00) >> 8]) + $sbox3[$x1 & 0xff] ^ $p[10];
$x1 ^= ($sbox0[($x0 & 0xff000000) >> 24] + $sbox1[($x0 & 0xff0000) >> 16] ^ $sbox2[($x0 & 0xff00) >> 8]) + $sbox3[$x0 & 0xff] ^ $p[11];
$x0 ^= ($sbox0[($x1 & 0xff000000) >> 24] + $sbox1[($x1 & 0xff0000) >> 16] ^ $sbox2[($x1 & 0xff00) >> 8]) + $sbox3[$x1 & 0xff] ^ $p[12];
$x1 ^= ($sbox0[($x0 & 0xff000000) >> 24] + $sbox1[($x0 & 0xff0000) >> 16] ^ $sbox2[($x0 & 0xff00) >> 8]) + $sbox3[$x0 & 0xff] ^ $p[13];
$x0 ^= ($sbox0[($x1 & 0xff000000) >> 24] + $sbox1[($x1 & 0xff0000) >> 16] ^ $sbox2[($x1 & 0xff00) >> 8]) + $sbox3[$x1 & 0xff] ^ $p[14];
$x1 ^= ($sbox0[($x0 & 0xff000000) >> 24] + $sbox1[($x0 & 0xff0000) >> 16] ^ $sbox2[($x0 & 0xff00) >> 8]) + $sbox3[$x0 & 0xff] ^ $p[15];
$x0 ^= ($sbox0[($x1 & 0xff000000) >> 24] + $sbox1[($x1 & 0xff0000) >> 16] ^ $sbox2[($x1 & 0xff00) >> 8]) + $sbox3[$x1 & 0xff] ^ $p[16];
return [$x1 & 0xffffffff ^ $p[17], $x0 & 0xffffffff];
}
/**
* Slow helper function for block encryption
*
* @access private
* @param int $x0
* @param int $x1
* @param int[] $sbox0
* @param int[] $sbox1
* @param int[] $sbox2
* @param int[] $sbox3
* @param int[] $p
* @return int[]
*/
private static function encryptBlockHelperSlow($x0, $x1, array $sbox0, array $sbox1, array $sbox2, array $sbox3, array $p)
{
// -16777216 == intval(0xFF000000) on 32-bit PHP installs
$x0 ^= $p[0];
$x1 ^= self::safe_intval((self::safe_intval($sbox0[($x0 & -16777216) >> 24 & 0xff] + $sbox1[($x0 & 0xff0000) >> 16]) ^ $sbox2[($x0 & 0xff00) >> 8]) + $sbox3[$x0 & 0xff]) ^ $p[1];
$x0 ^= self::safe_intval((self::safe_intval($sbox0[($x1 & -16777216) >> 24 & 0xff] + $sbox1[($x1 & 0xff0000) >> 16]) ^ $sbox2[($x1 & 0xff00) >> 8]) + $sbox3[$x1 & 0xff]) ^ $p[2];
$x1 ^= self::safe_intval((self::safe_intval($sbox0[($x0 & -16777216) >> 24 & 0xff] + $sbox1[($x0 & 0xff0000) >> 16]) ^ $sbox2[($x0 & 0xff00) >> 8]) + $sbox3[$x0 & 0xff]) ^ $p[3];
$x0 ^= self::safe_intval((self::safe_intval($sbox0[($x1 & -16777216) >> 24 & 0xff] + $sbox1[($x1 & 0xff0000) >> 16]) ^ $sbox2[($x1 & 0xff00) >> 8]) + $sbox3[$x1 & 0xff]) ^ $p[4];
$x1 ^= self::safe_intval((self::safe_intval($sbox0[($x0 & -16777216) >> 24 & 0xff] + $sbox1[($x0 & 0xff0000) >> 16]) ^ $sbox2[($x0 & 0xff00) >> 8]) + $sbox3[$x0 & 0xff]) ^ $p[5];
$x0 ^= self::safe_intval((self::safe_intval($sbox0[($x1 & -16777216) >> 24 & 0xff] + $sbox1[($x1 & 0xff0000) >> 16]) ^ $sbox2[($x1 & 0xff00) >> 8]) + $sbox3[$x1 & 0xff]) ^ $p[6];
$x1 ^= self::safe_intval((self::safe_intval($sbox0[($x0 & -16777216) >> 24 & 0xff] + $sbox1[($x0 & 0xff0000) >> 16]) ^ $sbox2[($x0 & 0xff00) >> 8]) + $sbox3[$x0 & 0xff]) ^ $p[7];
$x0 ^= self::safe_intval((self::safe_intval($sbox0[($x1 & -16777216) >> 24 & 0xff] + $sbox1[($x1 & 0xff0000) >> 16]) ^ $sbox2[($x1 & 0xff00) >> 8]) + $sbox3[$x1 & 0xff]) ^ $p[8];
$x1 ^= self::safe_intval((self::safe_intval($sbox0[($x0 & -16777216) >> 24 & 0xff] + $sbox1[($x0 & 0xff0000) >> 16]) ^ $sbox2[($x0 & 0xff00) >> 8]) + $sbox3[$x0 & 0xff]) ^ $p[9];
$x0 ^= self::safe_intval((self::safe_intval($sbox0[($x1 & -16777216) >> 24 & 0xff] + $sbox1[($x1 & 0xff0000) >> 16]) ^ $sbox2[($x1 & 0xff00) >> 8]) + $sbox3[$x1 & 0xff]) ^ $p[10];
$x1 ^= self::safe_intval((self::safe_intval($sbox0[($x0 & -16777216) >> 24 & 0xff] + $sbox1[($x0 & 0xff0000) >> 16]) ^ $sbox2[($x0 & 0xff00) >> 8]) + $sbox3[$x0 & 0xff]) ^ $p[11];
$x0 ^= self::safe_intval((self::safe_intval($sbox0[($x1 & -16777216) >> 24 & 0xff] + $sbox1[($x1 & 0xff0000) >> 16]) ^ $sbox2[($x1 & 0xff00) >> 8]) + $sbox3[$x1 & 0xff]) ^ $p[12];
$x1 ^= self::safe_intval((self::safe_intval($sbox0[($x0 & -16777216) >> 24 & 0xff] + $sbox1[($x0 & 0xff0000) >> 16]) ^ $sbox2[($x0 & 0xff00) >> 8]) + $sbox3[$x0 & 0xff]) ^ $p[13];
$x0 ^= self::safe_intval((self::safe_intval($sbox0[($x1 & -16777216) >> 24 & 0xff] + $sbox1[($x1 & 0xff0000) >> 16]) ^ $sbox2[($x1 & 0xff00) >> 8]) + $sbox3[$x1 & 0xff]) ^ $p[14];
$x1 ^= self::safe_intval((self::safe_intval($sbox0[($x0 & -16777216) >> 24 & 0xff] + $sbox1[($x0 & 0xff0000) >> 16]) ^ $sbox2[($x0 & 0xff00) >> 8]) + $sbox3[$x0 & 0xff]) ^ $p[15];
$x0 ^= self::safe_intval((self::safe_intval($sbox0[($x1 & -16777216) >> 24 & 0xff] + $sbox1[($x1 & 0xff0000) >> 16]) ^ $sbox2[($x1 & 0xff00) >> 8]) + $sbox3[$x1 & 0xff]) ^ $p[16];
return [$x1 ^ $p[17], $x0];
}
/**
* Decrypts a block
*
* @param string $in
* @return string
*/
protected function decryptBlock($in)
{
$p = $this->bctx['p'];
$sb_0 = $this->bctx['sb'][0];
$sb_1 = $this->bctx['sb'][1];
$sb_2 = $this->bctx['sb'][2];
$sb_3 = $this->bctx['sb'][3];
$in = \unpack('N*', $in);
$l = $in[1];
$r = $in[2];
for ($i = 17; $i > 2; $i -= 2) {
$l ^= $p[$i];
$r ^= self::safe_intval((self::safe_intval($sb_0[$l >> 24 & 0xff] + $sb_1[$l >> 16 & 0xff]) ^ $sb_2[$l >> 8 & 0xff]) + $sb_3[$l & 0xff]);
$r ^= $p[$i - 1];
$l ^= self::safe_intval((self::safe_intval($sb_0[$r >> 24 & 0xff] + $sb_1[$r >> 16 & 0xff]) ^ $sb_2[$r >> 8 & 0xff]) + $sb_3[$r & 0xff]);
}
return \pack('N*', $r ^ $p[0], $l ^ $p[1]);
}
/**
* Setup the performance-optimized function for de/encrypt()
*
* @see \VendorDuplicator\phpseclib3\Crypt\Common\SymmetricKey::_setupInlineCrypt()
*/
protected function setupInlineCrypt()
{
$p = $this->bctx['p'];
$init_crypt = '
static $sb_0, $sb_1, $sb_2, $sb_3;
if (!$sb_0) {
$sb_0 = $this->bctx["sb"][0];
$sb_1 = $this->bctx["sb"][1];
$sb_2 = $this->bctx["sb"][2];
$sb_3 = $this->bctx["sb"][3];
}
';
$safeint = self::safe_intval_inline();
// Generating encrypt code:
$encrypt_block = '
$in = unpack("N*", $in);
$l = $in[1];
$r = $in[2];
';
for ($i = 0; $i < 16; $i += 2) {
$encrypt_block .= '
$l^= ' . $p[$i] . ';
$r^= ' . \sprintf($safeint, '(' . \sprintf($safeint, '$sb_0[$l >> 24 & 0xff] + $sb_1[$l >> 16 & 0xff]') . ' ^
$sb_2[$l >> 8 & 0xff]) +
$sb_3[$l & 0xff]') . ';
$r^= ' . $p[$i + 1] . ';
$l^= ' . \sprintf($safeint, '(' . \sprintf($safeint, '$sb_0[$r >> 24 & 0xff] + $sb_1[$r >> 16 & 0xff]') . ' ^
$sb_2[$r >> 8 & 0xff]) +
$sb_3[$r & 0xff]') . ';
';
}
$encrypt_block .= '
$in = pack("N*",
$r ^ ' . $p[17] . ',
$l ^ ' . $p[16] . '
);
';
// Generating decrypt code:
$decrypt_block = '
$in = unpack("N*", $in);
$l = $in[1];
$r = $in[2];
';
for ($i = 17; $i > 2; $i -= 2) {
$decrypt_block .= '
$l^= ' . $p[$i] . ';
$r^= ' . \sprintf($safeint, '(' . \sprintf($safeint, '$sb_0[$l >> 24 & 0xff] + $sb_1[$l >> 16 & 0xff]') . ' ^
$sb_2[$l >> 8 & 0xff]) +
$sb_3[$l & 0xff]') . ';
$r^= ' . $p[$i - 1] . ';
$l^= ' . \sprintf($safeint, '(' . \sprintf($safeint, '$sb_0[$r >> 24 & 0xff] + $sb_1[$r >> 16 & 0xff]') . ' ^
$sb_2[$r >> 8 & 0xff]) +
$sb_3[$r & 0xff]') . ';
';
}
$decrypt_block .= '
$in = pack("N*",
$r ^ ' . $p[0] . ',
$l ^ ' . $p[1] . '
);
';
$this->inline_crypt = $this->createInlineCryptFunction(['init_crypt' => $init_crypt, 'init_encrypt' => '', 'init_decrypt' => '', 'encrypt_block' => $encrypt_block, 'decrypt_block' => $decrypt_block]);
}
}

View File

@@ -0,0 +1,999 @@
<?php
/**
* Pure-PHP implementation of ChaCha20.
*
* PHP version 5
*
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2019 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net
*/
namespace VendorDuplicator\phpseclib3\Crypt;
use VendorDuplicator\phpseclib3\Exception\BadDecryptionException;
use VendorDuplicator\phpseclib3\Exception\InsufficientSetupException;
/**
* Pure-PHP implementation of ChaCha20.
*
* @author Jim Wigginton <terrafrost@php.net>
*/
class ChaCha20 extends Salsa20
{
/**
* The OpenSSL specific name of the cipher
*
* @var string
*/
protected $cipher_name_openssl = 'chacha20';
/**
* Test for engine validity
*
* This is mainly just a wrapper to set things up for \phpseclib3\Crypt\Common\SymmetricKey::isValidEngine()
*
* @see \VendorDuplicator\phpseclib3\Crypt\Common\SymmetricKey::__construct()
* @param int $engine
* @return bool
*/
protected function isValidEngineHelper($engine)
{
switch ($engine) {
case self::ENGINE_LIBSODIUM:
// PHP 7.2.0 (30 Nov 2017) added support for libsodium
// we could probably make it so that if $this->counter == 0 then the first block would be done with either OpenSSL
// or PHP and then subsequent blocks would then be done with libsodium but idk - it's not a high priority atm
// we could also make it so that if $this->counter == 0 and $this->continuousBuffer then do the first string
// with libsodium and subsequent strings with openssl or pure-PHP but again not a high priority
return \function_exists('sodium_crypto_aead_chacha20poly1305_ietf_encrypt') && $this->key_length == 32 && ($this->usePoly1305 && !isset($this->poly1305Key) && $this->counter == 0 || $this->counter == 1) && !$this->continuousBuffer;
case self::ENGINE_OPENSSL:
// OpenSSL 1.1.0 (released 25 Aug 2016) added support for chacha20.
// PHP didn't support OpenSSL 1.1.0 until 7.0.19 (11 May 2017)
// if you attempt to provide openssl with a 128 bit key (as opposed to a 256 bit key) openssl will null
// pad the key to 256 bits and still use the expansion constant for 256-bit keys. the fact that
// openssl treats the IV as both the counter and nonce, however, let's us use openssl in continuous mode
// whereas libsodium does not
if ($this->key_length != 32) {
return \false;
}
}
return parent::isValidEngineHelper($engine);
}
/**
* Encrypts a message.
*
* @see \VendorDuplicator\phpseclib3\Crypt\Common\SymmetricKey::decrypt()
* @see self::crypt()
* @param string $plaintext
* @return string $ciphertext
*/
public function encrypt($plaintext)
{
$this->setup();
if ($this->engine == self::ENGINE_LIBSODIUM) {
return $this->encrypt_with_libsodium($plaintext);
}
return parent::encrypt($plaintext);
}
/**
* Decrypts a message.
*
* $this->decrypt($this->encrypt($plaintext)) == $this->encrypt($this->encrypt($plaintext)).
* At least if the continuous buffer is disabled.
*
* @see \VendorDuplicator\phpseclib3\Crypt\Common\SymmetricKey::encrypt()
* @see self::crypt()
* @param string $ciphertext
* @return string $plaintext
*/
public function decrypt($ciphertext)
{
$this->setup();
if ($this->engine == self::ENGINE_LIBSODIUM) {
return $this->decrypt_with_libsodium($ciphertext);
}
return parent::decrypt($ciphertext);
}
/**
* Encrypts a message with libsodium
*
* @see self::encrypt()
* @param string $plaintext
* @return string $text
*/
private function encrypt_with_libsodium($plaintext)
{
$params = [$plaintext, $this->aad, $this->nonce, $this->key];
$ciphertext = \strlen($this->nonce) == 8 ? \sodium_crypto_aead_chacha20poly1305_encrypt(...$params) : \sodium_crypto_aead_chacha20poly1305_ietf_encrypt(...$params);
if (!$this->usePoly1305) {
return \substr($ciphertext, 0, \strlen($plaintext));
}
$newciphertext = \substr($ciphertext, 0, \strlen($plaintext));
$this->newtag = $this->usingGeneratedPoly1305Key && \strlen($this->nonce) == 12 ? \substr($ciphertext, \strlen($plaintext)) : $this->poly1305($newciphertext);
return $newciphertext;
}
/**
* Decrypts a message with libsodium
*
* @see self::decrypt()
* @param string $ciphertext
* @return string $text
*/
private function decrypt_with_libsodium($ciphertext)
{
$params = [$ciphertext, $this->aad, $this->nonce, $this->key];
if (isset($this->poly1305Key)) {
if ($this->oldtag === \false) {
throw new InsufficientSetupException('Authentication Tag has not been set');
}
if ($this->usingGeneratedPoly1305Key && \strlen($this->nonce) == 12) {
$plaintext = \sodium_crypto_aead_chacha20poly1305_ietf_decrypt(...$params);
$this->oldtag = \false;
if ($plaintext === \false) {
throw new BadDecryptionException('Derived authentication tag and supplied authentication tag do not match');
}
return $plaintext;
}
$newtag = $this->poly1305($ciphertext);
if ($this->oldtag != \substr($newtag, 0, \strlen($this->oldtag))) {
$this->oldtag = \false;
throw new BadDecryptionException('Derived authentication tag and supplied authentication tag do not match');
}
$this->oldtag = \false;
}
$plaintext = \strlen($this->nonce) == 8 ? \sodium_crypto_aead_chacha20poly1305_encrypt(...$params) : \sodium_crypto_aead_chacha20poly1305_ietf_encrypt(...$params);
return \substr($plaintext, 0, \strlen($ciphertext));
}
/**
* Sets the nonce.
*
* @param string $nonce
*/
public function setNonce($nonce)
{
if (!\is_string($nonce)) {
throw new \UnexpectedValueException('The nonce should be a string');
}
/*
from https://tools.ietf.org/html/rfc7539#page-7
"Note also that the original ChaCha had a 64-bit nonce and 64-bit
block count. We have modified this here to be more consistent with
recommendations in Section 3.2 of [RFC5116]."
*/
switch (\strlen($nonce)) {
case 8:
// 64 bits
case 12:
// 96 bits
break;
default:
throw new \LengthException('Nonce of size ' . \strlen($nonce) . ' not supported by this algorithm. Only 64-bit nonces or 96-bit nonces are supported');
}
$this->nonce = $nonce;
$this->changed = \true;
$this->setEngine();
}
/**
* Setup the self::ENGINE_INTERNAL $engine
*
* (re)init, if necessary, the internal cipher $engine
*
* _setup() will be called each time if $changed === true
* typically this happens when using one or more of following public methods:
*
* - setKey()
*
* - setNonce()
*
* - First run of encrypt() / decrypt() with no init-settings
*
* @see self::setKey()
* @see self::setNonce()
* @see self::disableContinuousBuffer()
*/
protected function setup()
{
if (!$this->changed) {
return;
}
$this->enbuffer = $this->debuffer = ['ciphertext' => '', 'counter' => $this->counter];
$this->changed = $this->nonIVChanged = \false;
if ($this->nonce === \false) {
throw new InsufficientSetupException('No nonce has been defined');
}
if ($this->key === \false) {
throw new InsufficientSetupException('No key has been defined');
}
if ($this->usePoly1305 && !isset($this->poly1305Key)) {
$this->usingGeneratedPoly1305Key = \true;
if ($this->engine == self::ENGINE_LIBSODIUM) {
return;
}
$this->createPoly1305Key();
}
$key = $this->key;
if (\strlen($key) == 16) {
$constant = 'expand 16-byte k';
$key .= $key;
} else {
$constant = 'expand 32-byte k';
}
$this->p1 = $constant . $key;
$this->p2 = $this->nonce;
if (\strlen($this->nonce) == 8) {
$this->p2 = "\x00\x00\x00\x00" . $this->p2;
}
}
/**
* The quarterround function
*
* @param int $a
* @param int $b
* @param int $c
* @param int $d
*/
protected static function quarterRound(&$a, &$b, &$c, &$d)
{
// in https://datatracker.ietf.org/doc/html/rfc7539#section-2.1 the addition,
// xor'ing and rotation are all on the same line so i'm keeping it on the same
// line here as well
// @codingStandardsIgnoreStart
$a += $b;
$d = self::leftRotate(\intval($d) ^ \intval($a), 16);
$c += $d;
$b = self::leftRotate(\intval($b) ^ \intval($c), 12);
$a += $b;
$d = self::leftRotate(\intval($d) ^ \intval($a), 8);
$c += $d;
$b = self::leftRotate(\intval($b) ^ \intval($c), 7);
// @codingStandardsIgnoreEnd
}
/**
* The doubleround function
*
* @param int $x0 (by reference)
* @param int $x1 (by reference)
* @param int $x2 (by reference)
* @param int $x3 (by reference)
* @param int $x4 (by reference)
* @param int $x5 (by reference)
* @param int $x6 (by reference)
* @param int $x7 (by reference)
* @param int $x8 (by reference)
* @param int $x9 (by reference)
* @param int $x10 (by reference)
* @param int $x11 (by reference)
* @param int $x12 (by reference)
* @param int $x13 (by reference)
* @param int $x14 (by reference)
* @param int $x15 (by reference)
*/
protected static function doubleRound(&$x0, &$x1, &$x2, &$x3, &$x4, &$x5, &$x6, &$x7, &$x8, &$x9, &$x10, &$x11, &$x12, &$x13, &$x14, &$x15)
{
// columnRound
static::quarterRound($x0, $x4, $x8, $x12);
static::quarterRound($x1, $x5, $x9, $x13);
static::quarterRound($x2, $x6, $x10, $x14);
static::quarterRound($x3, $x7, $x11, $x15);
// rowRound
static::quarterRound($x0, $x5, $x10, $x15);
static::quarterRound($x1, $x6, $x11, $x12);
static::quarterRound($x2, $x7, $x8, $x13);
static::quarterRound($x3, $x4, $x9, $x14);
}
/**
* The Salsa20 hash function function
*
* On my laptop this loop unrolled / function dereferenced version of parent::salsa20 encrypts 1mb of text in
* 0.65s vs the 0.85s that it takes with the parent method.
*
* If we were free to assume that the host OS would always be 64-bits then the if condition in leftRotate could
* be eliminated and we could knock this done to 0.60s.
*
* For comparison purposes, RC4 takes 0.16s and AES in CTR mode with the Eval engine takes 0.48s.
* AES in CTR mode with the PHP engine takes 1.19s. Salsa20 / ChaCha20 do not benefit as much from the Eval
* approach due to the fact that there are a lot less variables to de-reference, fewer loops to unroll, etc
*
* @param string $x
*/
protected static function salsa20($x)
{
list(, $x0, $x1, $x2, $x3, $x4, $x5, $x6, $x7, $x8, $x9, $x10, $x11, $x12, $x13, $x14, $x15) = \unpack('V*', $x);
$z0 = $x0;
$z1 = $x1;
$z2 = $x2;
$z3 = $x3;
$z4 = $x4;
$z5 = $x5;
$z6 = $x6;
$z7 = $x7;
$z8 = $x8;
$z9 = $x9;
$z10 = $x10;
$z11 = $x11;
$z12 = $x12;
$z13 = $x13;
$z14 = $x14;
$z15 = $x15;
// @codingStandardsIgnoreStart
// columnRound
$x0 += $x4;
$x12 = self::leftRotate(\intval($x12) ^ \intval($x0), 16);
$x8 += $x12;
$x4 = self::leftRotate(\intval($x4) ^ \intval($x8), 12);
$x0 += $x4;
$x12 = self::leftRotate(\intval($x12) ^ \intval($x0), 8);
$x8 += $x12;
$x4 = self::leftRotate(\intval($x4) ^ \intval($x8), 7);
$x1 += $x5;
$x13 = self::leftRotate(\intval($x13) ^ \intval($x1), 16);
$x9 += $x13;
$x5 = self::leftRotate(\intval($x5) ^ \intval($x9), 12);
$x1 += $x5;
$x13 = self::leftRotate(\intval($x13) ^ \intval($x1), 8);
$x9 += $x13;
$x5 = self::leftRotate(\intval($x5) ^ \intval($x9), 7);
$x2 += $x6;
$x14 = self::leftRotate(\intval($x14) ^ \intval($x2), 16);
$x10 += $x14;
$x6 = self::leftRotate(\intval($x6) ^ \intval($x10), 12);
$x2 += $x6;
$x14 = self::leftRotate(\intval($x14) ^ \intval($x2), 8);
$x10 += $x14;
$x6 = self::leftRotate(\intval($x6) ^ \intval($x10), 7);
$x3 += $x7;
$x15 = self::leftRotate(\intval($x15) ^ \intval($x3), 16);
$x11 += $x15;
$x7 = self::leftRotate(\intval($x7) ^ \intval($x11), 12);
$x3 += $x7;
$x15 = self::leftRotate(\intval($x15) ^ \intval($x3), 8);
$x11 += $x15;
$x7 = self::leftRotate(\intval($x7) ^ \intval($x11), 7);
// rowRound
$x0 += $x5;
$x15 = self::leftRotate(\intval($x15) ^ \intval($x0), 16);
$x10 += $x15;
$x5 = self::leftRotate(\intval($x5) ^ \intval($x10), 12);
$x0 += $x5;
$x15 = self::leftRotate(\intval($x15) ^ \intval($x0), 8);
$x10 += $x15;
$x5 = self::leftRotate(\intval($x5) ^ \intval($x10), 7);
$x1 += $x6;
$x12 = self::leftRotate(\intval($x12) ^ \intval($x1), 16);
$x11 += $x12;
$x6 = self::leftRotate(\intval($x6) ^ \intval($x11), 12);
$x1 += $x6;
$x12 = self::leftRotate(\intval($x12) ^ \intval($x1), 8);
$x11 += $x12;
$x6 = self::leftRotate(\intval($x6) ^ \intval($x11), 7);
$x2 += $x7;
$x13 = self::leftRotate(\intval($x13) ^ \intval($x2), 16);
$x8 += $x13;
$x7 = self::leftRotate(\intval($x7) ^ \intval($x8), 12);
$x2 += $x7;
$x13 = self::leftRotate(\intval($x13) ^ \intval($x2), 8);
$x8 += $x13;
$x7 = self::leftRotate(\intval($x7) ^ \intval($x8), 7);
$x3 += $x4;
$x14 = self::leftRotate(\intval($x14) ^ \intval($x3), 16);
$x9 += $x14;
$x4 = self::leftRotate(\intval($x4) ^ \intval($x9), 12);
$x3 += $x4;
$x14 = self::leftRotate(\intval($x14) ^ \intval($x3), 8);
$x9 += $x14;
$x4 = self::leftRotate(\intval($x4) ^ \intval($x9), 7);
// columnRound
$x0 += $x4;
$x12 = self::leftRotate(\intval($x12) ^ \intval($x0), 16);
$x8 += $x12;
$x4 = self::leftRotate(\intval($x4) ^ \intval($x8), 12);
$x0 += $x4;
$x12 = self::leftRotate(\intval($x12) ^ \intval($x0), 8);
$x8 += $x12;
$x4 = self::leftRotate(\intval($x4) ^ \intval($x8), 7);
$x1 += $x5;
$x13 = self::leftRotate(\intval($x13) ^ \intval($x1), 16);
$x9 += $x13;
$x5 = self::leftRotate(\intval($x5) ^ \intval($x9), 12);
$x1 += $x5;
$x13 = self::leftRotate(\intval($x13) ^ \intval($x1), 8);
$x9 += $x13;
$x5 = self::leftRotate(\intval($x5) ^ \intval($x9), 7);
$x2 += $x6;
$x14 = self::leftRotate(\intval($x14) ^ \intval($x2), 16);
$x10 += $x14;
$x6 = self::leftRotate(\intval($x6) ^ \intval($x10), 12);
$x2 += $x6;
$x14 = self::leftRotate(\intval($x14) ^ \intval($x2), 8);
$x10 += $x14;
$x6 = self::leftRotate(\intval($x6) ^ \intval($x10), 7);
$x3 += $x7;
$x15 = self::leftRotate(\intval($x15) ^ \intval($x3), 16);
$x11 += $x15;
$x7 = self::leftRotate(\intval($x7) ^ \intval($x11), 12);
$x3 += $x7;
$x15 = self::leftRotate(\intval($x15) ^ \intval($x3), 8);
$x11 += $x15;
$x7 = self::leftRotate(\intval($x7) ^ \intval($x11), 7);
// rowRound
$x0 += $x5;
$x15 = self::leftRotate(\intval($x15) ^ \intval($x0), 16);
$x10 += $x15;
$x5 = self::leftRotate(\intval($x5) ^ \intval($x10), 12);
$x0 += $x5;
$x15 = self::leftRotate(\intval($x15) ^ \intval($x0), 8);
$x10 += $x15;
$x5 = self::leftRotate(\intval($x5) ^ \intval($x10), 7);
$x1 += $x6;
$x12 = self::leftRotate(\intval($x12) ^ \intval($x1), 16);
$x11 += $x12;
$x6 = self::leftRotate(\intval($x6) ^ \intval($x11), 12);
$x1 += $x6;
$x12 = self::leftRotate(\intval($x12) ^ \intval($x1), 8);
$x11 += $x12;
$x6 = self::leftRotate(\intval($x6) ^ \intval($x11), 7);
$x2 += $x7;
$x13 = self::leftRotate(\intval($x13) ^ \intval($x2), 16);
$x8 += $x13;
$x7 = self::leftRotate(\intval($x7) ^ \intval($x8), 12);
$x2 += $x7;
$x13 = self::leftRotate(\intval($x13) ^ \intval($x2), 8);
$x8 += $x13;
$x7 = self::leftRotate(\intval($x7) ^ \intval($x8), 7);
$x3 += $x4;
$x14 = self::leftRotate(\intval($x14) ^ \intval($x3), 16);
$x9 += $x14;
$x4 = self::leftRotate(\intval($x4) ^ \intval($x9), 12);
$x3 += $x4;
$x14 = self::leftRotate(\intval($x14) ^ \intval($x3), 8);
$x9 += $x14;
$x4 = self::leftRotate(\intval($x4) ^ \intval($x9), 7);
// columnRound
$x0 += $x4;
$x12 = self::leftRotate(\intval($x12) ^ \intval($x0), 16);
$x8 += $x12;
$x4 = self::leftRotate(\intval($x4) ^ \intval($x8), 12);
$x0 += $x4;
$x12 = self::leftRotate(\intval($x12) ^ \intval($x0), 8);
$x8 += $x12;
$x4 = self::leftRotate(\intval($x4) ^ \intval($x8), 7);
$x1 += $x5;
$x13 = self::leftRotate(\intval($x13) ^ \intval($x1), 16);
$x9 += $x13;
$x5 = self::leftRotate(\intval($x5) ^ \intval($x9), 12);
$x1 += $x5;
$x13 = self::leftRotate(\intval($x13) ^ \intval($x1), 8);
$x9 += $x13;
$x5 = self::leftRotate(\intval($x5) ^ \intval($x9), 7);
$x2 += $x6;
$x14 = self::leftRotate(\intval($x14) ^ \intval($x2), 16);
$x10 += $x14;
$x6 = self::leftRotate(\intval($x6) ^ \intval($x10), 12);
$x2 += $x6;
$x14 = self::leftRotate(\intval($x14) ^ \intval($x2), 8);
$x10 += $x14;
$x6 = self::leftRotate(\intval($x6) ^ \intval($x10), 7);
$x3 += $x7;
$x15 = self::leftRotate(\intval($x15) ^ \intval($x3), 16);
$x11 += $x15;
$x7 = self::leftRotate(\intval($x7) ^ \intval($x11), 12);
$x3 += $x7;
$x15 = self::leftRotate(\intval($x15) ^ \intval($x3), 8);
$x11 += $x15;
$x7 = self::leftRotate(\intval($x7) ^ \intval($x11), 7);
// rowRound
$x0 += $x5;
$x15 = self::leftRotate(\intval($x15) ^ \intval($x0), 16);
$x10 += $x15;
$x5 = self::leftRotate(\intval($x5) ^ \intval($x10), 12);
$x0 += $x5;
$x15 = self::leftRotate(\intval($x15) ^ \intval($x0), 8);
$x10 += $x15;
$x5 = self::leftRotate(\intval($x5) ^ \intval($x10), 7);
$x1 += $x6;
$x12 = self::leftRotate(\intval($x12) ^ \intval($x1), 16);
$x11 += $x12;
$x6 = self::leftRotate(\intval($x6) ^ \intval($x11), 12);
$x1 += $x6;
$x12 = self::leftRotate(\intval($x12) ^ \intval($x1), 8);
$x11 += $x12;
$x6 = self::leftRotate(\intval($x6) ^ \intval($x11), 7);
$x2 += $x7;
$x13 = self::leftRotate(\intval($x13) ^ \intval($x2), 16);
$x8 += $x13;
$x7 = self::leftRotate(\intval($x7) ^ \intval($x8), 12);
$x2 += $x7;
$x13 = self::leftRotate(\intval($x13) ^ \intval($x2), 8);
$x8 += $x13;
$x7 = self::leftRotate(\intval($x7) ^ \intval($x8), 7);
$x3 += $x4;
$x14 = self::leftRotate(\intval($x14) ^ \intval($x3), 16);
$x9 += $x14;
$x4 = self::leftRotate(\intval($x4) ^ \intval($x9), 12);
$x3 += $x4;
$x14 = self::leftRotate(\intval($x14) ^ \intval($x3), 8);
$x9 += $x14;
$x4 = self::leftRotate(\intval($x4) ^ \intval($x9), 7);
// columnRound
$x0 += $x4;
$x12 = self::leftRotate(\intval($x12) ^ \intval($x0), 16);
$x8 += $x12;
$x4 = self::leftRotate(\intval($x4) ^ \intval($x8), 12);
$x0 += $x4;
$x12 = self::leftRotate(\intval($x12) ^ \intval($x0), 8);
$x8 += $x12;
$x4 = self::leftRotate(\intval($x4) ^ \intval($x8), 7);
$x1 += $x5;
$x13 = self::leftRotate(\intval($x13) ^ \intval($x1), 16);
$x9 += $x13;
$x5 = self::leftRotate(\intval($x5) ^ \intval($x9), 12);
$x1 += $x5;
$x13 = self::leftRotate(\intval($x13) ^ \intval($x1), 8);
$x9 += $x13;
$x5 = self::leftRotate(\intval($x5) ^ \intval($x9), 7);
$x2 += $x6;
$x14 = self::leftRotate(\intval($x14) ^ \intval($x2), 16);
$x10 += $x14;
$x6 = self::leftRotate(\intval($x6) ^ \intval($x10), 12);
$x2 += $x6;
$x14 = self::leftRotate(\intval($x14) ^ \intval($x2), 8);
$x10 += $x14;
$x6 = self::leftRotate(\intval($x6) ^ \intval($x10), 7);
$x3 += $x7;
$x15 = self::leftRotate(\intval($x15) ^ \intval($x3), 16);
$x11 += $x15;
$x7 = self::leftRotate(\intval($x7) ^ \intval($x11), 12);
$x3 += $x7;
$x15 = self::leftRotate(\intval($x15) ^ \intval($x3), 8);
$x11 += $x15;
$x7 = self::leftRotate(\intval($x7) ^ \intval($x11), 7);
// rowRound
$x0 += $x5;
$x15 = self::leftRotate(\intval($x15) ^ \intval($x0), 16);
$x10 += $x15;
$x5 = self::leftRotate(\intval($x5) ^ \intval($x10), 12);
$x0 += $x5;
$x15 = self::leftRotate(\intval($x15) ^ \intval($x0), 8);
$x10 += $x15;
$x5 = self::leftRotate(\intval($x5) ^ \intval($x10), 7);
$x1 += $x6;
$x12 = self::leftRotate(\intval($x12) ^ \intval($x1), 16);
$x11 += $x12;
$x6 = self::leftRotate(\intval($x6) ^ \intval($x11), 12);
$x1 += $x6;
$x12 = self::leftRotate(\intval($x12) ^ \intval($x1), 8);
$x11 += $x12;
$x6 = self::leftRotate(\intval($x6) ^ \intval($x11), 7);
$x2 += $x7;
$x13 = self::leftRotate(\intval($x13) ^ \intval($x2), 16);
$x8 += $x13;
$x7 = self::leftRotate(\intval($x7) ^ \intval($x8), 12);
$x2 += $x7;
$x13 = self::leftRotate(\intval($x13) ^ \intval($x2), 8);
$x8 += $x13;
$x7 = self::leftRotate(\intval($x7) ^ \intval($x8), 7);
$x3 += $x4;
$x14 = self::leftRotate(\intval($x14) ^ \intval($x3), 16);
$x9 += $x14;
$x4 = self::leftRotate(\intval($x4) ^ \intval($x9), 12);
$x3 += $x4;
$x14 = self::leftRotate(\intval($x14) ^ \intval($x3), 8);
$x9 += $x14;
$x4 = self::leftRotate(\intval($x4) ^ \intval($x9), 7);
// columnRound
$x0 += $x4;
$x12 = self::leftRotate(\intval($x12) ^ \intval($x0), 16);
$x8 += $x12;
$x4 = self::leftRotate(\intval($x4) ^ \intval($x8), 12);
$x0 += $x4;
$x12 = self::leftRotate(\intval($x12) ^ \intval($x0), 8);
$x8 += $x12;
$x4 = self::leftRotate(\intval($x4) ^ \intval($x8), 7);
$x1 += $x5;
$x13 = self::leftRotate(\intval($x13) ^ \intval($x1), 16);
$x9 += $x13;
$x5 = self::leftRotate(\intval($x5) ^ \intval($x9), 12);
$x1 += $x5;
$x13 = self::leftRotate(\intval($x13) ^ \intval($x1), 8);
$x9 += $x13;
$x5 = self::leftRotate(\intval($x5) ^ \intval($x9), 7);
$x2 += $x6;
$x14 = self::leftRotate(\intval($x14) ^ \intval($x2), 16);
$x10 += $x14;
$x6 = self::leftRotate(\intval($x6) ^ \intval($x10), 12);
$x2 += $x6;
$x14 = self::leftRotate(\intval($x14) ^ \intval($x2), 8);
$x10 += $x14;
$x6 = self::leftRotate(\intval($x6) ^ \intval($x10), 7);
$x3 += $x7;
$x15 = self::leftRotate(\intval($x15) ^ \intval($x3), 16);
$x11 += $x15;
$x7 = self::leftRotate(\intval($x7) ^ \intval($x11), 12);
$x3 += $x7;
$x15 = self::leftRotate(\intval($x15) ^ \intval($x3), 8);
$x11 += $x15;
$x7 = self::leftRotate(\intval($x7) ^ \intval($x11), 7);
// rowRound
$x0 += $x5;
$x15 = self::leftRotate(\intval($x15) ^ \intval($x0), 16);
$x10 += $x15;
$x5 = self::leftRotate(\intval($x5) ^ \intval($x10), 12);
$x0 += $x5;
$x15 = self::leftRotate(\intval($x15) ^ \intval($x0), 8);
$x10 += $x15;
$x5 = self::leftRotate(\intval($x5) ^ \intval($x10), 7);
$x1 += $x6;
$x12 = self::leftRotate(\intval($x12) ^ \intval($x1), 16);
$x11 += $x12;
$x6 = self::leftRotate(\intval($x6) ^ \intval($x11), 12);
$x1 += $x6;
$x12 = self::leftRotate(\intval($x12) ^ \intval($x1), 8);
$x11 += $x12;
$x6 = self::leftRotate(\intval($x6) ^ \intval($x11), 7);
$x2 += $x7;
$x13 = self::leftRotate(\intval($x13) ^ \intval($x2), 16);
$x8 += $x13;
$x7 = self::leftRotate(\intval($x7) ^ \intval($x8), 12);
$x2 += $x7;
$x13 = self::leftRotate(\intval($x13) ^ \intval($x2), 8);
$x8 += $x13;
$x7 = self::leftRotate(\intval($x7) ^ \intval($x8), 7);
$x3 += $x4;
$x14 = self::leftRotate(\intval($x14) ^ \intval($x3), 16);
$x9 += $x14;
$x4 = self::leftRotate(\intval($x4) ^ \intval($x9), 12);
$x3 += $x4;
$x14 = self::leftRotate(\intval($x14) ^ \intval($x3), 8);
$x9 += $x14;
$x4 = self::leftRotate(\intval($x4) ^ \intval($x9), 7);
// columnRound
$x0 += $x4;
$x12 = self::leftRotate(\intval($x12) ^ \intval($x0), 16);
$x8 += $x12;
$x4 = self::leftRotate(\intval($x4) ^ \intval($x8), 12);
$x0 += $x4;
$x12 = self::leftRotate(\intval($x12) ^ \intval($x0), 8);
$x8 += $x12;
$x4 = self::leftRotate(\intval($x4) ^ \intval($x8), 7);
$x1 += $x5;
$x13 = self::leftRotate(\intval($x13) ^ \intval($x1), 16);
$x9 += $x13;
$x5 = self::leftRotate(\intval($x5) ^ \intval($x9), 12);
$x1 += $x5;
$x13 = self::leftRotate(\intval($x13) ^ \intval($x1), 8);
$x9 += $x13;
$x5 = self::leftRotate(\intval($x5) ^ \intval($x9), 7);
$x2 += $x6;
$x14 = self::leftRotate(\intval($x14) ^ \intval($x2), 16);
$x10 += $x14;
$x6 = self::leftRotate(\intval($x6) ^ \intval($x10), 12);
$x2 += $x6;
$x14 = self::leftRotate(\intval($x14) ^ \intval($x2), 8);
$x10 += $x14;
$x6 = self::leftRotate(\intval($x6) ^ \intval($x10), 7);
$x3 += $x7;
$x15 = self::leftRotate(\intval($x15) ^ \intval($x3), 16);
$x11 += $x15;
$x7 = self::leftRotate(\intval($x7) ^ \intval($x11), 12);
$x3 += $x7;
$x15 = self::leftRotate(\intval($x15) ^ \intval($x3), 8);
$x11 += $x15;
$x7 = self::leftRotate(\intval($x7) ^ \intval($x11), 7);
// rowRound
$x0 += $x5;
$x15 = self::leftRotate(\intval($x15) ^ \intval($x0), 16);
$x10 += $x15;
$x5 = self::leftRotate(\intval($x5) ^ \intval($x10), 12);
$x0 += $x5;
$x15 = self::leftRotate(\intval($x15) ^ \intval($x0), 8);
$x10 += $x15;
$x5 = self::leftRotate(\intval($x5) ^ \intval($x10), 7);
$x1 += $x6;
$x12 = self::leftRotate(\intval($x12) ^ \intval($x1), 16);
$x11 += $x12;
$x6 = self::leftRotate(\intval($x6) ^ \intval($x11), 12);
$x1 += $x6;
$x12 = self::leftRotate(\intval($x12) ^ \intval($x1), 8);
$x11 += $x12;
$x6 = self::leftRotate(\intval($x6) ^ \intval($x11), 7);
$x2 += $x7;
$x13 = self::leftRotate(\intval($x13) ^ \intval($x2), 16);
$x8 += $x13;
$x7 = self::leftRotate(\intval($x7) ^ \intval($x8), 12);
$x2 += $x7;
$x13 = self::leftRotate(\intval($x13) ^ \intval($x2), 8);
$x8 += $x13;
$x7 = self::leftRotate(\intval($x7) ^ \intval($x8), 7);
$x3 += $x4;
$x14 = self::leftRotate(\intval($x14) ^ \intval($x3), 16);
$x9 += $x14;
$x4 = self::leftRotate(\intval($x4) ^ \intval($x9), 12);
$x3 += $x4;
$x14 = self::leftRotate(\intval($x14) ^ \intval($x3), 8);
$x9 += $x14;
$x4 = self::leftRotate(\intval($x4) ^ \intval($x9), 7);
// columnRound
$x0 += $x4;
$x12 = self::leftRotate(\intval($x12) ^ \intval($x0), 16);
$x8 += $x12;
$x4 = self::leftRotate(\intval($x4) ^ \intval($x8), 12);
$x0 += $x4;
$x12 = self::leftRotate(\intval($x12) ^ \intval($x0), 8);
$x8 += $x12;
$x4 = self::leftRotate(\intval($x4) ^ \intval($x8), 7);
$x1 += $x5;
$x13 = self::leftRotate(\intval($x13) ^ \intval($x1), 16);
$x9 += $x13;
$x5 = self::leftRotate(\intval($x5) ^ \intval($x9), 12);
$x1 += $x5;
$x13 = self::leftRotate(\intval($x13) ^ \intval($x1), 8);
$x9 += $x13;
$x5 = self::leftRotate(\intval($x5) ^ \intval($x9), 7);
$x2 += $x6;
$x14 = self::leftRotate(\intval($x14) ^ \intval($x2), 16);
$x10 += $x14;
$x6 = self::leftRotate(\intval($x6) ^ \intval($x10), 12);
$x2 += $x6;
$x14 = self::leftRotate(\intval($x14) ^ \intval($x2), 8);
$x10 += $x14;
$x6 = self::leftRotate(\intval($x6) ^ \intval($x10), 7);
$x3 += $x7;
$x15 = self::leftRotate(\intval($x15) ^ \intval($x3), 16);
$x11 += $x15;
$x7 = self::leftRotate(\intval($x7) ^ \intval($x11), 12);
$x3 += $x7;
$x15 = self::leftRotate(\intval($x15) ^ \intval($x3), 8);
$x11 += $x15;
$x7 = self::leftRotate(\intval($x7) ^ \intval($x11), 7);
// rowRound
$x0 += $x5;
$x15 = self::leftRotate(\intval($x15) ^ \intval($x0), 16);
$x10 += $x15;
$x5 = self::leftRotate(\intval($x5) ^ \intval($x10), 12);
$x0 += $x5;
$x15 = self::leftRotate(\intval($x15) ^ \intval($x0), 8);
$x10 += $x15;
$x5 = self::leftRotate(\intval($x5) ^ \intval($x10), 7);
$x1 += $x6;
$x12 = self::leftRotate(\intval($x12) ^ \intval($x1), 16);
$x11 += $x12;
$x6 = self::leftRotate(\intval($x6) ^ \intval($x11), 12);
$x1 += $x6;
$x12 = self::leftRotate(\intval($x12) ^ \intval($x1), 8);
$x11 += $x12;
$x6 = self::leftRotate(\intval($x6) ^ \intval($x11), 7);
$x2 += $x7;
$x13 = self::leftRotate(\intval($x13) ^ \intval($x2), 16);
$x8 += $x13;
$x7 = self::leftRotate(\intval($x7) ^ \intval($x8), 12);
$x2 += $x7;
$x13 = self::leftRotate(\intval($x13) ^ \intval($x2), 8);
$x8 += $x13;
$x7 = self::leftRotate(\intval($x7) ^ \intval($x8), 7);
$x3 += $x4;
$x14 = self::leftRotate(\intval($x14) ^ \intval($x3), 16);
$x9 += $x14;
$x4 = self::leftRotate(\intval($x4) ^ \intval($x9), 12);
$x3 += $x4;
$x14 = self::leftRotate(\intval($x14) ^ \intval($x3), 8);
$x9 += $x14;
$x4 = self::leftRotate(\intval($x4) ^ \intval($x9), 7);
// columnRound
$x0 += $x4;
$x12 = self::leftRotate(\intval($x12) ^ \intval($x0), 16);
$x8 += $x12;
$x4 = self::leftRotate(\intval($x4) ^ \intval($x8), 12);
$x0 += $x4;
$x12 = self::leftRotate(\intval($x12) ^ \intval($x0), 8);
$x8 += $x12;
$x4 = self::leftRotate(\intval($x4) ^ \intval($x8), 7);
$x1 += $x5;
$x13 = self::leftRotate(\intval($x13) ^ \intval($x1), 16);
$x9 += $x13;
$x5 = self::leftRotate(\intval($x5) ^ \intval($x9), 12);
$x1 += $x5;
$x13 = self::leftRotate(\intval($x13) ^ \intval($x1), 8);
$x9 += $x13;
$x5 = self::leftRotate(\intval($x5) ^ \intval($x9), 7);
$x2 += $x6;
$x14 = self::leftRotate(\intval($x14) ^ \intval($x2), 16);
$x10 += $x14;
$x6 = self::leftRotate(\intval($x6) ^ \intval($x10), 12);
$x2 += $x6;
$x14 = self::leftRotate(\intval($x14) ^ \intval($x2), 8);
$x10 += $x14;
$x6 = self::leftRotate(\intval($x6) ^ \intval($x10), 7);
$x3 += $x7;
$x15 = self::leftRotate(\intval($x15) ^ \intval($x3), 16);
$x11 += $x15;
$x7 = self::leftRotate(\intval($x7) ^ \intval($x11), 12);
$x3 += $x7;
$x15 = self::leftRotate(\intval($x15) ^ \intval($x3), 8);
$x11 += $x15;
$x7 = self::leftRotate(\intval($x7) ^ \intval($x11), 7);
// rowRound
$x0 += $x5;
$x15 = self::leftRotate(\intval($x15) ^ \intval($x0), 16);
$x10 += $x15;
$x5 = self::leftRotate(\intval($x5) ^ \intval($x10), 12);
$x0 += $x5;
$x15 = self::leftRotate(\intval($x15) ^ \intval($x0), 8);
$x10 += $x15;
$x5 = self::leftRotate(\intval($x5) ^ \intval($x10), 7);
$x1 += $x6;
$x12 = self::leftRotate(\intval($x12) ^ \intval($x1), 16);
$x11 += $x12;
$x6 = self::leftRotate(\intval($x6) ^ \intval($x11), 12);
$x1 += $x6;
$x12 = self::leftRotate(\intval($x12) ^ \intval($x1), 8);
$x11 += $x12;
$x6 = self::leftRotate(\intval($x6) ^ \intval($x11), 7);
$x2 += $x7;
$x13 = self::leftRotate(\intval($x13) ^ \intval($x2), 16);
$x8 += $x13;
$x7 = self::leftRotate(\intval($x7) ^ \intval($x8), 12);
$x2 += $x7;
$x13 = self::leftRotate(\intval($x13) ^ \intval($x2), 8);
$x8 += $x13;
$x7 = self::leftRotate(\intval($x7) ^ \intval($x8), 7);
$x3 += $x4;
$x14 = self::leftRotate(\intval($x14) ^ \intval($x3), 16);
$x9 += $x14;
$x4 = self::leftRotate(\intval($x4) ^ \intval($x9), 12);
$x3 += $x4;
$x14 = self::leftRotate(\intval($x14) ^ \intval($x3), 8);
$x9 += $x14;
$x4 = self::leftRotate(\intval($x4) ^ \intval($x9), 7);
// columnRound
$x0 += $x4;
$x12 = self::leftRotate(\intval($x12) ^ \intval($x0), 16);
$x8 += $x12;
$x4 = self::leftRotate(\intval($x4) ^ \intval($x8), 12);
$x0 += $x4;
$x12 = self::leftRotate(\intval($x12) ^ \intval($x0), 8);
$x8 += $x12;
$x4 = self::leftRotate(\intval($x4) ^ \intval($x8), 7);
$x1 += $x5;
$x13 = self::leftRotate(\intval($x13) ^ \intval($x1), 16);
$x9 += $x13;
$x5 = self::leftRotate(\intval($x5) ^ \intval($x9), 12);
$x1 += $x5;
$x13 = self::leftRotate(\intval($x13) ^ \intval($x1), 8);
$x9 += $x13;
$x5 = self::leftRotate(\intval($x5) ^ \intval($x9), 7);
$x2 += $x6;
$x14 = self::leftRotate(\intval($x14) ^ \intval($x2), 16);
$x10 += $x14;
$x6 = self::leftRotate(\intval($x6) ^ \intval($x10), 12);
$x2 += $x6;
$x14 = self::leftRotate(\intval($x14) ^ \intval($x2), 8);
$x10 += $x14;
$x6 = self::leftRotate(\intval($x6) ^ \intval($x10), 7);
$x3 += $x7;
$x15 = self::leftRotate(\intval($x15) ^ \intval($x3), 16);
$x11 += $x15;
$x7 = self::leftRotate(\intval($x7) ^ \intval($x11), 12);
$x3 += $x7;
$x15 = self::leftRotate(\intval($x15) ^ \intval($x3), 8);
$x11 += $x15;
$x7 = self::leftRotate(\intval($x7) ^ \intval($x11), 7);
// rowRound
$x0 += $x5;
$x15 = self::leftRotate(\intval($x15) ^ \intval($x0), 16);
$x10 += $x15;
$x5 = self::leftRotate(\intval($x5) ^ \intval($x10), 12);
$x0 += $x5;
$x15 = self::leftRotate(\intval($x15) ^ \intval($x0), 8);
$x10 += $x15;
$x5 = self::leftRotate(\intval($x5) ^ \intval($x10), 7);
$x1 += $x6;
$x12 = self::leftRotate(\intval($x12) ^ \intval($x1), 16);
$x11 += $x12;
$x6 = self::leftRotate(\intval($x6) ^ \intval($x11), 12);
$x1 += $x6;
$x12 = self::leftRotate(\intval($x12) ^ \intval($x1), 8);
$x11 += $x12;
$x6 = self::leftRotate(\intval($x6) ^ \intval($x11), 7);
$x2 += $x7;
$x13 = self::leftRotate(\intval($x13) ^ \intval($x2), 16);
$x8 += $x13;
$x7 = self::leftRotate(\intval($x7) ^ \intval($x8), 12);
$x2 += $x7;
$x13 = self::leftRotate(\intval($x13) ^ \intval($x2), 8);
$x8 += $x13;
$x7 = self::leftRotate(\intval($x7) ^ \intval($x8), 7);
$x3 += $x4;
$x14 = self::leftRotate(\intval($x14) ^ \intval($x3), 16);
$x9 += $x14;
$x4 = self::leftRotate(\intval($x4) ^ \intval($x9), 12);
$x3 += $x4;
$x14 = self::leftRotate(\intval($x14) ^ \intval($x3), 8);
$x9 += $x14;
$x4 = self::leftRotate(\intval($x4) ^ \intval($x9), 7);
// columnRound
$x0 += $x4;
$x12 = self::leftRotate(\intval($x12) ^ \intval($x0), 16);
$x8 += $x12;
$x4 = self::leftRotate(\intval($x4) ^ \intval($x8), 12);
$x0 += $x4;
$x12 = self::leftRotate(\intval($x12) ^ \intval($x0), 8);
$x8 += $x12;
$x4 = self::leftRotate(\intval($x4) ^ \intval($x8), 7);
$x1 += $x5;
$x13 = self::leftRotate(\intval($x13) ^ \intval($x1), 16);
$x9 += $x13;
$x5 = self::leftRotate(\intval($x5) ^ \intval($x9), 12);
$x1 += $x5;
$x13 = self::leftRotate(\intval($x13) ^ \intval($x1), 8);
$x9 += $x13;
$x5 = self::leftRotate(\intval($x5) ^ \intval($x9), 7);
$x2 += $x6;
$x14 = self::leftRotate(\intval($x14) ^ \intval($x2), 16);
$x10 += $x14;
$x6 = self::leftRotate(\intval($x6) ^ \intval($x10), 12);
$x2 += $x6;
$x14 = self::leftRotate(\intval($x14) ^ \intval($x2), 8);
$x10 += $x14;
$x6 = self::leftRotate(\intval($x6) ^ \intval($x10), 7);
$x3 += $x7;
$x15 = self::leftRotate(\intval($x15) ^ \intval($x3), 16);
$x11 += $x15;
$x7 = self::leftRotate(\intval($x7) ^ \intval($x11), 12);
$x3 += $x7;
$x15 = self::leftRotate(\intval($x15) ^ \intval($x3), 8);
$x11 += $x15;
$x7 = self::leftRotate(\intval($x7) ^ \intval($x11), 7);
// rowRound
$x0 += $x5;
$x15 = self::leftRotate(\intval($x15) ^ \intval($x0), 16);
$x10 += $x15;
$x5 = self::leftRotate(\intval($x5) ^ \intval($x10), 12);
$x0 += $x5;
$x15 = self::leftRotate(\intval($x15) ^ \intval($x0), 8);
$x10 += $x15;
$x5 = self::leftRotate(\intval($x5) ^ \intval($x10), 7);
$x1 += $x6;
$x12 = self::leftRotate(\intval($x12) ^ \intval($x1), 16);
$x11 += $x12;
$x6 = self::leftRotate(\intval($x6) ^ \intval($x11), 12);
$x1 += $x6;
$x12 = self::leftRotate(\intval($x12) ^ \intval($x1), 8);
$x11 += $x12;
$x6 = self::leftRotate(\intval($x6) ^ \intval($x11), 7);
$x2 += $x7;
$x13 = self::leftRotate(\intval($x13) ^ \intval($x2), 16);
$x8 += $x13;
$x7 = self::leftRotate(\intval($x7) ^ \intval($x8), 12);
$x2 += $x7;
$x13 = self::leftRotate(\intval($x13) ^ \intval($x2), 8);
$x8 += $x13;
$x7 = self::leftRotate(\intval($x7) ^ \intval($x8), 7);
$x3 += $x4;
$x14 = self::leftRotate(\intval($x14) ^ \intval($x3), 16);
$x9 += $x14;
$x4 = self::leftRotate(\intval($x4) ^ \intval($x9), 12);
$x3 += $x4;
$x14 = self::leftRotate(\intval($x14) ^ \intval($x3), 8);
$x9 += $x14;
$x4 = self::leftRotate(\intval($x4) ^ \intval($x9), 7);
// @codingStandardsIgnoreEnd
$x0 += $z0;
$x1 += $z1;
$x2 += $z2;
$x3 += $z3;
$x4 += $z4;
$x5 += $z5;
$x6 += $z6;
$x7 += $z7;
$x8 += $z8;
$x9 += $z9;
$x10 += $z10;
$x11 += $z11;
$x12 += $z12;
$x13 += $z13;
$x14 += $z14;
$x15 += $z15;
return \pack('V*', $x0, $x1, $x2, $x3, $x4, $x5, $x6, $x7, $x8, $x9, $x10, $x11, $x12, $x13, $x14, $x15);
}
}

View File

@@ -0,0 +1,511 @@
<?php
/**
* Base Class for all asymmetric key ciphers
*
* PHP version 5
*
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2016 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net
*/
namespace VendorDuplicator\phpseclib3\Crypt\Common;
use VendorDuplicator\phpseclib3\Crypt\DSA;
use VendorDuplicator\phpseclib3\Crypt\Hash;
use VendorDuplicator\phpseclib3\Crypt\RSA;
use VendorDuplicator\phpseclib3\Exception\NoKeyLoadedException;
use VendorDuplicator\phpseclib3\Exception\UnsupportedFormatException;
use VendorDuplicator\phpseclib3\Math\BigInteger;
/**
* Base Class for all asymmetric cipher classes
*
* @author Jim Wigginton <terrafrost@php.net>
*/
abstract class AsymmetricKey
{
/**
* Precomputed Zero
*
* @var \VendorDuplicator\phpseclib3\Math\BigInteger
*/
protected static $zero;
/**
* Precomputed One
*
* @var \VendorDuplicator\phpseclib3\Math\BigInteger
*/
protected static $one;
/**
* Format of the loaded key
*
* @var string
*/
protected $format;
/**
* Hash function
*
* @var \VendorDuplicator\phpseclib3\Crypt\Hash
*/
protected $hash;
/**
* HMAC function
*
* @var \VendorDuplicator\phpseclib3\Crypt\Hash
*/
private $hmac;
/**
* Supported plugins (lower case)
*
* @see self::initialize_static_variables()
* @var array
*/
private static $plugins = [];
/**
* Invisible plugins
*
* @see self::initialize_static_variables()
* @var array
*/
private static $invisiblePlugins = [];
/**
* Available Engines
*
* @var boolean[]
*/
protected static $engines = [];
/**
* Key Comment
*
* @var null|string
*/
private $comment;
/**
* @param string $type
* @return string
*/
public abstract function toString($type, array $options = []);
/**
* The constructor
*/
protected function __construct()
{
self::initialize_static_variables();
$this->hash = new Hash('sha256');
$this->hmac = new Hash('sha256');
}
/**
* Initialize static variables
*/
protected static function initialize_static_variables()
{
if (!isset(self::$zero)) {
self::$zero = new BigInteger(0);
self::$one = new BigInteger(1);
}
self::loadPlugins('Keys');
if (static::ALGORITHM != 'RSA' && static::ALGORITHM != 'DH') {
self::loadPlugins('Signature');
}
}
/**
* Load the key
*
* @param string $key
* @param string $password optional
* @return \VendorDuplicator\phpseclib3\Crypt\Common\PublicKey|\phpseclib3\Crypt\Common\PrivateKey
*/
public static function load($key, $password = \false)
{
self::initialize_static_variables();
$class = new \ReflectionClass(static::class);
if ($class->isFinal()) {
throw new \RuntimeException('load() should not be called from final classes (' . static::class . ')');
}
$components = \false;
foreach (self::$plugins[static::ALGORITHM]['Keys'] as $format) {
if (isset(self::$invisiblePlugins[static::ALGORITHM]) && \in_array($format, self::$invisiblePlugins[static::ALGORITHM])) {
continue;
}
try {
$components = $format::load($key, $password);
} catch (\Exception $e) {
$components = \false;
}
if ($components !== \false) {
break;
}
}
if ($components === \false) {
throw new NoKeyLoadedException('Unable to read key');
}
$components['format'] = $format;
$components['secret'] = isset($components['secret']) ? $components['secret'] : '';
$comment = isset($components['comment']) ? $components['comment'] : null;
$new = static::onLoad($components);
$new->format = $format;
$new->comment = $comment;
return $new instanceof PrivateKey ? $new->withPassword($password) : $new;
}
/**
* Loads a private key
*
* @return PrivateKey
* @param string|array $key
* @param string $password optional
*/
public static function loadPrivateKey($key, $password = '')
{
$key = self::load($key, $password);
if (!$key instanceof PrivateKey) {
throw new NoKeyLoadedException('The key that was loaded was not a private key');
}
return $key;
}
/**
* Loads a public key
*
* @return PublicKey
* @param string|array $key
*/
public static function loadPublicKey($key)
{
$key = self::load($key);
if (!$key instanceof PublicKey) {
throw new NoKeyLoadedException('The key that was loaded was not a public key');
}
return $key;
}
/**
* Loads parameters
*
* @return AsymmetricKey
* @param string|array $key
*/
public static function loadParameters($key)
{
$key = self::load($key);
if (!$key instanceof PrivateKey && !$key instanceof PublicKey) {
throw new NoKeyLoadedException('The key that was loaded was not a parameter');
}
return $key;
}
/**
* Load the key, assuming a specific format
*
* @param string $type
* @param string $key
* @param string $password optional
* @return static
*/
public static function loadFormat($type, $key, $password = \false)
{
self::initialize_static_variables();
$components = \false;
$format = \strtolower($type);
if (isset(self::$plugins[static::ALGORITHM]['Keys'][$format])) {
$format = self::$plugins[static::ALGORITHM]['Keys'][$format];
$components = $format::load($key, $password);
}
if ($components === \false) {
throw new NoKeyLoadedException('Unable to read key');
}
$components['format'] = $format;
$components['secret'] = isset($components['secret']) ? $components['secret'] : '';
$new = static::onLoad($components);
$new->format = $format;
return $new instanceof PrivateKey ? $new->withPassword($password) : $new;
}
/**
* Loads a private key
*
* @return PrivateKey
* @param string $type
* @param string $key
* @param string $password optional
*/
public static function loadPrivateKeyFormat($type, $key, $password = \false)
{
$key = self::loadFormat($type, $key, $password);
if (!$key instanceof PrivateKey) {
throw new NoKeyLoadedException('The key that was loaded was not a private key');
}
return $key;
}
/**
* Loads a public key
*
* @return PublicKey
* @param string $type
* @param string $key
*/
public static function loadPublicKeyFormat($type, $key)
{
$key = self::loadFormat($type, $key);
if (!$key instanceof PublicKey) {
throw new NoKeyLoadedException('The key that was loaded was not a public key');
}
return $key;
}
/**
* Loads parameters
*
* @return AsymmetricKey
* @param string $type
* @param string|array $key
*/
public static function loadParametersFormat($type, $key)
{
$key = self::loadFormat($type, $key);
if (!$key instanceof PrivateKey && !$key instanceof PublicKey) {
throw new NoKeyLoadedException('The key that was loaded was not a parameter');
}
return $key;
}
/**
* Validate Plugin
*
* @param string $format
* @param string $type
* @param string $method optional
* @return mixed
*/
protected static function validatePlugin($format, $type, $method = null)
{
$type = \strtolower($type);
if (!isset(self::$plugins[static::ALGORITHM][$format][$type])) {
throw new UnsupportedFormatException("{$type} is not a supported format");
}
$type = self::$plugins[static::ALGORITHM][$format][$type];
if (isset($method) && !\method_exists($type, $method)) {
throw new UnsupportedFormatException("{$type} does not implement {$method}");
}
return $type;
}
/**
* Load Plugins
*
* @param string $format
*/
private static function loadPlugins($format)
{
if (!isset(self::$plugins[static::ALGORITHM][$format])) {
self::$plugins[static::ALGORITHM][$format] = [];
foreach (new \DirectoryIterator(__DIR__ . '/../' . static::ALGORITHM . '/Formats/' . $format . '/') as $file) {
if ($file->getExtension() != 'php') {
continue;
}
$name = $file->getBasename('.php');
if ($name[0] == '.') {
continue;
}
$type = 'VendorDuplicator\\phpseclib3\\Crypt\\' . static::ALGORITHM . '\\Formats\\' . $format . '\\' . $name;
$reflect = new \ReflectionClass($type);
if ($reflect->isTrait()) {
continue;
}
self::$plugins[static::ALGORITHM][$format][\strtolower($name)] = $type;
if ($reflect->hasConstant('IS_INVISIBLE')) {
self::$invisiblePlugins[static::ALGORITHM][] = $type;
}
}
}
}
/**
* Returns a list of supported formats.
*
* @return array
*/
public static function getSupportedKeyFormats()
{
self::initialize_static_variables();
return self::$plugins[static::ALGORITHM]['Keys'];
}
/**
* Add a fileformat plugin
*
* The plugin needs to either already be loaded or be auto-loadable.
* Loading a plugin whose shortname overwrite an existing shortname will overwrite the old plugin.
*
* @see self::load()
* @param string $fullname
* @return bool
*/
public static function addFileFormat($fullname)
{
self::initialize_static_variables();
if (\class_exists($fullname)) {
$meta = new \ReflectionClass($fullname);
$shortname = $meta->getShortName();
self::$plugins[static::ALGORITHM]['Keys'][\strtolower($shortname)] = $fullname;
if ($meta->hasConstant('IS_INVISIBLE')) {
self::$invisiblePlugins[static::ALGORITHM] = \strtolower($name);
}
}
}
/**
* Returns the format of the loaded key.
*
* If the key that was loaded wasn't in a valid or if the key was auto-generated
* with RSA::createKey() then this will throw an exception.
*
* @see self::load()
* @return mixed
*/
public function getLoadedFormat()
{
if (empty($this->format)) {
throw new NoKeyLoadedException('This key was created with createKey - it was not loaded with load. Therefore there is no "loaded format"');
}
$meta = new \ReflectionClass($this->format);
return $meta->getShortName();
}
/**
* Returns the key's comment
*
* Not all key formats support comments. If you want to set a comment use toString()
*
* @return null|string
*/
public function getComment()
{
return $this->comment;
}
/**
* Tests engine validity
*
*/
public static function useBestEngine()
{
static::$engines = [
'PHP' => \true,
'OpenSSL' => \extension_loaded('openssl'),
// this test can be satisfied by either of the following:
// http://php.net/manual/en/book.sodium.php
// https://github.com/paragonie/sodium_compat
'libsodium' => \function_exists('sodium_crypto_sign_keypair'),
];
return static::$engines;
}
/**
* Flag to use internal engine only (useful for unit testing)
*
*/
public static function useInternalEngine()
{
static::$engines = ['PHP' => \true, 'OpenSSL' => \false, 'libsodium' => \false];
}
/**
* __toString() magic method
*
* @return string
*/
public function __toString()
{
return $this->toString('PKCS8');
}
/**
* Determines which hashing function should be used
*
* @param string $hash
*/
public function withHash($hash)
{
$new = clone $this;
$new->hash = new Hash($hash);
$new->hmac = new Hash($hash);
return $new;
}
/**
* Returns the hash algorithm currently being used
*
*/
public function getHash()
{
return clone $this->hash;
}
/**
* Compute the pseudorandom k for signature generation,
* using the process specified for deterministic DSA.
*
* @param string $h1
* @return string
*/
protected function computek($h1)
{
$v = \str_repeat("\x01", \strlen($h1));
$k = \str_repeat("\x00", \strlen($h1));
$x = $this->int2octets($this->x);
$h1 = $this->bits2octets($h1);
$this->hmac->setKey($k);
$k = $this->hmac->hash($v . "\x00" . $x . $h1);
$this->hmac->setKey($k);
$v = $this->hmac->hash($v);
$k = $this->hmac->hash($v . "\x01" . $x . $h1);
$this->hmac->setKey($k);
$v = $this->hmac->hash($v);
$qlen = $this->q->getLengthInBytes();
while (\true) {
$t = '';
while (\strlen($t) < $qlen) {
$v = $this->hmac->hash($v);
$t = $t . $v;
}
$k = $this->bits2int($t);
if (!$k->equals(self::$zero) && $k->compare($this->q) < 0) {
break;
}
$k = $this->hmac->hash($v . "\x00");
$this->hmac->setKey($k);
$v = $this->hmac->hash($v);
}
return $k;
}
/**
* Integer to Octet String
*
* @param \VendorDuplicator\phpseclib3\Math\BigInteger $v
* @return string
*/
private function int2octets($v)
{
$out = $v->toBytes();
$rolen = $this->q->getLengthInBytes();
if (\strlen($out) < $rolen) {
return \str_pad($out, $rolen, "\x00", \STR_PAD_LEFT);
} elseif (\strlen($out) > $rolen) {
return \substr($out, -$rolen);
} else {
return $out;
}
}
/**
* Bit String to Integer
*
* @param string $in
* @return \VendorDuplicator\phpseclib3\Math\BigInteger
*/
protected function bits2int($in)
{
$v = new BigInteger($in, 256);
$vlen = \strlen($in) << 3;
$qlen = $this->q->getLength();
if ($vlen > $qlen) {
return $v->bitwise_rightShift($vlen - $qlen);
}
return $v;
}
/**
* Bit String to Octet String
*
* @param string $in
* @return string
*/
private function bits2octets($in)
{
$z1 = $this->bits2int($in);
$z2 = $z1->subtract($this->q);
return $z2->compare(self::$zero) < 0 ? $this->int2octets($z1) : $this->int2octets($z2);
}
}

View File

@@ -0,0 +1,23 @@
<?php
/**
* Base Class for all block ciphers
*
* PHP version 5
*
* @author Jim Wigginton <terrafrost@php.net>
* @author Hans-Juergen Petrich <petrich@tronic-media.com>
* @copyright 2007 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net
*/
namespace VendorDuplicator\phpseclib3\Crypt\Common;
/**
* Base Class for all block cipher classes
*
* @author Jim Wigginton <terrafrost@php.net>
*/
abstract class BlockCipher extends SymmetricKey
{
}

View File

@@ -0,0 +1,62 @@
<?php
/**
* JSON Web Key (RFC7517) Handler
*
* PHP version 5
*
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2015 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net
*/
namespace VendorDuplicator\phpseclib3\Crypt\Common\Formats\Keys;
use VendorDuplicator\phpseclib3\Common\Functions\Strings;
/**
* JSON Web Key Formatted Key Handler
*
* @author Jim Wigginton <terrafrost@php.net>
*/
abstract class JWK
{
/**
* Break a public or private key down into its constituent components
*
* @param string $key
* @param string $password
* @return array
*/
public static function load($key, $password = '')
{
if (!Strings::is_stringable($key)) {
throw new \UnexpectedValueException('Key should be a string - not a ' . \gettype($key));
}
$key = \preg_replace('#\\s#', '', $key);
// remove whitespace
if (\PHP_VERSION_ID >= 73000) {
$key = \json_decode($key, null, 512, \JSON_THROW_ON_ERROR);
} else {
$key = \json_decode($key);
if (!$key) {
throw new \RuntimeException('Unable to decode JSON');
}
}
if (isset($key->kty)) {
return $key;
}
if (\count($key->keys) != 1) {
throw new \RuntimeException('Although the JWK key format supports multiple keys phpseclib does not');
}
return $key->keys[0];
}
/**
* Wrap a key appropriately
*
* @return string
*/
protected static function wrapKey(array $key, array $options)
{
return \json_encode(['keys' => [$key + $options]]);
}
}

View File

@@ -0,0 +1,195 @@
<?php
/**
* OpenSSH Key Handler
*
* PHP version 5
*
* Place in $HOME/.ssh/authorized_keys
*
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2015 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net
*/
namespace VendorDuplicator\phpseclib3\Crypt\Common\Formats\Keys;
use VendorDuplicator\phpseclib3\Common\Functions\Strings;
use VendorDuplicator\phpseclib3\Crypt\AES;
use VendorDuplicator\phpseclib3\Crypt\Random;
/**
* OpenSSH Formatted RSA Key Handler
*
* @author Jim Wigginton <terrafrost@php.net>
*/
abstract class OpenSSH
{
/**
* Default comment
*
* @var string
*/
protected static $comment = 'phpseclib-generated-key';
/**
* Binary key flag
*
* @var bool
*/
protected static $binary = \false;
/**
* Sets the default comment
*
* @param string $comment
*/
public static function setComment($comment)
{
self::$comment = \str_replace(["\r", "\n"], '', $comment);
}
/**
* Break a public or private key down into its constituent components
*
* $type can be either ssh-dss or ssh-rsa
*
* @param string $key
* @param string $password
* @return array
*/
public static function load($key, $password = '')
{
if (!Strings::is_stringable($key)) {
throw new \UnexpectedValueException('Key should be a string - not a ' . \gettype($key));
}
// key format is described here:
// https://cvsweb.openbsd.org/cgi-bin/cvsweb/src/usr.bin/ssh/PROTOCOL.key?annotate=HEAD
if (\strpos($key, 'BEGIN OPENSSH PRIVATE KEY') !== \false) {
$key = \preg_replace('#(?:^-.*?-[\\r\\n]*$)|\\s#ms', '', $key);
$key = Strings::base64_decode($key);
$magic = Strings::shift($key, 15);
if ($magic != "openssh-key-v1\x00") {
throw new \RuntimeException('Expected openssh-key-v1');
}
list($ciphername, $kdfname, $kdfoptions, $numKeys) = Strings::unpackSSH2('sssN', $key);
if ($numKeys != 1) {
// if we wanted to support multiple keys we could update PublicKeyLoader to preview what the # of keys
// would be; it'd then call Common\Keys\OpenSSH.php::load() and get the paddedKey. it'd then pass
// that to the appropriate key loading parser $numKey times or something
throw new \RuntimeException('Although the OpenSSH private key format supports multiple keys phpseclib does not');
}
switch ($ciphername) {
case 'none':
break;
case 'aes256-ctr':
if ($kdfname != 'bcrypt') {
throw new \RuntimeException('Only the bcrypt kdf is supported (' . $kdfname . ' encountered)');
}
list($salt, $rounds) = Strings::unpackSSH2('sN', $kdfoptions);
$crypto = new AES('ctr');
//$crypto->setKeyLength(256);
//$crypto->disablePadding();
$crypto->setPassword($password, 'bcrypt', $salt, $rounds, 32);
break;
default:
throw new \RuntimeException('The only supported cipherse are: none, aes256-ctr (' . $ciphername . ' is being used)');
}
list($publicKey, $paddedKey) = Strings::unpackSSH2('ss', $key);
list($type) = Strings::unpackSSH2('s', $publicKey);
if (isset($crypto)) {
$paddedKey = $crypto->decrypt($paddedKey);
}
list($checkint1, $checkint2) = Strings::unpackSSH2('NN', $paddedKey);
// any leftover bytes in $paddedKey are for padding? but they should be sequential bytes. eg. 1, 2, 3, etc.
if ($checkint1 != $checkint2) {
throw new \RuntimeException('The two checkints do not match');
}
self::checkType($type);
return \compact('type', 'publicKey', 'paddedKey');
}
$parts = \explode(' ', $key, 3);
if (!isset($parts[1])) {
$key = \base64_decode($parts[0]);
$comment = \false;
} else {
$asciiType = $parts[0];
self::checkType($parts[0]);
$key = \base64_decode($parts[1]);
$comment = isset($parts[2]) ? $parts[2] : \false;
}
if ($key === \false) {
throw new \UnexpectedValueException('Key should be a string - not a ' . \gettype($key));
}
list($type) = Strings::unpackSSH2('s', $key);
self::checkType($type);
if (isset($asciiType) && $asciiType != $type) {
throw new \RuntimeException('Two different types of keys are claimed: ' . $asciiType . ' and ' . $type);
}
if (\strlen($key) <= 4) {
throw new \UnexpectedValueException('Key appears to be malformed');
}
$publicKey = $key;
return \compact('type', 'publicKey', 'comment');
}
/**
* Toggle between binary and printable keys
*
* Printable keys are what are generated by default. These are the ones that go in
* $HOME/.ssh/authorized_key.
*
* @param bool $enabled
*/
public static function setBinaryOutput($enabled)
{
self::$binary = $enabled;
}
/**
* Checks to see if the type is valid
*
* @param string $candidate
*/
private static function checkType($candidate)
{
if (!\in_array($candidate, static::$types)) {
throw new \RuntimeException("The key type ({$candidate}) is not equal to: " . \implode(',', static::$types));
}
}
/**
* Wrap a private key appropriately
*
* @param string $publicKey
* @param string $privateKey
* @param string $password
* @param array $options
* @return string
*/
protected static function wrapPrivateKey($publicKey, $privateKey, $password, $options)
{
list(, $checkint) = \unpack('N', Random::string(4));
$comment = isset($options['comment']) ? $options['comment'] : self::$comment;
$paddedKey = Strings::packSSH2('NN', $checkint, $checkint) . $privateKey . Strings::packSSH2('s', $comment);
$usesEncryption = !empty($password) && \is_string($password);
/*
from http://tools.ietf.org/html/rfc4253#section-6 :
Note that the length of the concatenation of 'packet_length',
'padding_length', 'payload', and 'random padding' MUST be a multiple
of the cipher block size or 8, whichever is larger.
*/
$blockSize = $usesEncryption ? 16 : 8;
$paddingLength = ($blockSize - 1) * \strlen($paddedKey) % $blockSize;
for ($i = 1; $i <= $paddingLength; $i++) {
$paddedKey .= \chr($i);
}
if (!$usesEncryption) {
$key = Strings::packSSH2('sssNss', 'none', 'none', '', 1, $publicKey, $paddedKey);
} else {
$rounds = isset($options['rounds']) ? $options['rounds'] : 16;
$salt = Random::string(16);
$kdfoptions = Strings::packSSH2('sN', $salt, $rounds);
$crypto = new AES('ctr');
$crypto->setPassword($password, 'bcrypt', $salt, $rounds, 32);
$paddedKey = $crypto->encrypt($paddedKey);
$key = Strings::packSSH2('sssNss', 'aes256-ctr', 'bcrypt', $kdfoptions, 1, $publicKey, $paddedKey);
}
$key = "openssh-key-v1\x00{$key}";
return "-----BEGIN OPENSSH PRIVATE KEY-----\n" . \chunk_split(Strings::base64_encode($key), 70, "\n") . "-----END OPENSSH PRIVATE KEY-----\n";
}
}

View File

@@ -0,0 +1,67 @@
<?php
/**
* PKCS Formatted Key Handler
*
* PHP version 5
*
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2015 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net
*/
namespace VendorDuplicator\phpseclib3\Crypt\Common\Formats\Keys;
/**
* PKCS1 Formatted Key Handler
*
* @author Jim Wigginton <terrafrost@php.net>
*/
abstract class PKCS
{
/**
* Auto-detect the format
*/
const MODE_ANY = 0;
/**
* Require base64-encoded PEM's be supplied
*/
const MODE_PEM = 1;
/**
* Require raw DER's be supplied
*/
const MODE_DER = 2;
/**#@-*/
/**
* Is the key a base-64 encoded PEM, DER or should it be auto-detected?
*
* @var int
*/
protected static $format = self::MODE_ANY;
/**
* Require base64-encoded PEM's be supplied
*
*/
public static function requirePEM()
{
self::$format = self::MODE_PEM;
}
/**
* Require raw DER's be supplied
*
*/
public static function requireDER()
{
self::$format = self::MODE_DER;
}
/**
* Accept any format and auto detect the format
*
* This is the default setting
*
*/
public static function requireAny()
{
self::$format = self::MODE_ANY;
}
}

View File

@@ -0,0 +1,187 @@
<?php
/**
* PKCS1 Formatted Key Handler
*
* PHP version 5
*
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2015 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net
*/
namespace VendorDuplicator\phpseclib3\Crypt\Common\Formats\Keys;
use VendorDuplicator\phpseclib3\Common\Functions\Strings;
use VendorDuplicator\phpseclib3\Crypt\AES;
use VendorDuplicator\phpseclib3\Crypt\DES;
use VendorDuplicator\phpseclib3\Crypt\Random;
use VendorDuplicator\phpseclib3\Crypt\TripleDES;
use VendorDuplicator\phpseclib3\Exception\UnsupportedAlgorithmException;
use VendorDuplicator\phpseclib3\File\ASN1;
/**
* PKCS1 Formatted Key Handler
*
* @author Jim Wigginton <terrafrost@php.net>
*/
abstract class PKCS1 extends PKCS
{
/**
* Default encryption algorithm
*
* @var string
*/
private static $defaultEncryptionAlgorithm = 'AES-128-CBC';
/**
* Sets the default encryption algorithm
*
* @param string $algo
*/
public static function setEncryptionAlgorithm($algo)
{
self::$defaultEncryptionAlgorithm = $algo;
}
/**
* Returns the mode constant corresponding to the mode string
*
* @param string $mode
* @return int
* @throws \UnexpectedValueException if the block cipher mode is unsupported
*/
private static function getEncryptionMode($mode)
{
switch ($mode) {
case 'CBC':
case 'ECB':
case 'CFB':
case 'OFB':
case 'CTR':
return $mode;
}
throw new \UnexpectedValueException('Unsupported block cipher mode of operation');
}
/**
* Returns a cipher object corresponding to a string
*
* @param string $algo
* @return string
* @throws \UnexpectedValueException if the encryption algorithm is unsupported
*/
private static function getEncryptionObject($algo)
{
$modes = '(CBC|ECB|CFB|OFB|CTR)';
switch (\true) {
case \preg_match("#^AES-(128|192|256)-{$modes}\$#", $algo, $matches):
$cipher = new AES(self::getEncryptionMode($matches[2]));
$cipher->setKeyLength($matches[1]);
return $cipher;
case \preg_match("#^DES-EDE3-{$modes}\$#", $algo, $matches):
return new TripleDES(self::getEncryptionMode($matches[1]));
case \preg_match("#^DES-{$modes}\$#", $algo, $matches):
return new DES(self::getEncryptionMode($matches[1]));
default:
throw new UnsupportedAlgorithmException($algo . ' is not a supported algorithm');
}
}
/**
* Generate a symmetric key for PKCS#1 keys
*
* @param string $password
* @param string $iv
* @param int $length
* @return string
*/
private static function generateSymmetricKey($password, $iv, $length)
{
$symkey = '';
$iv = \substr($iv, 0, 8);
while (\strlen($symkey) < $length) {
$symkey .= \md5($symkey . $password . $iv, \true);
}
return \substr($symkey, 0, $length);
}
/**
* Break a public or private key down into its constituent components
*
* @param string $key
* @param string $password optional
* @return array
*/
protected static function load($key, $password)
{
if (!Strings::is_stringable($key)) {
throw new \UnexpectedValueException('Key should be a string - not a ' . \gettype($key));
}
/* Although PKCS#1 proposes a format that public and private keys can use, encrypting them is
"outside the scope" of PKCS#1. PKCS#1 then refers you to PKCS#12 and PKCS#15 if you're wanting to
protect private keys, however, that's not what OpenSSL* does. OpenSSL protects private keys by adding
two new "fields" to the key - DEK-Info and Proc-Type. These fields are discussed here:
http://tools.ietf.org/html/rfc1421#section-4.6.1.1
http://tools.ietf.org/html/rfc1421#section-4.6.1.3
DES-EDE3-CBC as an algorithm, however, is not discussed anywhere, near as I can tell.
DES-CBC and DES-EDE are discussed in RFC1423, however, DES-EDE3-CBC isn't, nor is its key derivation
function. As is, the definitive authority on this encoding scheme isn't the IETF but rather OpenSSL's
own implementation. ie. the implementation *is* the standard and any bugs that may exist in that
implementation are part of the standard, as well.
* OpenSSL is the de facto standard. It's utilized by OpenSSH and other projects */
if (\preg_match('#DEK-Info: (.+),(.+)#', $key, $matches)) {
$iv = Strings::hex2bin(\trim($matches[2]));
// remove the Proc-Type / DEK-Info sections as they're no longer needed
$key = \preg_replace('#^(?:Proc-Type|DEK-Info): .*#m', '', $key);
$ciphertext = ASN1::extractBER($key);
if ($ciphertext === \false) {
$ciphertext = $key;
}
$crypto = self::getEncryptionObject($matches[1]);
$crypto->setKey(self::generateSymmetricKey($password, $iv, $crypto->getKeyLength() >> 3));
$crypto->setIV($iv);
$key = $crypto->decrypt($ciphertext);
} else {
if (self::$format != self::MODE_DER) {
$decoded = ASN1::extractBER($key);
if ($decoded !== \false) {
$key = $decoded;
} elseif (self::$format == self::MODE_PEM) {
throw new \UnexpectedValueException('Expected base64-encoded PEM format but was unable to decode base64 text');
}
}
}
return $key;
}
/**
* Wrap a private key appropriately
*
* @param string $key
* @param string $type
* @param string $password
* @param array $options optional
* @return string
*/
protected static function wrapPrivateKey($key, $type, $password, array $options = [])
{
if (empty($password) || !\is_string($password)) {
return "-----BEGIN {$type} PRIVATE KEY-----\r\n" . \chunk_split(Strings::base64_encode($key), 64) . "-----END {$type} PRIVATE KEY-----";
}
$encryptionAlgorithm = isset($options['encryptionAlgorithm']) ? $options['encryptionAlgorithm'] : self::$defaultEncryptionAlgorithm;
$cipher = self::getEncryptionObject($encryptionAlgorithm);
$iv = Random::string($cipher->getBlockLength() >> 3);
$cipher->setKey(self::generateSymmetricKey($password, $iv, $cipher->getKeyLength() >> 3));
$cipher->setIV($iv);
$iv = \strtoupper(Strings::bin2hex($iv));
return "-----BEGIN {$type} PRIVATE KEY-----\r\n" . "Proc-Type: 4,ENCRYPTED\r\n" . "DEK-Info: " . $encryptionAlgorithm . ",{$iv}\r\n" . "\r\n" . \chunk_split(Strings::base64_encode($cipher->encrypt($key)), 64) . "-----END {$type} PRIVATE KEY-----";
}
/**
* Wrap a public key appropriately
*
* @param string $key
* @param string $type
* @return string
*/
protected static function wrapPublicKey($key, $type)
{
return "-----BEGIN {$type} PUBLIC KEY-----\r\n" . \chunk_split(Strings::base64_encode($key), 64) . "-----END {$type} PUBLIC KEY-----";
}
}

View File

@@ -0,0 +1,599 @@
<?php
/**
* PKCS#8 Formatted Key Handler
*
* PHP version 5
*
* Used by PHP's openssl_public_encrypt() and openssl's rsautl (when -pubin is set)
*
* Processes keys with the following headers:
*
* -----BEGIN ENCRYPTED PRIVATE KEY-----
* -----BEGIN PRIVATE KEY-----
* -----BEGIN PUBLIC KEY-----
*
* Analogous to ssh-keygen's pkcs8 format (as specified by -m). Although PKCS8
* is specific to private keys it's basically creating a DER-encoded wrapper
* for keys. This just extends that same concept to public keys (much like ssh-keygen)
*
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2015 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net
*/
namespace VendorDuplicator\phpseclib3\Crypt\Common\Formats\Keys;
use VendorDuplicator\phpseclib3\Common\Functions\Strings;
use VendorDuplicator\phpseclib3\Crypt\AES;
use VendorDuplicator\phpseclib3\Crypt\DES;
use VendorDuplicator\phpseclib3\Crypt\Random;
use VendorDuplicator\phpseclib3\Crypt\RC2;
use VendorDuplicator\phpseclib3\Crypt\RC4;
use VendorDuplicator\phpseclib3\Crypt\TripleDES;
use VendorDuplicator\phpseclib3\Exception\InsufficientSetupException;
use VendorDuplicator\phpseclib3\Exception\UnsupportedAlgorithmException;
use VendorDuplicator\phpseclib3\File\ASN1;
use VendorDuplicator\phpseclib3\File\ASN1\Maps;
/**
* PKCS#8 Formatted Key Handler
*
* @author Jim Wigginton <terrafrost@php.net>
*/
abstract class PKCS8 extends PKCS
{
/**
* Default encryption algorithm
*
* @var string
*/
private static $defaultEncryptionAlgorithm = 'id-PBES2';
/**
* Default encryption scheme
*
* Only used when defaultEncryptionAlgorithm is id-PBES2
*
* @var string
*/
private static $defaultEncryptionScheme = 'aes128-CBC-PAD';
/**
* Default PRF
*
* Only used when defaultEncryptionAlgorithm is id-PBES2
*
* @var string
*/
private static $defaultPRF = 'id-hmacWithSHA256';
/**
* Default Iteration Count
*
* @var int
*/
private static $defaultIterationCount = 2048;
/**
* OIDs loaded
*
* @var bool
*/
private static $oidsLoaded = \false;
/**
* Sets the default encryption algorithm
*
* @param string $algo
*/
public static function setEncryptionAlgorithm($algo)
{
self::$defaultEncryptionAlgorithm = $algo;
}
/**
* Sets the default encryption algorithm for PBES2
*
* @param string $algo
*/
public static function setEncryptionScheme($algo)
{
self::$defaultEncryptionScheme = $algo;
}
/**
* Sets the iteration count
*
* @param int $count
*/
public static function setIterationCount($count)
{
self::$defaultIterationCount = $count;
}
/**
* Sets the PRF for PBES2
*
* @param string $algo
*/
public static function setPRF($algo)
{
self::$defaultPRF = $algo;
}
/**
* Returns a SymmetricKey object based on a PBES1 $algo
*
* @return \VendorDuplicator\phpseclib3\Crypt\Common\SymmetricKey
* @param string $algo
*/
private static function getPBES1EncryptionObject($algo)
{
$algo = \preg_match('#^pbeWith(?:MD2|MD5|SHA1|SHA)And(.*?)-CBC$#', $algo, $matches) ? $matches[1] : \substr($algo, 13);
// strlen('pbeWithSHAAnd') == 13
switch ($algo) {
case 'DES':
$cipher = new DES('cbc');
break;
case 'RC2':
$cipher = new RC2('cbc');
$cipher->setKeyLength(64);
break;
case '3-KeyTripleDES':
$cipher = new TripleDES('cbc');
break;
case '2-KeyTripleDES':
$cipher = new TripleDES('cbc');
$cipher->setKeyLength(128);
break;
case '128BitRC2':
$cipher = new RC2('cbc');
$cipher->setKeyLength(128);
break;
case '40BitRC2':
$cipher = new RC2('cbc');
$cipher->setKeyLength(40);
break;
case '128BitRC4':
$cipher = new RC4();
$cipher->setKeyLength(128);
break;
case '40BitRC4':
$cipher = new RC4();
$cipher->setKeyLength(40);
break;
default:
throw new UnsupportedAlgorithmException("{$algo} is not a supported algorithm");
}
return $cipher;
}
/**
* Returns a hash based on a PBES1 $algo
*
* @return string
* @param string $algo
*/
private static function getPBES1Hash($algo)
{
if (\preg_match('#^pbeWith(MD2|MD5|SHA1|SHA)And.*?-CBC$#', $algo, $matches)) {
return $matches[1] == 'SHA' ? 'sha1' : $matches[1];
}
return 'sha1';
}
/**
* Returns a KDF baesd on a PBES1 $algo
*
* @return string
* @param string $algo
*/
private static function getPBES1KDF($algo)
{
switch ($algo) {
case 'pbeWithMD2AndDES-CBC':
case 'pbeWithMD2AndRC2-CBC':
case 'pbeWithMD5AndDES-CBC':
case 'pbeWithMD5AndRC2-CBC':
case 'pbeWithSHA1AndDES-CBC':
case 'pbeWithSHA1AndRC2-CBC':
return 'pbkdf1';
}
return 'pkcs12';
}
/**
* Returns a SymmetricKey object baesd on a PBES2 $algo
*
* @return SymmetricKey
* @param string $algo
*/
private static function getPBES2EncryptionObject($algo)
{
switch ($algo) {
case 'desCBC':
$cipher = new DES('cbc');
break;
case 'des-EDE3-CBC':
$cipher = new TripleDES('cbc');
break;
case 'rc2CBC':
$cipher = new RC2('cbc');
// in theory this can be changed
$cipher->setKeyLength(128);
break;
case 'rc5-CBC-PAD':
throw new UnsupportedAlgorithmException('rc5-CBC-PAD is not supported for PBES2 PKCS#8 keys');
case 'aes128-CBC-PAD':
case 'aes192-CBC-PAD':
case 'aes256-CBC-PAD':
$cipher = new AES('cbc');
$cipher->setKeyLength(\substr($algo, 3, 3));
break;
default:
throw new UnsupportedAlgorithmException("{$algo} is not supported");
}
return $cipher;
}
/**
* Initialize static variables
*
*/
private static function initialize_static_variables()
{
if (!isset(static::$childOIDsLoaded)) {
throw new InsufficientSetupException('This class should not be called directly');
}
if (!static::$childOIDsLoaded) {
ASN1::loadOIDs(\is_array(static::OID_NAME) ? \array_combine(static::OID_NAME, static::OID_VALUE) : [static::OID_NAME => static::OID_VALUE]);
static::$childOIDsLoaded = \true;
}
if (!self::$oidsLoaded) {
// from https://tools.ietf.org/html/rfc2898
ASN1::loadOIDs([
// PBES1 encryption schemes
'pbeWithMD2AndDES-CBC' => '1.2.840.113549.1.5.1',
'pbeWithMD2AndRC2-CBC' => '1.2.840.113549.1.5.4',
'pbeWithMD5AndDES-CBC' => '1.2.840.113549.1.5.3',
'pbeWithMD5AndRC2-CBC' => '1.2.840.113549.1.5.6',
'pbeWithSHA1AndDES-CBC' => '1.2.840.113549.1.5.10',
'pbeWithSHA1AndRC2-CBC' => '1.2.840.113549.1.5.11',
// from PKCS#12:
// https://tools.ietf.org/html/rfc7292
'pbeWithSHAAnd128BitRC4' => '1.2.840.113549.1.12.1.1',
'pbeWithSHAAnd40BitRC4' => '1.2.840.113549.1.12.1.2',
'pbeWithSHAAnd3-KeyTripleDES-CBC' => '1.2.840.113549.1.12.1.3',
'pbeWithSHAAnd2-KeyTripleDES-CBC' => '1.2.840.113549.1.12.1.4',
'pbeWithSHAAnd128BitRC2-CBC' => '1.2.840.113549.1.12.1.5',
'pbeWithSHAAnd40BitRC2-CBC' => '1.2.840.113549.1.12.1.6',
'id-PBKDF2' => '1.2.840.113549.1.5.12',
'id-PBES2' => '1.2.840.113549.1.5.13',
'id-PBMAC1' => '1.2.840.113549.1.5.14',
// from PKCS#5 v2.1:
// http://www.rsa.com/rsalabs/pkcs/files/h11302-wp-pkcs5v2-1-password-based-cryptography-standard.pdf
'id-hmacWithSHA1' => '1.2.840.113549.2.7',
'id-hmacWithSHA224' => '1.2.840.113549.2.8',
'id-hmacWithSHA256' => '1.2.840.113549.2.9',
'id-hmacWithSHA384' => '1.2.840.113549.2.10',
'id-hmacWithSHA512' => '1.2.840.113549.2.11',
'id-hmacWithSHA512-224' => '1.2.840.113549.2.12',
'id-hmacWithSHA512-256' => '1.2.840.113549.2.13',
'desCBC' => '1.3.14.3.2.7',
'des-EDE3-CBC' => '1.2.840.113549.3.7',
'rc2CBC' => '1.2.840.113549.3.2',
'rc5-CBC-PAD' => '1.2.840.113549.3.9',
'aes128-CBC-PAD' => '2.16.840.1.101.3.4.1.2',
'aes192-CBC-PAD' => '2.16.840.1.101.3.4.1.22',
'aes256-CBC-PAD' => '2.16.840.1.101.3.4.1.42',
]);
self::$oidsLoaded = \true;
}
}
/**
* Break a public or private key down into its constituent components
*
* @param string $key
* @param string $password optional
* @return array
*/
protected static function load($key, $password = '')
{
if (!Strings::is_stringable($key)) {
throw new \UnexpectedValueException('Key should be a string - not a ' . \gettype($key));
}
$isPublic = \strpos($key, 'PUBLIC') !== \false;
$isPrivate = \strpos($key, 'PRIVATE') !== \false;
$decoded = self::preParse($key);
$meta = [];
$decrypted = ASN1::asn1map($decoded[0], Maps\EncryptedPrivateKeyInfo::MAP);
if (\strlen($password) && \is_array($decrypted)) {
$algorithm = $decrypted['encryptionAlgorithm']['algorithm'];
switch ($algorithm) {
// PBES1
case 'pbeWithMD2AndDES-CBC':
case 'pbeWithMD2AndRC2-CBC':
case 'pbeWithMD5AndDES-CBC':
case 'pbeWithMD5AndRC2-CBC':
case 'pbeWithSHA1AndDES-CBC':
case 'pbeWithSHA1AndRC2-CBC':
case 'pbeWithSHAAnd3-KeyTripleDES-CBC':
case 'pbeWithSHAAnd2-KeyTripleDES-CBC':
case 'pbeWithSHAAnd128BitRC2-CBC':
case 'pbeWithSHAAnd40BitRC2-CBC':
case 'pbeWithSHAAnd128BitRC4':
case 'pbeWithSHAAnd40BitRC4':
$cipher = self::getPBES1EncryptionObject($algorithm);
$hash = self::getPBES1Hash($algorithm);
$kdf = self::getPBES1KDF($algorithm);
$meta['meta']['algorithm'] = $algorithm;
$temp = ASN1::decodeBER($decrypted['encryptionAlgorithm']['parameters']);
if (!$temp) {
throw new \RuntimeException('Unable to decode BER');
}
\extract(ASN1::asn1map($temp[0], Maps\PBEParameter::MAP));
$iterationCount = (int) $iterationCount->toString();
$cipher->setPassword($password, $kdf, $hash, $salt, $iterationCount);
$key = $cipher->decrypt($decrypted['encryptedData']);
$decoded = ASN1::decodeBER($key);
if (!$decoded) {
throw new \RuntimeException('Unable to decode BER 2');
}
break;
case 'id-PBES2':
$meta['meta']['algorithm'] = $algorithm;
$temp = ASN1::decodeBER($decrypted['encryptionAlgorithm']['parameters']);
if (!$temp) {
throw new \RuntimeException('Unable to decode BER');
}
$temp = ASN1::asn1map($temp[0], Maps\PBES2params::MAP);
\extract($temp);
$cipher = self::getPBES2EncryptionObject($encryptionScheme['algorithm']);
$meta['meta']['cipher'] = $encryptionScheme['algorithm'];
$temp = ASN1::decodeBER($decrypted['encryptionAlgorithm']['parameters']);
if (!$temp) {
throw new \RuntimeException('Unable to decode BER');
}
$temp = ASN1::asn1map($temp[0], Maps\PBES2params::MAP);
\extract($temp);
if (!$cipher instanceof RC2) {
$cipher->setIV($encryptionScheme['parameters']['octetString']);
} else {
$temp = ASN1::decodeBER($encryptionScheme['parameters']);
if (!$temp) {
throw new \RuntimeException('Unable to decode BER');
}
\extract(ASN1::asn1map($temp[0], Maps\RC2CBCParameter::MAP));
$effectiveKeyLength = (int) $rc2ParametersVersion->toString();
switch ($effectiveKeyLength) {
case 160:
$effectiveKeyLength = 40;
break;
case 120:
$effectiveKeyLength = 64;
break;
case 58:
$effectiveKeyLength = 128;
break;
}
$cipher->setIV($iv);
$cipher->setKeyLength($effectiveKeyLength);
}
$meta['meta']['keyDerivationFunc'] = $keyDerivationFunc['algorithm'];
switch ($keyDerivationFunc['algorithm']) {
case 'id-PBKDF2':
$temp = ASN1::decodeBER($keyDerivationFunc['parameters']);
if (!$temp) {
throw new \RuntimeException('Unable to decode BER');
}
$prf = ['algorithm' => 'id-hmacWithSHA1'];
$params = ASN1::asn1map($temp[0], Maps\PBKDF2params::MAP);
\extract($params);
$meta['meta']['prf'] = $prf['algorithm'];
$hash = \str_replace('-', '/', \substr($prf['algorithm'], 11));
$params = [$password, 'pbkdf2', $hash, $salt, (int) $iterationCount->toString()];
if (isset($keyLength)) {
$params[] = (int) $keyLength->toString();
}
$cipher->setPassword(...$params);
$key = $cipher->decrypt($decrypted['encryptedData']);
$decoded = ASN1::decodeBER($key);
if (!$decoded) {
throw new \RuntimeException('Unable to decode BER 3');
}
break;
default:
throw new UnsupportedAlgorithmException('Only PBKDF2 is supported for PBES2 PKCS#8 keys');
}
break;
case 'id-PBMAC1':
//$temp = ASN1::decodeBER($decrypted['encryptionAlgorithm']['parameters']);
//$value = ASN1::asn1map($temp[0], Maps\PBMAC1params::MAP);
// since i can't find any implementation that does PBMAC1 it is unsupported
throw new UnsupportedAlgorithmException('Only PBES1 and PBES2 PKCS#8 keys are supported.');
}
}
$private = ASN1::asn1map($decoded[0], Maps\OneAsymmetricKey::MAP);
if (\is_array($private)) {
if ($isPublic) {
throw new \UnexpectedValueException('Human readable string claims public key but DER encoded string claims private key');
}
if (isset($private['privateKeyAlgorithm']['parameters']) && !$private['privateKeyAlgorithm']['parameters'] instanceof ASN1\Element && isset($decoded[0]['content'][1]['content'][1])) {
$temp = $decoded[0]['content'][1]['content'][1];
$private['privateKeyAlgorithm']['parameters'] = new ASN1\Element(\substr($key, $temp['start'], $temp['length']));
}
if (\is_array(static::OID_NAME)) {
if (!\in_array($private['privateKeyAlgorithm']['algorithm'], static::OID_NAME)) {
throw new UnsupportedAlgorithmException($private['privateKeyAlgorithm']['algorithm'] . ' is not a supported key type');
}
} else {
if ($private['privateKeyAlgorithm']['algorithm'] != static::OID_NAME) {
throw new UnsupportedAlgorithmException('Only ' . static::OID_NAME . ' keys are supported; this is a ' . $private['privateKeyAlgorithm']['algorithm'] . ' key');
}
}
if (isset($private['publicKey'])) {
if ($private['publicKey'][0] != "\x00") {
throw new \UnexpectedValueException('The first byte of the public key should be null - not ' . \bin2hex($private['publicKey'][0]));
}
$private['publicKey'] = \substr($private['publicKey'], 1);
}
return $private + $meta;
}
// EncryptedPrivateKeyInfo and PublicKeyInfo have largely identical "signatures". the only difference
// is that the former has an octet string and the later has a bit string. the first byte of a bit
// string represents the number of bits in the last byte that are to be ignored but, currently,
// bit strings wanting a non-zero amount of bits trimmed are not supported
$public = ASN1::asn1map($decoded[0], Maps\PublicKeyInfo::MAP);
if (\is_array($public)) {
if ($isPrivate) {
throw new \UnexpectedValueException('Human readable string claims private key but DER encoded string claims public key');
}
if ($public['publicKey'][0] != "\x00") {
throw new \UnexpectedValueException('The first byte of the public key should be null - not ' . \bin2hex($public['publicKey'][0]));
}
if (\is_array(static::OID_NAME)) {
if (!\in_array($public['publicKeyAlgorithm']['algorithm'], static::OID_NAME)) {
throw new UnsupportedAlgorithmException($public['publicKeyAlgorithm']['algorithm'] . ' is not a supported key type');
}
} else {
if ($public['publicKeyAlgorithm']['algorithm'] != static::OID_NAME) {
throw new UnsupportedAlgorithmException('Only ' . static::OID_NAME . ' keys are supported; this is a ' . $public['publicKeyAlgorithm']['algorithm'] . ' key');
}
}
if (isset($public['publicKeyAlgorithm']['parameters']) && !$public['publicKeyAlgorithm']['parameters'] instanceof ASN1\Element && isset($decoded[0]['content'][0]['content'][1])) {
$temp = $decoded[0]['content'][0]['content'][1];
$public['publicKeyAlgorithm']['parameters'] = new ASN1\Element(\substr($key, $temp['start'], $temp['length']));
}
$public['publicKey'] = \substr($public['publicKey'], 1);
return $public;
}
throw new \RuntimeException('Unable to parse using either OneAsymmetricKey or PublicKeyInfo ASN1 maps');
}
/**
* Wrap a private key appropriately
*
* @param string $key
* @param string $attr
* @param mixed $params
* @param string $password
* @param string $oid optional
* @param string $publicKey optional
* @param array $options optional
* @return string
*/
protected static function wrapPrivateKey($key, $attr, $params, $password, $oid = null, $publicKey = '', array $options = [])
{
self::initialize_static_variables();
$key = ['version' => 'v1', 'privateKeyAlgorithm' => ['algorithm' => \is_string(static::OID_NAME) ? static::OID_NAME : $oid], 'privateKey' => $key];
if ($oid != 'id-Ed25519' && $oid != 'id-Ed448') {
$key['privateKeyAlgorithm']['parameters'] = $params;
}
if (!empty($attr)) {
$key['attributes'] = $attr;
}
if (!empty($publicKey)) {
$key['version'] = 'v2';
$key['publicKey'] = $publicKey;
}
$key = ASN1::encodeDER($key, Maps\OneAsymmetricKey::MAP);
if (!empty($password) && \is_string($password)) {
$salt = Random::string(8);
$iterationCount = isset($options['iterationCount']) ? $options['iterationCount'] : self::$defaultIterationCount;
$encryptionAlgorithm = isset($options['encryptionAlgorithm']) ? $options['encryptionAlgorithm'] : self::$defaultEncryptionAlgorithm;
$encryptionScheme = isset($options['encryptionScheme']) ? $options['encryptionScheme'] : self::$defaultEncryptionScheme;
$prf = isset($options['PRF']) ? $options['PRF'] : self::$defaultPRF;
if ($encryptionAlgorithm == 'id-PBES2') {
$crypto = self::getPBES2EncryptionObject($encryptionScheme);
$hash = \str_replace('-', '/', \substr($prf, 11));
$kdf = 'pbkdf2';
$iv = Random::string($crypto->getBlockLength() >> 3);
$PBKDF2params = ['salt' => $salt, 'iterationCount' => $iterationCount, 'prf' => ['algorithm' => $prf, 'parameters' => null]];
$PBKDF2params = ASN1::encodeDER($PBKDF2params, Maps\PBKDF2params::MAP);
if (!$crypto instanceof RC2) {
$params = ['octetString' => $iv];
} else {
$params = ['rc2ParametersVersion' => 58, 'iv' => $iv];
$params = ASN1::encodeDER($params, Maps\RC2CBCParameter::MAP);
$params = new ASN1\Element($params);
}
$params = ['keyDerivationFunc' => ['algorithm' => 'id-PBKDF2', 'parameters' => new ASN1\Element($PBKDF2params)], 'encryptionScheme' => ['algorithm' => $encryptionScheme, 'parameters' => $params]];
$params = ASN1::encodeDER($params, Maps\PBES2params::MAP);
$crypto->setIV($iv);
} else {
$crypto = self::getPBES1EncryptionObject($encryptionAlgorithm);
$hash = self::getPBES1Hash($encryptionAlgorithm);
$kdf = self::getPBES1KDF($encryptionAlgorithm);
$params = ['salt' => $salt, 'iterationCount' => $iterationCount];
$params = ASN1::encodeDER($params, Maps\PBEParameter::MAP);
}
$crypto->setPassword($password, $kdf, $hash, $salt, $iterationCount);
$key = $crypto->encrypt($key);
$key = ['encryptionAlgorithm' => ['algorithm' => $encryptionAlgorithm, 'parameters' => new ASN1\Element($params)], 'encryptedData' => $key];
$key = ASN1::encodeDER($key, Maps\EncryptedPrivateKeyInfo::MAP);
return "-----BEGIN ENCRYPTED PRIVATE KEY-----\r\n" . \chunk_split(Strings::base64_encode($key), 64) . "-----END ENCRYPTED PRIVATE KEY-----";
}
return "-----BEGIN PRIVATE KEY-----\r\n" . \chunk_split(Strings::base64_encode($key), 64) . "-----END PRIVATE KEY-----";
}
/**
* Wrap a public key appropriately
*
* @param string $key
* @param mixed $params
* @param string $oid
* @return string
*/
protected static function wrapPublicKey($key, $params, $oid = null)
{
self::initialize_static_variables();
$key = ['publicKeyAlgorithm' => ['algorithm' => \is_string(static::OID_NAME) ? static::OID_NAME : $oid], 'publicKey' => "\x00" . $key];
if ($oid != 'id-Ed25519' && $oid != 'id-Ed448') {
$key['publicKeyAlgorithm']['parameters'] = $params;
}
$key = ASN1::encodeDER($key, Maps\PublicKeyInfo::MAP);
return "-----BEGIN PUBLIC KEY-----\r\n" . \chunk_split(Strings::base64_encode($key), 64) . "-----END PUBLIC KEY-----";
}
/**
* Perform some preliminary parsing of the key
*
* @param string $key
* @return array
*/
private static function preParse(&$key)
{
self::initialize_static_variables();
if (self::$format != self::MODE_DER) {
$decoded = ASN1::extractBER($key);
if ($decoded !== \false) {
$key = $decoded;
} elseif (self::$format == self::MODE_PEM) {
throw new \UnexpectedValueException('Expected base64-encoded PEM format but was unable to decode base64 text');
}
}
$decoded = ASN1::decodeBER($key);
if (!$decoded) {
throw new \RuntimeException('Unable to decode BER');
}
return $decoded;
}
/**
* Returns the encryption parameters used by the key
*
* @param string $key
* @return array
*/
public static function extractEncryptionAlgorithm($key)
{
if (!Strings::is_stringable($key)) {
throw new \UnexpectedValueException('Key should be a string - not a ' . \gettype($key));
}
$decoded = self::preParse($key);
$r = ASN1::asn1map($decoded[0], ASN1\Maps\EncryptedPrivateKeyInfo::MAP);
if (!\is_array($r)) {
throw new \RuntimeException('Unable to parse using EncryptedPrivateKeyInfo map');
}
if ($r['encryptionAlgorithm']['algorithm'] == 'id-PBES2') {
$decoded = ASN1::decodeBER($r['encryptionAlgorithm']['parameters']->element);
if (!$decoded) {
throw new \RuntimeException('Unable to decode BER');
}
$r['encryptionAlgorithm']['parameters'] = ASN1::asn1map($decoded[0], ASN1\Maps\PBES2params::MAP);
$kdf =& $r['encryptionAlgorithm']['parameters']['keyDerivationFunc'];
switch ($kdf['algorithm']) {
case 'id-PBKDF2':
$decoded = ASN1::decodeBER($kdf['parameters']->element);
if (!$decoded) {
throw new \RuntimeException('Unable to decode BER');
}
$kdf['parameters'] = ASN1::asn1map($decoded[0], Maps\PBKDF2params::MAP);
}
}
return $r['encryptionAlgorithm'];
}
}

View File

@@ -0,0 +1,324 @@
<?php
/**
* PuTTY Formatted Key Handler
*
* See PuTTY's SSHPUBK.C and https://tartarus.org/~simon/putty-snapshots/htmldoc/AppendixC.html
*
* PHP version 5
*
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2016 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net
*/
namespace VendorDuplicator\phpseclib3\Crypt\Common\Formats\Keys;
use VendorDuplicator\phpseclib3\Common\Functions\Strings;
use VendorDuplicator\phpseclib3\Crypt\AES;
use VendorDuplicator\phpseclib3\Crypt\Hash;
use VendorDuplicator\phpseclib3\Crypt\Random;
use VendorDuplicator\phpseclib3\Exception\UnsupportedAlgorithmException;
/**
* PuTTY Formatted Key Handler
*
* @author Jim Wigginton <terrafrost@php.net>
*/
abstract class PuTTY
{
/**
* Default comment
*
* @var string
*/
private static $comment = 'phpseclib-generated-key';
/**
* Default version
*
* @var int
*/
private static $version = 2;
/**
* Sets the default comment
*
* @param string $comment
*/
public static function setComment($comment)
{
self::$comment = \str_replace(["\r", "\n"], '', $comment);
}
/**
* Sets the default version
*
* @param int $version
*/
public static function setVersion($version)
{
if ($version != 2 && $version != 3) {
throw new \RuntimeException('Only supported versions are 2 and 3');
}
self::$version = $version;
}
/**
* Generate a symmetric key for PuTTY v2 keys
*
* @param string $password
* @param int $length
* @return string
*/
private static function generateV2Key($password, $length)
{
$symkey = '';
$sequence = 0;
while (\strlen($symkey) < $length) {
$temp = \pack('Na*', $sequence++, $password);
$symkey .= Strings::hex2bin(\sha1($temp));
}
return \substr($symkey, 0, $length);
}
/**
* Generate a symmetric key for PuTTY v3 keys
*
* @param string $password
* @param string $flavour
* @param int $memory
* @param int $passes
* @param string $salt
* @return array
*/
private static function generateV3Key($password, $flavour, $memory, $passes, $salt)
{
if (!\function_exists('sodium_crypto_pwhash')) {
throw new \RuntimeException('sodium_crypto_pwhash needs to exist for Argon2 password hasing');
}
switch ($flavour) {
case 'Argon2i':
$flavour = \SODIUM_CRYPTO_PWHASH_ALG_ARGON2I13;
break;
case 'Argon2id':
$flavour = \SODIUM_CRYPTO_PWHASH_ALG_ARGON2ID13;
break;
default:
throw new UnsupportedAlgorithmException('Only Argon2i and Argon2id are supported');
}
$length = 80;
// keylen + ivlen + mac_keylen
$temp = \sodium_crypto_pwhash($length, $password, $salt, $passes, $memory << 10, $flavour);
$symkey = \substr($temp, 0, 32);
$symiv = \substr($temp, 32, 16);
$hashkey = \substr($temp, -32);
return \compact('symkey', 'symiv', 'hashkey');
}
/**
* Break a public or private key down into its constituent components
*
* @param string $key
* @param string $password
* @return array
*/
public static function load($key, $password)
{
if (!Strings::is_stringable($key)) {
throw new \UnexpectedValueException('Key should be a string - not a ' . \gettype($key));
}
if (\strpos($key, 'BEGIN SSH2 PUBLIC KEY') !== \false) {
$lines = \preg_split('#[\\r\\n]+#', $key);
switch (\true) {
case $lines[0] != '---- BEGIN SSH2 PUBLIC KEY ----':
throw new \UnexpectedValueException('Key doesn\'t start with ---- BEGIN SSH2 PUBLIC KEY ----');
case $lines[\count($lines) - 1] != '---- END SSH2 PUBLIC KEY ----':
throw new \UnexpectedValueException('Key doesn\'t end with ---- END SSH2 PUBLIC KEY ----');
}
$lines = \array_splice($lines, 1, -1);
$lines = \array_map(function ($line) {
return \rtrim($line, "\r\n");
}, $lines);
$data = $current = '';
$values = [];
$in_value = \false;
foreach ($lines as $line) {
switch (\true) {
case \preg_match('#^(.*?): (.*)#', $line, $match):
$in_value = $line[\strlen($line) - 1] == '\\';
$current = \strtolower($match[1]);
$values[$current] = $in_value ? \substr($match[2], 0, -1) : $match[2];
break;
case $in_value:
$in_value = $line[\strlen($line) - 1] == '\\';
$values[$current] .= $in_value ? \substr($line, 0, -1) : $line;
break;
default:
$data .= $line;
}
}
$components = \call_user_func([static::PUBLIC_HANDLER, 'load'], $data);
if ($components === \false) {
throw new \UnexpectedValueException('Unable to decode public key');
}
$components += $values;
$components['comment'] = \str_replace(['\\\\', '\\"'], ['\\', '"'], $values['comment']);
return $components;
}
$components = [];
$key = \preg_split('#\\r\\n|\\r|\\n#', \trim($key));
if (Strings::shift($key[0], \strlen('PuTTY-User-Key-File-')) != 'PuTTY-User-Key-File-') {
return \false;
}
$version = (int) Strings::shift($key[0], 3);
// should be either "2: " or "3: 0" prior to int casting
if ($version != 2 && $version != 3) {
throw new \RuntimeException('Only v2 and v3 PuTTY private keys are supported');
}
$components['type'] = $type = \rtrim($key[0]);
if (!\in_array($type, static::$types)) {
$error = \count(static::$types) == 1 ? 'Only ' . static::$types[0] . ' keys are supported. ' : '';
throw new UnsupportedAlgorithmException($error . 'This is an unsupported ' . $type . ' key');
}
$encryption = \trim(\preg_replace('#Encryption: (.+)#', '$1', $key[1]));
$components['comment'] = \trim(\preg_replace('#Comment: (.+)#', '$1', $key[2]));
$publicLength = \trim(\preg_replace('#Public-Lines: (\\d+)#', '$1', $key[3]));
$public = Strings::base64_decode(\implode('', \array_map('trim', \array_slice($key, 4, $publicLength))));
$source = Strings::packSSH2('ssss', $type, $encryption, $components['comment'], $public);
\extract(\unpack('Nlength', Strings::shift($public, 4)));
$newtype = Strings::shift($public, $length);
if ($newtype != $type) {
throw new \RuntimeException('The binary type does not match the human readable type field');
}
$components['public'] = $public;
switch ($version) {
case 3:
$hashkey = '';
break;
case 2:
$hashkey = 'putty-private-key-file-mac-key';
}
$offset = $publicLength + 4;
switch ($encryption) {
case 'aes256-cbc':
$crypto = new AES('cbc');
switch ($version) {
case 3:
$flavour = \trim(\preg_replace('#Key-Derivation: (.*)#', '$1', $key[$offset++]));
$memory = \trim(\preg_replace('#Argon2-Memory: (\\d+)#', '$1', $key[$offset++]));
$passes = \trim(\preg_replace('#Argon2-Passes: (\\d+)#', '$1', $key[$offset++]));
$parallelism = \trim(\preg_replace('#Argon2-Parallelism: (\\d+)#', '$1', $key[$offset++]));
$salt = Strings::hex2bin(\trim(\preg_replace('#Argon2-Salt: ([0-9a-f]+)#', '$1', $key[$offset++])));
\extract(self::generateV3Key($password, $flavour, $memory, $passes, $salt));
break;
case 2:
$symkey = self::generateV2Key($password, 32);
$symiv = \str_repeat("\x00", $crypto->getBlockLength() >> 3);
$hashkey .= $password;
}
}
switch ($version) {
case 3:
$hash = new Hash('sha256');
$hash->setKey($hashkey);
break;
case 2:
$hash = new Hash('sha1');
$hash->setKey(\sha1($hashkey, \true));
}
$privateLength = \trim(\preg_replace('#Private-Lines: (\\d+)#', '$1', $key[$offset++]));
$private = Strings::base64_decode(\implode('', \array_map('trim', \array_slice($key, $offset, $privateLength))));
if ($encryption != 'none') {
$crypto->setKey($symkey);
$crypto->setIV($symiv);
$crypto->disablePadding();
$private = $crypto->decrypt($private);
}
$source .= Strings::packSSH2('s', $private);
$hmac = \trim(\preg_replace('#Private-MAC: (.+)#', '$1', $key[$offset + $privateLength]));
$hmac = Strings::hex2bin($hmac);
if (!\hash_equals($hash->hash($source), $hmac)) {
throw new \UnexpectedValueException('MAC validation error');
}
$components['private'] = $private;
return $components;
}
/**
* Wrap a private key appropriately
*
* @param string $public
* @param string $private
* @param string $type
* @param string $password
* @param array $options optional
* @return string
*/
protected static function wrapPrivateKey($public, $private, $type, $password, array $options = [])
{
$encryption = !empty($password) || \is_string($password) ? 'aes256-cbc' : 'none';
$comment = isset($options['comment']) ? $options['comment'] : self::$comment;
$version = isset($options['version']) ? $options['version'] : self::$version;
$key = "PuTTY-User-Key-File-{$version}: {$type}\r\n";
$key .= "Encryption: {$encryption}\r\n";
$key .= "Comment: {$comment}\r\n";
$public = Strings::packSSH2('s', $type) . $public;
$source = Strings::packSSH2('ssss', $type, $encryption, $comment, $public);
$public = Strings::base64_encode($public);
$key .= "Public-Lines: " . (\strlen($public) + 63 >> 6) . "\r\n";
$key .= \chunk_split($public, 64);
if (empty($password) && !\is_string($password)) {
$source .= Strings::packSSH2('s', $private);
switch ($version) {
case 3:
$hash = new Hash('sha256');
$hash->setKey('');
break;
case 2:
$hash = new Hash('sha1');
$hash->setKey(\sha1('putty-private-key-file-mac-key', \true));
}
} else {
$private .= Random::string(16 - (\strlen($private) & 15));
$source .= Strings::packSSH2('s', $private);
$crypto = new AES('cbc');
switch ($version) {
case 3:
$salt = Random::string(16);
$key .= "Key-Derivation: Argon2id\r\n";
$key .= "Argon2-Memory: 8192\r\n";
$key .= "Argon2-Passes: 13\r\n";
$key .= "Argon2-Parallelism: 1\r\n";
$key .= "Argon2-Salt: " . Strings::bin2hex($salt) . "\r\n";
\extract(self::generateV3Key($password, 'Argon2id', 8192, 13, $salt));
$hash = new Hash('sha256');
$hash->setKey($hashkey);
break;
case 2:
$symkey = self::generateV2Key($password, 32);
$symiv = \str_repeat("\x00", $crypto->getBlockLength() >> 3);
$hashkey = 'putty-private-key-file-mac-key' . $password;
$hash = new Hash('sha1');
$hash->setKey(\sha1($hashkey, \true));
}
$crypto->setKey($symkey);
$crypto->setIV($symiv);
$crypto->disablePadding();
$private = $crypto->encrypt($private);
$mac = $hash->hash($source);
}
$private = Strings::base64_encode($private);
$key .= 'Private-Lines: ' . (\strlen($private) + 63 >> 6) . "\r\n";
$key .= \chunk_split($private, 64);
$key .= 'Private-MAC: ' . Strings::bin2hex($hash->hash($source)) . "\r\n";
return $key;
}
/**
* Wrap a public key appropriately
*
* This is basically the format described in RFC 4716 (https://tools.ietf.org/html/rfc4716)
*
* @param string $key
* @param string $type
* @return string
*/
protected static function wrapPublicKey($key, $type)
{
$key = \pack('Na*a*', \strlen($type), $type, $key);
$key = "---- BEGIN SSH2 PUBLIC KEY ----\r\n" . 'Comment: "' . \str_replace(['\\', '"'], ['\\\\', '\\"'], self::$comment) . "\"\r\n" . \chunk_split(Strings::base64_encode($key), 64) . '---- END SSH2 PUBLIC KEY ----';
return $key;
}
}

View File

@@ -0,0 +1,53 @@
<?php
/**
* Raw Signature Handler
*
* PHP version 5
*
* Handles signatures as arrays
*
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2016 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net
*/
namespace VendorDuplicator\phpseclib3\Crypt\Common\Formats\Signature;
use VendorDuplicator\phpseclib3\Math\BigInteger;
/**
* Raw Signature Handler
*
* @author Jim Wigginton <terrafrost@php.net>
*/
abstract class Raw
{
/**
* Loads a signature
*
* @param array $sig
* @return array|bool
*/
public static function load($sig)
{
switch (\true) {
case !\is_array($sig):
case !isset($sig['r']) || !isset($sig['s']):
case !$sig['r'] instanceof BigInteger:
case !$sig['s'] instanceof BigInteger:
return \false;
}
return ['r' => $sig['r'], 's' => $sig['s']];
}
/**
* Returns a signature in the appropriate format
*
* @param \VendorDuplicator\phpseclib3\Math\BigInteger $r
* @param \VendorDuplicator\phpseclib3\Math\BigInteger $s
* @return string
*/
public static function save(BigInteger $r, BigInteger $s)
{
return \compact('r', 's');
}
}

View File

@@ -0,0 +1,29 @@
<?php
/**
* PrivateKey interface
*
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2009 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net
*/
namespace VendorDuplicator\phpseclib3\Crypt\Common;
/**
* PrivateKey interface
*
* @author Jim Wigginton <terrafrost@php.net>
*/
interface PrivateKey
{
public function sign($message);
//public function decrypt($ciphertext);
public function getPublicKey();
public function toString($type, array $options = []);
/**
* @param string|false $password
* @return mixed
*/
public function withPassword($password = \false);
}

View File

@@ -0,0 +1,24 @@
<?php
/**
* PublicKey interface
*
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2009 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net
*/
namespace VendorDuplicator\phpseclib3\Crypt\Common;
/**
* PublicKey interface
*
* @author Jim Wigginton <terrafrost@php.net>
*/
interface PublicKey
{
public function verify($message, $signature);
//public function encrypt($plaintext);
public function toString($type, array $options = []);
public function getFingerprint($algorithm);
}

View File

@@ -0,0 +1,51 @@
<?php
/**
* Base Class for all stream ciphers
*
* PHP version 5
*
* @author Jim Wigginton <terrafrost@php.net>
* @author Hans-Juergen Petrich <petrich@tronic-media.com>
* @copyright 2007 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net
*/
namespace VendorDuplicator\phpseclib3\Crypt\Common;
/**
* Base Class for all stream cipher classes
*
* @author Jim Wigginton <terrafrost@php.net>
*/
abstract class StreamCipher extends SymmetricKey
{
/**
* Block Length of the cipher
*
* Stream ciphers do not have a block size
*
* @see \VendorDuplicator\phpseclib3\Crypt\Common\SymmetricKey::block_size
* @var int
*/
protected $block_size = 0;
/**
* Default Constructor.
*
* @see \VendorDuplicator\phpseclib3\Crypt\Common\SymmetricKey::__construct()
* @return \VendorDuplicator\phpseclib3\Crypt\Common\StreamCipher
*/
public function __construct()
{
parent::__construct('stream');
}
/**
* Stream ciphers not use an IV
*
* @return bool
*/
public function usesIV()
{
return \false;
}
}

View File

@@ -0,0 +1,55 @@
<?php
/**
* Fingerprint Trait for Public Keys
*
* PHP version 5
*
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2015 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net
*/
namespace VendorDuplicator\phpseclib3\Crypt\Common\Traits;
use VendorDuplicator\phpseclib3\Crypt\Hash;
/**
* Fingerprint Trait for Private Keys
*
* @author Jim Wigginton <terrafrost@php.net>
*/
trait Fingerprint
{
/**
* Returns the public key's fingerprint
*
* The public key's fingerprint is returned, which is equivalent to running `ssh-keygen -lf rsa.pub`. If there is
* no public key currently loaded, false is returned.
* Example output (md5): "c1:b1:30:29:d7:b8:de:6c:97:77:10:d7:46:41:63:87" (as specified by RFC 4716)
*
* @param string $algorithm The hashing algorithm to be used. Valid options are 'md5' and 'sha256'. False is returned
* for invalid values.
* @return mixed
*/
public function getFingerprint($algorithm = 'md5')
{
$type = self::validatePlugin('Keys', 'OpenSSH', 'savePublicKey');
if ($type === \false) {
return \false;
}
$key = $this->toString('OpenSSH', ['binary' => \true]);
if ($key === \false) {
return \false;
}
switch ($algorithm) {
case 'sha256':
$hash = new Hash('sha256');
$base = \base64_encode($hash->hash($key));
return \substr($base, 0, \strlen($base) - 1);
case 'md5':
return \substr(\chunk_split(\md5($key), 2, ':'), 0, -1);
default:
return \false;
}
}
}

View File

@@ -0,0 +1,44 @@
<?php
/**
* Password Protected Trait for Private Keys
*
* PHP version 5
*
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2015 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net
*/
namespace VendorDuplicator\phpseclib3\Crypt\Common\Traits;
/**
* Password Protected Trait for Private Keys
*
* @author Jim Wigginton <terrafrost@php.net>
*/
trait PasswordProtected
{
/**
* Password
*
* @var string|bool
*/
private $password = \false;
/**
* Sets the password
*
* Private keys can be encrypted with a password. To unset the password, pass in the empty string or false.
* Or rather, pass in $password such that empty($password) && !is_string($password) is true.
*
* @see self::createKey()
* @see self::load()
* @param string|bool $password
*/
public function withPassword($password = \false)
{
$new = clone $this;
$new->password = $password;
return $new;
}
}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,295 @@
<?php
/**
* Pure-PHP (EC)DH implementation
*
* PHP version 5
*
* Here's an example of how to compute a shared secret with this library:
* <code>
* <?php
* include 'vendor/autoload.php';
*
* $ourPrivate = \phpseclib3\Crypt\DH::createKey();
* $secret = DH::computeSecret($ourPrivate, $theirPublic);
*
* ?>
* </code>
*
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2016 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net
*/
namespace VendorDuplicator\phpseclib3\Crypt;
use VendorDuplicator\phpseclib3\Crypt\Common\AsymmetricKey;
use VendorDuplicator\phpseclib3\Crypt\DH\Parameters;
use VendorDuplicator\phpseclib3\Crypt\DH\PrivateKey;
use VendorDuplicator\phpseclib3\Crypt\DH\PublicKey;
use VendorDuplicator\phpseclib3\Exception\NoKeyLoadedException;
use VendorDuplicator\phpseclib3\Exception\UnsupportedOperationException;
use VendorDuplicator\phpseclib3\Math\BigInteger;
/**
* Pure-PHP (EC)DH implementation
*
* @author Jim Wigginton <terrafrost@php.net>
*/
abstract class DH extends AsymmetricKey
{
/**
* Algorithm Name
*
* @var string
*/
const ALGORITHM = 'DH';
/**
* DH prime
*
* @var \VendorDuplicator\phpseclib3\Math\BigInteger
*/
protected $prime;
/**
* DH Base
*
* Prime divisor of p-1
*
* @var \VendorDuplicator\phpseclib3\Math\BigInteger
*/
protected $base;
/**
* Public Key
*
* @var \VendorDuplicator\phpseclib3\Math\BigInteger
*/
protected $publicKey;
/**
* Create DH parameters
*
* This method is a bit polymorphic. It can take any of the following:
* - two BigInteger's (prime and base)
* - an integer representing the size of the prime in bits (the base is assumed to be 2)
* - a string (eg. diffie-hellman-group14-sha1)
*
* @return Parameters
*/
public static function createParameters(...$args)
{
$class = new \ReflectionClass(static::class);
if ($class->isFinal()) {
throw new \RuntimeException('createParameters() should not be called from final classes (' . static::class . ')');
}
$params = new Parameters();
if (\count($args) == 2 && $args[0] instanceof BigInteger && $args[1] instanceof BigInteger) {
//if (!$args[0]->isPrime()) {
// throw new \InvalidArgumentException('The first parameter should be a prime number');
//}
$params->prime = $args[0];
$params->base = $args[1];
return $params;
} elseif (\count($args) == 1 && \is_numeric($args[0])) {
$params->prime = BigInteger::randomPrime($args[0]);
$params->base = new BigInteger(2);
return $params;
} elseif (\count($args) != 1 || !\is_string($args[0])) {
throw new \InvalidArgumentException('Valid parameters are either: two BigInteger\'s (prime and base), a single integer (the length of the prime; base is assumed to be 2) or a string');
}
switch ($args[0]) {
// see http://tools.ietf.org/html/rfc2409#section-6.2 and
// http://tools.ietf.org/html/rfc2412, appendex E
case 'diffie-hellman-group1-sha1':
$prime = 'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74' . '020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F1437' . '4FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED' . 'EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF';
break;
// see http://tools.ietf.org/html/rfc3526#section-3
case 'diffie-hellman-group14-sha1':
// 2048-bit MODP Group
case 'diffie-hellman-group14-sha256':
$prime = 'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74' . '020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F1437' . '4FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED' . 'EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF05' . '98DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB' . '9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B' . 'E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718' . '3995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF';
break;
// see https://tools.ietf.org/html/rfc3526#section-4
case 'diffie-hellman-group15-sha512':
// 3072-bit MODP Group
$prime = 'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74' . '020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F1437' . '4FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED' . 'EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF05' . '98DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB' . '9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B' . 'E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718' . '3995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D04507A33' . 'A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7' . 'ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6BF12FFA06D98A0864' . 'D87602733EC86A64521F2B18177B200CBBE117577A615D6C770988C0BAD946E2' . '08E24FA074E5AB3143DB5BFCE0FD108E4B82D120A93AD2CAFFFFFFFFFFFFFFFF';
break;
// see https://tools.ietf.org/html/rfc3526#section-5
case 'diffie-hellman-group16-sha512':
// 4096-bit MODP Group
$prime = 'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74' . '020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F1437' . '4FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED' . 'EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF05' . '98DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB' . '9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B' . 'E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718' . '3995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D04507A33' . 'A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7' . 'ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6BF12FFA06D98A0864' . 'D87602733EC86A64521F2B18177B200CBBE117577A615D6C770988C0BAD946E2' . '08E24FA074E5AB3143DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7' . '88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8' . 'DBBBC2DB04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2' . '233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9' . '93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934063199FFFFFFFFFFFFFFFF';
break;
// see https://tools.ietf.org/html/rfc3526#section-6
case 'diffie-hellman-group17-sha512':
// 6144-bit MODP Group
$prime = 'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74' . '020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F1437' . '4FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED' . 'EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF05' . '98DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB' . '9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B' . 'E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718' . '3995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D04507A33' . 'A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7' . 'ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6BF12FFA06D98A0864' . 'D87602733EC86A64521F2B18177B200CBBE117577A615D6C770988C0BAD946E2' . '08E24FA074E5AB3143DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7' . '88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8' . 'DBBBC2DB04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2' . '233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9' . '93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C93402849236C3FAB4D27C7026' . 'C1D4DCB2602646DEC9751E763DBA37BDF8FF9406AD9E530EE5DB382F413001AE' . 'B06A53ED9027D831179727B0865A8918DA3EDBEBCF9B14ED44CE6CBACED4BB1B' . 'DB7F1447E6CC254B332051512BD7AF426FB8F401378CD2BF5983CA01C64B92EC' . 'F032EA15D1721D03F482D7CE6E74FEF6D55E702F46980C82B5A84031900B1C9E' . '59E7C97FBEC7E8F323A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA' . 'CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE32806A1D58BB7C5DA76' . 'F550AA3D8A1FBFF0EB19CCB1A313D55CDA56C9EC2EF29632387FE8D76E3C0468' . '043E8F663F4860EE12BF2D5B0B7474D6E694F91E6DCC4024FFFFFFFFFFFFFFFF';
break;
// see https://tools.ietf.org/html/rfc3526#section-7
case 'diffie-hellman-group18-sha512':
// 8192-bit MODP Group
$prime = 'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74' . '020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F1437' . '4FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED' . 'EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF05' . '98DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB' . '9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B' . 'E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718' . '3995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D04507A33' . 'A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7' . 'ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6BF12FFA06D98A0864' . 'D87602733EC86A64521F2B18177B200CBBE117577A615D6C770988C0BAD946E2' . '08E24FA074E5AB3143DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7' . '88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8' . 'DBBBC2DB04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2' . '233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9' . '93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C93402849236C3FAB4D27C7026' . 'C1D4DCB2602646DEC9751E763DBA37BDF8FF9406AD9E530EE5DB382F413001AE' . 'B06A53ED9027D831179727B0865A8918DA3EDBEBCF9B14ED44CE6CBACED4BB1B' . 'DB7F1447E6CC254B332051512BD7AF426FB8F401378CD2BF5983CA01C64B92EC' . 'F032EA15D1721D03F482D7CE6E74FEF6D55E702F46980C82B5A84031900B1C9E' . '59E7C97FBEC7E8F323A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA' . 'CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE32806A1D58BB7C5DA76' . 'F550AA3D8A1FBFF0EB19CCB1A313D55CDA56C9EC2EF29632387FE8D76E3C0468' . '043E8F663F4860EE12BF2D5B0B7474D6E694F91E6DBE115974A3926F12FEE5E4' . '38777CB6A932DF8CD8BEC4D073B931BA3BC832B68D9DD300741FA7BF8AFC47ED' . '2576F6936BA424663AAB639C5AE4F5683423B4742BF1C978238F16CBE39D652D' . 'E3FDB8BEFC848AD922222E04A4037C0713EB57A81A23F0C73473FC646CEA306B' . '4BCBC8862F8385DDFA9D4B7FA2C087E879683303ED5BDD3A062B3CF5B3A278A6' . '6D2A13F83F44F82DDF310EE074AB6A364597E899A0255DC164F31CC50846851D' . 'F9AB48195DED7EA1B1D510BD7EE74D73FAF36BC31ECFA268359046F4EB879F92' . '4009438B481C6CD7889A002ED5EE382BC9190DA6FC026E479558E4475677E9AA' . '9E3050E2765694DFC81F56E880B96E7160C980DD98EDD3DFFFFFFFFFFFFFFFFF';
break;
default:
throw new \InvalidArgumentException('Invalid named prime provided');
}
$params->prime = new BigInteger($prime, 16);
$params->base = new BigInteger(2);
return $params;
}
/**
* Create public / private key pair.
*
* The rationale for the second parameter is described in http://tools.ietf.org/html/rfc4419#section-6.2 :
*
* "To increase the speed of the key exchange, both client and server may
* reduce the size of their private exponents. It should be at least
* twice as long as the key material that is generated from the shared
* secret. For more details, see the paper by van Oorschot and Wiener
* [VAN-OORSCHOT]."
*
* $length is in bits
*
* @param Parameters $params
* @param int $length optional
* @return DH\PrivateKey
*/
public static function createKey(Parameters $params, $length = 0)
{
$class = new \ReflectionClass(static::class);
if ($class->isFinal()) {
throw new \RuntimeException('createKey() should not be called from final classes (' . static::class . ')');
}
$one = new BigInteger(1);
if ($length) {
$max = $one->bitwise_leftShift($length);
$max = $max->subtract($one);
} else {
$max = $params->prime->subtract($one);
}
$key = new PrivateKey();
$key->prime = $params->prime;
$key->base = $params->base;
$key->privateKey = BigInteger::randomRange($one, $max);
$key->publicKey = $key->base->powMod($key->privateKey, $key->prime);
return $key;
}
/**
* Compute Shared Secret
*
* @param PrivateKey|EC $private
* @param PublicKey|BigInteger|string $public
* @return mixed
*/
public static function computeSecret($private, $public)
{
if ($private instanceof PrivateKey) {
// DH\PrivateKey
switch (\true) {
case $public instanceof PublicKey:
if (!$private->prime->equals($public->prime) || !$private->base->equals($public->base)) {
throw new \InvalidArgumentException('The public and private key do not share the same prime and / or base numbers');
}
return $public->publicKey->powMod($private->privateKey, $private->prime)->toBytes(\true);
case \is_string($public):
$public = new BigInteger($public, -256);
// fall-through
case $public instanceof BigInteger:
return $public->powMod($private->privateKey, $private->prime)->toBytes(\true);
default:
throw new \InvalidArgumentException('$public needs to be an instance of DH\\PublicKey, a BigInteger or a string');
}
}
if ($private instanceof EC\PrivateKey) {
switch (\true) {
case $public instanceof EC\PublicKey:
$public = $public->getEncodedCoordinates();
// fall-through
case \is_string($public):
$point = $private->multiply($public);
switch ($private->getCurve()) {
case 'Curve25519':
case 'Curve448':
$secret = $point;
break;
default:
// according to https://www.secg.org/sec1-v2.pdf#page=33 only X is returned
$secret = \substr($point, 1, \strlen($point) - 1 >> 1);
}
/*
if (($secret[0] & "\x80") === "\x80") {
$secret = "\0$secret";
}
*/
return $secret;
default:
throw new \InvalidArgumentException('$public needs to be an instance of EC\\PublicKey or a string (an encoded coordinate)');
}
}
}
/**
* Load the key
*
* @param string $key
* @param string $password optional
* @return AsymmetricKey
*/
public static function load($key, $password = \false)
{
try {
return EC::load($key, $password);
} catch (NoKeyLoadedException $e) {
}
return parent::load($key, $password);
}
/**
* OnLoad Handler
*
* @return bool
*/
protected static function onLoad(array $components)
{
if (!isset($components['privateKey']) && !isset($components['publicKey'])) {
$new = new Parameters();
} else {
$new = isset($components['privateKey']) ? new PrivateKey() : new PublicKey();
}
$new->prime = $components['prime'];
$new->base = $components['base'];
if (isset($components['privateKey'])) {
$new->privateKey = $components['privateKey'];
}
if (isset($components['publicKey'])) {
$new->publicKey = $components['publicKey'];
}
return $new;
}
/**
* Determines which hashing function should be used
*
* @param string $hash
*/
public function withHash($hash)
{
throw new UnsupportedOperationException('DH does not use a hash algorithm');
}
/**
* Returns the hash algorithm currently being used
*
*/
public function getHash()
{
throw new UnsupportedOperationException('DH does not use a hash algorithm');
}
/**
* Returns the parameters
*
* A public / private key is only returned if the currently loaded "key" contains an x or y
* value.
*
* @see self::getPublicKey()
* @return mixed
*/
public function getParameters()
{
$type = DH::validatePlugin('Keys', 'PKCS1', 'saveParameters');
$key = $type::saveParameters($this->prime, $this->base);
return DH::load($key, 'PKCS1');
}
}

View File

@@ -0,0 +1,65 @@
<?php
/**
* "PKCS1" Formatted EC Key Handler
*
* PHP version 5
*
* Processes keys with the following headers:
*
* -----BEGIN DH PARAMETERS-----
*
* Technically, PKCS1 is for RSA keys, only, but we're using PKCS1 to describe
* DSA, whose format isn't really formally described anywhere, so might as well
* use it to describe this, too.
*
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2015 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net
*/
namespace VendorDuplicator\phpseclib3\Crypt\DH\Formats\Keys;
use VendorDuplicator\phpseclib3\Crypt\Common\Formats\Keys\PKCS1 as Progenitor;
use VendorDuplicator\phpseclib3\File\ASN1;
use VendorDuplicator\phpseclib3\File\ASN1\Maps;
use VendorDuplicator\phpseclib3\Math\BigInteger;
/**
* "PKCS1" Formatted DH Key Handler
*
* @author Jim Wigginton <terrafrost@php.net>
*/
abstract class PKCS1 extends Progenitor
{
/**
* Break a public or private key down into its constituent components
*
* @param string $key
* @param string $password optional
* @return array
*/
public static function load($key, $password = '')
{
$key = parent::load($key, $password);
$decoded = ASN1::decodeBER($key);
if (!$decoded) {
throw new \RuntimeException('Unable to decode BER');
}
$components = ASN1::asn1map($decoded[0], Maps\DHParameter::MAP);
if (!\is_array($components)) {
throw new \RuntimeException('Unable to perform ASN1 mapping on parameters');
}
return $components;
}
/**
* Convert EC parameters to the appropriate format
*
* @return string
*/
public static function saveParameters(BigInteger $prime, BigInteger $base, array $options = [])
{
$params = ['prime' => $prime, 'base' => $base];
$params = ASN1::encodeDER($params, Maps\DHParameter::MAP);
return "-----BEGIN DH PARAMETERS-----\r\n" . \chunk_split(\base64_encode($params), 64) . "-----END DH PARAMETERS-----\r\n";
}
}

View File

@@ -0,0 +1,115 @@
<?php
/**
* PKCS#8 Formatted DH Key Handler
*
* PHP version 5
*
* Processes keys with the following headers:
*
* -----BEGIN ENCRYPTED PRIVATE KEY-----
* -----BEGIN PRIVATE KEY-----
* -----BEGIN PUBLIC KEY-----
*
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2015 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net
*/
namespace VendorDuplicator\phpseclib3\Crypt\DH\Formats\Keys;
use VendorDuplicator\phpseclib3\Crypt\Common\Formats\Keys\PKCS8 as Progenitor;
use VendorDuplicator\phpseclib3\File\ASN1;
use VendorDuplicator\phpseclib3\File\ASN1\Maps;
use VendorDuplicator\phpseclib3\Math\BigInteger;
/**
* PKCS#8 Formatted DH Key Handler
*
* @author Jim Wigginton <terrafrost@php.net>
*/
abstract class PKCS8 extends Progenitor
{
/**
* OID Name
*
* @var string
*/
const OID_NAME = 'dhKeyAgreement';
/**
* OID Value
*
* @var string
*/
const OID_VALUE = '1.2.840.113549.1.3.1';
/**
* Child OIDs loaded
*
* @var bool
*/
protected static $childOIDsLoaded = \false;
/**
* Break a public or private key down into its constituent components
*
* @param string $key
* @param string $password optional
* @return array
*/
public static function load($key, $password = '')
{
$key = parent::load($key, $password);
$type = isset($key['privateKey']) ? 'privateKey' : 'publicKey';
$decoded = ASN1::decodeBER($key[$type . 'Algorithm']['parameters']->element);
if (empty($decoded)) {
throw new \RuntimeException('Unable to decode BER of parameters');
}
$components = ASN1::asn1map($decoded[0], Maps\DHParameter::MAP);
if (!\is_array($components)) {
throw new \RuntimeException('Unable to perform ASN1 mapping on parameters');
}
$decoded = ASN1::decodeBER($key[$type]);
switch (\true) {
case !isset($decoded):
case !isset($decoded[0]['content']):
case !$decoded[0]['content'] instanceof BigInteger:
throw new \RuntimeException('Unable to decode BER of parameters');
}
$components[$type] = $decoded[0]['content'];
return $components;
}
/**
* Convert a private key to the appropriate format.
*
* @param \VendorDuplicator\phpseclib3\Math\BigInteger $prime
* @param \VendorDuplicator\phpseclib3\Math\BigInteger $base
* @param \VendorDuplicator\phpseclib3\Math\BigInteger $privateKey
* @param \VendorDuplicator\phpseclib3\Math\BigInteger $publicKey
* @param string $password optional
* @param array $options optional
* @return string
*/
public static function savePrivateKey(BigInteger $prime, BigInteger $base, BigInteger $privateKey, BigInteger $publicKey, $password = '', array $options = [])
{
$params = ['prime' => $prime, 'base' => $base];
$params = ASN1::encodeDER($params, Maps\DHParameter::MAP);
$params = new ASN1\Element($params);
$key = ASN1::encodeDER($privateKey, ['type' => ASN1::TYPE_INTEGER]);
return self::wrapPrivateKey($key, [], $params, $password, null, '', $options);
}
/**
* Convert a public key to the appropriate format
*
* @param \VendorDuplicator\phpseclib3\Math\BigInteger $prime
* @param \VendorDuplicator\phpseclib3\Math\BigInteger $base
* @param \VendorDuplicator\phpseclib3\Math\BigInteger $publicKey
* @param array $options optional
* @return string
*/
public static function savePublicKey(BigInteger $prime, BigInteger $base, BigInteger $publicKey, array $options = [])
{
$params = ['prime' => $prime, 'base' => $base];
$params = ASN1::encodeDER($params, Maps\DHParameter::MAP);
$params = new ASN1\Element($params);
$key = ASN1::encodeDER($publicKey, ['type' => ASN1::TYPE_INTEGER]);
return self::wrapPublicKey($key, $params);
}
}

View File

@@ -0,0 +1,33 @@
<?php
/**
* DH Parameters
*
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2015 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net
*/
namespace VendorDuplicator\phpseclib3\Crypt\DH;
use VendorDuplicator\phpseclib3\Crypt\DH;
/**
* DH Parameters
*
* @author Jim Wigginton <terrafrost@php.net>
*/
final class Parameters extends DH
{
/**
* Returns the parameters
*
* @param string $type
* @param array $options optional
* @return string
*/
public function toString($type = 'PKCS1', array $options = [])
{
$type = self::validatePlugin('Keys', 'PKCS1', 'saveParameters');
return $type::saveParameters($this->prime, $this->base, $options);
}
}

View File

@@ -0,0 +1,64 @@
<?php
/**
* DH Private Key
*
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2015 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net
*/
namespace VendorDuplicator\phpseclib3\Crypt\DH;
use VendorDuplicator\phpseclib3\Crypt\Common;
use VendorDuplicator\phpseclib3\Crypt\DH;
/**
* DH Private Key
*
* @author Jim Wigginton <terrafrost@php.net>
*/
final class PrivateKey extends DH
{
use Common\Traits\PasswordProtected;
/**
* Private Key
*
* @var \VendorDuplicator\phpseclib3\Math\BigInteger
*/
protected $privateKey;
/**
* Public Key
*
* @var \VendorDuplicator\phpseclib3\Math\BigInteger
*/
protected $publicKey;
/**
* Returns the public key
*
* @return DH\PublicKey
*/
public function getPublicKey()
{
$type = self::validatePlugin('Keys', 'PKCS8', 'savePublicKey');
if (!isset($this->publicKey)) {
$this->publicKey = $this->base->powMod($this->privateKey, $this->prime);
}
$key = $type::savePublicKey($this->prime, $this->base, $this->publicKey);
return DH::loadFormat('PKCS8', $key);
}
/**
* Returns the private key
*
* @param string $type
* @param array $options optional
* @return string
*/
public function toString($type, array $options = [])
{
$type = self::validatePlugin('Keys', $type, 'savePrivateKey');
if (!isset($this->publicKey)) {
$this->publicKey = $this->base->powMod($this->privateKey, $this->prime);
}
return $type::savePrivateKey($this->prime, $this->base, $this->privateKey, $this->publicKey, $this->password, $options);
}
}

View File

@@ -0,0 +1,44 @@
<?php
/**
* DH Public Key
*
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2015 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net
*/
namespace VendorDuplicator\phpseclib3\Crypt\DH;
use VendorDuplicator\phpseclib3\Crypt\Common;
use VendorDuplicator\phpseclib3\Crypt\DH;
/**
* DH Public Key
*
* @author Jim Wigginton <terrafrost@php.net>
*/
final class PublicKey extends DH
{
use Common\Traits\Fingerprint;
/**
* Returns the public key
*
* @param string $type
* @param array $options optional
* @return string
*/
public function toString($type, array $options = [])
{
$type = self::validatePlugin('Keys', $type, 'savePublicKey');
return $type::savePublicKey($this->prime, $this->base, $this->publicKey, $options);
}
/**
* Returns the public key as a BigInteger
*
* @return \VendorDuplicator\phpseclib3\Math\BigInteger
*/
public function toBigInteger()
{
return $this->publicKey;
}
}

View File

@@ -0,0 +1,292 @@
<?php
/**
* Pure-PHP FIPS 186-4 compliant implementation of DSA.
*
* PHP version 5
*
* Here's an example of how to create signatures and verify signatures with this library:
* <code>
* <?php
* include 'vendor/autoload.php';
*
* $private = \phpseclib3\Crypt\DSA::createKey();
* $public = $private->getPublicKey();
*
* $plaintext = 'terrafrost';
*
* $signature = $private->sign($plaintext);
*
* echo $public->verify($plaintext, $signature) ? 'verified' : 'unverified';
* ?>
* </code>
*
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2016 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net
*/
namespace VendorDuplicator\phpseclib3\Crypt;
use VendorDuplicator\phpseclib3\Crypt\Common\AsymmetricKey;
use VendorDuplicator\phpseclib3\Crypt\DSA\Parameters;
use VendorDuplicator\phpseclib3\Crypt\DSA\PrivateKey;
use VendorDuplicator\phpseclib3\Crypt\DSA\PublicKey;
use VendorDuplicator\phpseclib3\Exception\InsufficientSetupException;
use VendorDuplicator\phpseclib3\Math\BigInteger;
/**
* Pure-PHP FIPS 186-4 compliant implementation of DSA.
*
* @author Jim Wigginton <terrafrost@php.net>
*/
abstract class DSA extends AsymmetricKey
{
/**
* Algorithm Name
*
* @var string
*/
const ALGORITHM = 'DSA';
/**
* DSA Prime P
*
* @var \VendorDuplicator\phpseclib3\Math\BigInteger
*/
protected $p;
/**
* DSA Group Order q
*
* Prime divisor of p-1
*
* @var \VendorDuplicator\phpseclib3\Math\BigInteger
*/
protected $q;
/**
* DSA Group Generator G
*
* @var \VendorDuplicator\phpseclib3\Math\BigInteger
*/
protected $g;
/**
* DSA public key value y
*
* @var \VendorDuplicator\phpseclib3\Math\BigInteger
*/
protected $y;
/**
* Signature Format
*
* @var string
*/
protected $sigFormat;
/**
* Signature Format (Short)
*
* @var string
*/
protected $shortFormat;
/**
* Create DSA parameters
*
* @param int $L
* @param int $N
* @return \VendorDuplicator\phpseclib3\Crypt\DSA|bool
*/
public static function createParameters($L = 2048, $N = 224)
{
self::initialize_static_variables();
$class = new \ReflectionClass(static::class);
if ($class->isFinal()) {
throw new \RuntimeException('createParameters() should not be called from final classes (' . static::class . ')');
}
if (!isset(self::$engines['PHP'])) {
self::useBestEngine();
}
switch (\true) {
case $N == 160:
/*
in FIPS 186-1 and 186-2 N was fixed at 160 whereas K had an upper bound of 1024.
RFC 4253 (SSH Transport Layer Protocol) references FIPS 186-2 and as such most
SSH DSA implementations only support keys with an N of 160.
puttygen let's you set the size of L (but not the size of N) and uses 2048 as the
default L value. that's not really compliant with any of the FIPS standards, however,
for the purposes of maintaining compatibility with puttygen, we'll support it
*/
//case ($L >= 512 || $L <= 1024) && (($L & 0x3F) == 0) && $N == 160:
// FIPS 186-3 changed this as follows:
//case $L == 1024 && $N == 160:
case $L == 2048 && $N == 224:
case $L == 2048 && $N == 256:
case $L == 3072 && $N == 256:
break;
default:
throw new \InvalidArgumentException('Invalid values for N and L');
}
$two = new BigInteger(2);
$q = BigInteger::randomPrime($N);
$divisor = $q->multiply($two);
do {
$x = BigInteger::random($L);
list(, $c) = $x->divide($divisor);
$p = $x->subtract($c->subtract(self::$one));
} while ($p->getLength() != $L || !$p->isPrime());
$p_1 = $p->subtract(self::$one);
list($e) = $p_1->divide($q);
// quoting http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf#page=50 ,
// "h could be obtained from a random number generator or from a counter that
// changes after each use". PuTTY (sshdssg.c) starts h off at 1 and increments
// it on each loop. wikipedia says "commonly h = 2 is used" so we'll just do that
$h = clone $two;
while (\true) {
$g = $h->powMod($e, $p);
if (!$g->equals(self::$one)) {
break;
}
$h = $h->add(self::$one);
}
$dsa = new Parameters();
$dsa->p = $p;
$dsa->q = $q;
$dsa->g = $g;
return $dsa;
}
/**
* Create public / private key pair.
*
* This method is a bit polymorphic. It can take a DSA/Parameters object, L / N as two distinct parameters or
* no parameters (at which point L and N will be generated with this method)
*
* Returns the private key, from which the publickey can be extracted
*
* @param int[] ...$args
* @return DSA\PrivateKey
*/
public static function createKey(...$args)
{
self::initialize_static_variables();
$class = new \ReflectionClass(static::class);
if ($class->isFinal()) {
throw new \RuntimeException('createKey() should not be called from final classes (' . static::class . ')');
}
if (!isset(self::$engines['PHP'])) {
self::useBestEngine();
}
if (\count($args) == 2 && \is_int($args[0]) && \is_int($args[1])) {
$params = self::createParameters($args[0], $args[1]);
} elseif (\count($args) == 1 && $args[0] instanceof Parameters) {
$params = $args[0];
} elseif (!\count($args)) {
$params = self::createParameters();
} else {
throw new InsufficientSetupException('Valid parameters are either two integers (L and N), a single DSA object or no parameters at all.');
}
$private = new PrivateKey();
$private->p = $params->p;
$private->q = $params->q;
$private->g = $params->g;
$private->x = BigInteger::randomRange(self::$one, $private->q->subtract(self::$one));
$private->y = $private->g->powMod($private->x, $private->p);
//$public = clone $private;
//unset($public->x);
return $private->withHash($params->hash->getHash())->withSignatureFormat($params->shortFormat);
}
/**
* OnLoad Handler
*
* @return bool
*/
protected static function onLoad(array $components)
{
if (!isset(self::$engines['PHP'])) {
self::useBestEngine();
}
if (!isset($components['x']) && !isset($components['y'])) {
$new = new Parameters();
} elseif (isset($components['x'])) {
$new = new PrivateKey();
$new->x = $components['x'];
} else {
$new = new PublicKey();
}
$new->p = $components['p'];
$new->q = $components['q'];
$new->g = $components['g'];
if (isset($components['y'])) {
$new->y = $components['y'];
}
return $new;
}
/**
* Constructor
*
* PublicKey and PrivateKey objects can only be created from abstract RSA class
*/
protected function __construct()
{
$this->sigFormat = self::validatePlugin('Signature', 'ASN1');
$this->shortFormat = 'ASN1';
parent::__construct();
}
/**
* Returns the key size
*
* More specifically, this L (the length of DSA Prime P) and N (the length of DSA Group Order q)
*
* @return array
*/
public function getLength()
{
return ['L' => $this->p->getLength(), 'N' => $this->q->getLength()];
}
/**
* Returns the current engine being used
*
* @see self::useInternalEngine()
* @see self::useBestEngine()
* @return string
*/
public function getEngine()
{
if (!isset(self::$engines['PHP'])) {
self::useBestEngine();
}
return self::$engines['OpenSSL'] && \in_array($this->hash->getHash(), \openssl_get_md_methods()) ? 'OpenSSL' : 'PHP';
}
/**
* Returns the parameters
*
* A public / private key is only returned if the currently loaded "key" contains an x or y
* value.
*
* @see self::getPublicKey()
* @return mixed
*/
public function getParameters()
{
$type = self::validatePlugin('Keys', 'PKCS1', 'saveParameters');
$key = $type::saveParameters($this->p, $this->q, $this->g);
return DSA::load($key, 'PKCS1')->withHash($this->hash->getHash())->withSignatureFormat($this->shortFormat);
}
/**
* Determines the signature padding mode
*
* Valid values are: ASN1, SSH2, Raw
*
* @param string $format
*/
public function withSignatureFormat($format)
{
$new = clone $this;
$new->shortFormat = $format;
$new->sigFormat = self::validatePlugin('Signature', $format);
return $new;
}
/**
* Returns the signature format currently being used
*
*/
public function getSignatureFormat()
{
return $this->shortFormat;
}
}

View File

@@ -0,0 +1,102 @@
<?php
/**
* OpenSSH Formatted DSA Key Handler
*
* PHP version 5
*
* Place in $HOME/.ssh/authorized_keys
*
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2015 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net
*/
namespace VendorDuplicator\phpseclib3\Crypt\DSA\Formats\Keys;
use VendorDuplicator\phpseclib3\Common\Functions\Strings;
use VendorDuplicator\phpseclib3\Crypt\Common\Formats\Keys\OpenSSH as Progenitor;
use VendorDuplicator\phpseclib3\Math\BigInteger;
/**
* OpenSSH Formatted DSA Key Handler
*
* @author Jim Wigginton <terrafrost@php.net>
*/
abstract class OpenSSH extends Progenitor
{
/**
* Supported Key Types
*
* @var array
*/
protected static $types = ['ssh-dss'];
/**
* Break a public or private key down into its constituent components
*
* @param string $key
* @param string $password optional
* @return array
*/
public static function load($key, $password = '')
{
$parsed = parent::load($key, $password);
if (isset($parsed['paddedKey'])) {
list($type) = Strings::unpackSSH2('s', $parsed['paddedKey']);
if ($type != $parsed['type']) {
throw new \RuntimeException("The public and private keys are not of the same type ({$type} vs {$parsed['type']})");
}
list($p, $q, $g, $y, $x, $comment) = Strings::unpackSSH2('i5s', $parsed['paddedKey']);
return \compact('p', 'q', 'g', 'y', 'x', 'comment');
}
list($p, $q, $g, $y) = Strings::unpackSSH2('iiii', $parsed['publicKey']);
$comment = $parsed['comment'];
return \compact('p', 'q', 'g', 'y', 'comment');
}
/**
* Convert a public key to the appropriate format
*
* @param \VendorDuplicator\phpseclib3\Math\BigInteger $p
* @param \VendorDuplicator\phpseclib3\Math\BigInteger $q
* @param \VendorDuplicator\phpseclib3\Math\BigInteger $g
* @param \VendorDuplicator\phpseclib3\Math\BigInteger $y
* @param array $options optional
* @return string
*/
public static function savePublicKey(BigInteger $p, BigInteger $q, BigInteger $g, BigInteger $y, array $options = [])
{
if ($q->getLength() != 160) {
throw new \InvalidArgumentException('SSH only supports keys with an N (length of Group Order q) of 160');
}
// from <http://tools.ietf.org/html/rfc4253#page-15>:
// string "ssh-dss"
// mpint p
// mpint q
// mpint g
// mpint y
$DSAPublicKey = Strings::packSSH2('siiii', 'ssh-dss', $p, $q, $g, $y);
if (isset($options['binary']) ? $options['binary'] : self::$binary) {
return $DSAPublicKey;
}
$comment = isset($options['comment']) ? $options['comment'] : self::$comment;
$DSAPublicKey = 'ssh-dss ' . \base64_encode($DSAPublicKey) . ' ' . $comment;
return $DSAPublicKey;
}
/**
* Convert a private key to the appropriate format.
*
* @param \VendorDuplicator\phpseclib3\Math\BigInteger $p
* @param \VendorDuplicator\phpseclib3\Math\BigInteger $q
* @param \VendorDuplicator\phpseclib3\Math\BigInteger $g
* @param \VendorDuplicator\phpseclib3\Math\BigInteger $y
* @param \VendorDuplicator\phpseclib3\Math\BigInteger $x
* @param string $password optional
* @param array $options optional
* @return string
*/
public static function savePrivateKey(BigInteger $p, BigInteger $q, BigInteger $g, BigInteger $y, BigInteger $x, $password = '', array $options = [])
{
$publicKey = self::savePublicKey($p, $q, $g, $y, ['binary' => \true]);
$privateKey = Strings::packSSH2('si5', 'ssh-dss', $p, $q, $g, $y, $x);
return self::wrapPrivateKey($publicKey, $privateKey, $password, $options);
}
}

View File

@@ -0,0 +1,115 @@
<?php
/**
* PKCS#1 Formatted DSA Key Handler
*
* PHP version 5
*
* Used by File/X509.php
*
* Processes keys with the following headers:
*
* -----BEGIN DSA PRIVATE KEY-----
* -----BEGIN DSA PUBLIC KEY-----
* -----BEGIN DSA PARAMETERS-----
*
* Analogous to ssh-keygen's pem format (as specified by -m)
*
* Also, technically, PKCS1 decribes RSA but I am not aware of a formal specification for DSA.
* The DSA private key format seems to have been adapted from the RSA private key format so
* we're just re-using that as the name.
*
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2015 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net
*/
namespace VendorDuplicator\phpseclib3\Crypt\DSA\Formats\Keys;
use VendorDuplicator\phpseclib3\Common\Functions\Strings;
use VendorDuplicator\phpseclib3\Crypt\Common\Formats\Keys\PKCS1 as Progenitor;
use VendorDuplicator\phpseclib3\File\ASN1;
use VendorDuplicator\phpseclib3\File\ASN1\Maps;
use VendorDuplicator\phpseclib3\Math\BigInteger;
/**
* PKCS#1 Formatted DSA Key Handler
*
* @author Jim Wigginton <terrafrost@php.net>
*/
abstract class PKCS1 extends Progenitor
{
/**
* Break a public or private key down into its constituent components
*
* @param string $key
* @param string $password optional
* @return array
*/
public static function load($key, $password = '')
{
$key = parent::load($key, $password);
$decoded = ASN1::decodeBER($key);
if (!$decoded) {
throw new \RuntimeException('Unable to decode BER');
}
$key = ASN1::asn1map($decoded[0], Maps\DSAParams::MAP);
if (\is_array($key)) {
return $key;
}
$key = ASN1::asn1map($decoded[0], Maps\DSAPrivateKey::MAP);
if (\is_array($key)) {
return $key;
}
$key = ASN1::asn1map($decoded[0], Maps\DSAPublicKey::MAP);
if (\is_array($key)) {
return $key;
}
throw new \RuntimeException('Unable to perform ASN1 mapping');
}
/**
* Convert DSA parameters to the appropriate format
*
* @param \VendorDuplicator\phpseclib3\Math\BigInteger $p
* @param \VendorDuplicator\phpseclib3\Math\BigInteger $q
* @param \VendorDuplicator\phpseclib3\Math\BigInteger $g
* @return string
*/
public static function saveParameters(BigInteger $p, BigInteger $q, BigInteger $g)
{
$key = ['p' => $p, 'q' => $q, 'g' => $g];
$key = ASN1::encodeDER($key, Maps\DSAParams::MAP);
return "-----BEGIN DSA PARAMETERS-----\r\n" . \chunk_split(Strings::base64_encode($key), 64) . "-----END DSA PARAMETERS-----\r\n";
}
/**
* Convert a private key to the appropriate format.
*
* @param \VendorDuplicator\phpseclib3\Math\BigInteger $p
* @param \VendorDuplicator\phpseclib3\Math\BigInteger $q
* @param \VendorDuplicator\phpseclib3\Math\BigInteger $g
* @param \VendorDuplicator\phpseclib3\Math\BigInteger $y
* @param \VendorDuplicator\phpseclib3\Math\BigInteger $x
* @param string $password optional
* @param array $options optional
* @return string
*/
public static function savePrivateKey(BigInteger $p, BigInteger $q, BigInteger $g, BigInteger $y, BigInteger $x, $password = '', array $options = [])
{
$key = ['version' => 0, 'p' => $p, 'q' => $q, 'g' => $g, 'y' => $y, 'x' => $x];
$key = ASN1::encodeDER($key, Maps\DSAPrivateKey::MAP);
return self::wrapPrivateKey($key, 'DSA', $password, $options);
}
/**
* Convert a public key to the appropriate format
*
* @param \VendorDuplicator\phpseclib3\Math\BigInteger $p
* @param \VendorDuplicator\phpseclib3\Math\BigInteger $q
* @param \VendorDuplicator\phpseclib3\Math\BigInteger $g
* @param \VendorDuplicator\phpseclib3\Math\BigInteger $y
* @return string
*/
public static function savePublicKey(BigInteger $p, BigInteger $q, BigInteger $g, BigInteger $y)
{
$key = ASN1::encodeDER($y, Maps\DSAPublicKey::MAP);
return self::wrapPublicKey($key, 'DSA');
}
}

View File

@@ -0,0 +1,125 @@
<?php
/**
* PKCS#8 Formatted DSA Key Handler
*
* PHP version 5
*
* Processes keys with the following headers:
*
* -----BEGIN ENCRYPTED PRIVATE KEY-----
* -----BEGIN PRIVATE KEY-----
* -----BEGIN PUBLIC KEY-----
*
* Analogous to ssh-keygen's pkcs8 format (as specified by -m). Although PKCS8
* is specific to private keys it's basically creating a DER-encoded wrapper
* for keys. This just extends that same concept to public keys (much like ssh-keygen)
*
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2015 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net
*/
namespace VendorDuplicator\phpseclib3\Crypt\DSA\Formats\Keys;
use VendorDuplicator\phpseclib3\Crypt\Common\Formats\Keys\PKCS8 as Progenitor;
use VendorDuplicator\phpseclib3\File\ASN1;
use VendorDuplicator\phpseclib3\File\ASN1\Maps;
use VendorDuplicator\phpseclib3\Math\BigInteger;
/**
* PKCS#8 Formatted DSA Key Handler
*
* @author Jim Wigginton <terrafrost@php.net>
*/
abstract class PKCS8 extends Progenitor
{
/**
* OID Name
*
* @var string
*/
const OID_NAME = 'id-dsa';
/**
* OID Value
*
* @var string
*/
const OID_VALUE = '1.2.840.10040.4.1';
/**
* Child OIDs loaded
*
* @var bool
*/
protected static $childOIDsLoaded = \false;
/**
* Break a public or private key down into its constituent components
*
* @param string $key
* @param string $password optional
* @return array
*/
public static function load($key, $password = '')
{
$key = parent::load($key, $password);
$type = isset($key['privateKey']) ? 'privateKey' : 'publicKey';
$decoded = ASN1::decodeBER($key[$type . 'Algorithm']['parameters']->element);
if (!$decoded) {
throw new \RuntimeException('Unable to decode BER of parameters');
}
$components = ASN1::asn1map($decoded[0], Maps\DSAParams::MAP);
if (!\is_array($components)) {
throw new \RuntimeException('Unable to perform ASN1 mapping on parameters');
}
$decoded = ASN1::decodeBER($key[$type]);
if (empty($decoded)) {
throw new \RuntimeException('Unable to decode BER');
}
$var = $type == 'privateKey' ? 'x' : 'y';
$components[$var] = ASN1::asn1map($decoded[0], Maps\DSAPublicKey::MAP);
if (!$components[$var] instanceof BigInteger) {
throw new \RuntimeException('Unable to perform ASN1 mapping');
}
if (isset($key['meta'])) {
$components['meta'] = $key['meta'];
}
return $components;
}
/**
* Convert a private key to the appropriate format.
*
* @param \VendorDuplicator\phpseclib3\Math\BigInteger $p
* @param \VendorDuplicator\phpseclib3\Math\BigInteger $q
* @param \VendorDuplicator\phpseclib3\Math\BigInteger $g
* @param \VendorDuplicator\phpseclib3\Math\BigInteger $y
* @param \VendorDuplicator\phpseclib3\Math\BigInteger $x
* @param string $password optional
* @param array $options optional
* @return string
*/
public static function savePrivateKey(BigInteger $p, BigInteger $q, BigInteger $g, BigInteger $y, BigInteger $x, $password = '', array $options = [])
{
$params = ['p' => $p, 'q' => $q, 'g' => $g];
$params = ASN1::encodeDER($params, Maps\DSAParams::MAP);
$params = new ASN1\Element($params);
$key = ASN1::encodeDER($x, Maps\DSAPublicKey::MAP);
return self::wrapPrivateKey($key, [], $params, $password, null, '', $options);
}
/**
* Convert a public key to the appropriate format
*
* @param \VendorDuplicator\phpseclib3\Math\BigInteger $p
* @param \VendorDuplicator\phpseclib3\Math\BigInteger $q
* @param \VendorDuplicator\phpseclib3\Math\BigInteger $g
* @param \VendorDuplicator\phpseclib3\Math\BigInteger $y
* @param array $options optional
* @return string
*/
public static function savePublicKey(BigInteger $p, BigInteger $q, BigInteger $g, BigInteger $y, array $options = [])
{
$params = ['p' => $p, 'q' => $q, 'g' => $g];
$params = ASN1::encodeDER($params, Maps\DSAParams::MAP);
$params = new ASN1\Element($params);
$key = ASN1::encodeDER($y, Maps\DSAPublicKey::MAP);
return self::wrapPublicKey($key, $params);
}
}

View File

@@ -0,0 +1,98 @@
<?php
/**
* PuTTY Formatted DSA Key Handler
*
* puttygen does not generate DSA keys with an N of anything other than 160, however,
* it can still load them and convert them. PuTTY will load them, too, but SSH servers
* won't accept them. Since PuTTY formatted keys are primarily used with SSH this makes
* keys with N > 160 kinda useless, hence this handlers not supporting such keys.
*
* PHP version 5
*
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2015 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net
*/
namespace VendorDuplicator\phpseclib3\Crypt\DSA\Formats\Keys;
use VendorDuplicator\phpseclib3\Common\Functions\Strings;
use VendorDuplicator\phpseclib3\Crypt\Common\Formats\Keys\PuTTY as Progenitor;
use VendorDuplicator\phpseclib3\Math\BigInteger;
/**
* PuTTY Formatted DSA Key Handler
*
* @author Jim Wigginton <terrafrost@php.net>
*/
abstract class PuTTY extends Progenitor
{
/**
* Public Handler
*
* @var string
*/
const PUBLIC_HANDLER = 'VendorDuplicator\\phpseclib3\\Crypt\\DSA\\Formats\\Keys\\OpenSSH';
/**
* Algorithm Identifier
*
* @var array
*/
protected static $types = ['ssh-dss'];
/**
* Break a public or private key down into its constituent components
*
* @param string $key
* @param string $password optional
* @return array
*/
public static function load($key, $password = '')
{
$components = parent::load($key, $password);
if (!isset($components['private'])) {
return $components;
}
\extract($components);
unset($components['public'], $components['private']);
list($p, $q, $g, $y) = Strings::unpackSSH2('iiii', $public);
list($x) = Strings::unpackSSH2('i', $private);
return \compact('p', 'q', 'g', 'y', 'x', 'comment');
}
/**
* Convert a private key to the appropriate format.
*
* @param \VendorDuplicator\phpseclib3\Math\BigInteger $p
* @param \VendorDuplicator\phpseclib3\Math\BigInteger $q
* @param \VendorDuplicator\phpseclib3\Math\BigInteger $g
* @param \VendorDuplicator\phpseclib3\Math\BigInteger $y
* @param \VendorDuplicator\phpseclib3\Math\BigInteger $x
* @param string $password optional
* @param array $options optional
* @return string
*/
public static function savePrivateKey(BigInteger $p, BigInteger $q, BigInteger $g, BigInteger $y, BigInteger $x, $password = \false, array $options = [])
{
if ($q->getLength() != 160) {
throw new \InvalidArgumentException('SSH only supports keys with an N (length of Group Order q) of 160');
}
$public = Strings::packSSH2('iiii', $p, $q, $g, $y);
$private = Strings::packSSH2('i', $x);
return self::wrapPrivateKey($public, $private, 'ssh-dss', $password, $options);
}
/**
* Convert a public key to the appropriate format
*
* @param \VendorDuplicator\phpseclib3\Math\BigInteger $p
* @param \VendorDuplicator\phpseclib3\Math\BigInteger $q
* @param \VendorDuplicator\phpseclib3\Math\BigInteger $g
* @param \VendorDuplicator\phpseclib3\Math\BigInteger $y
* @return string
*/
public static function savePublicKey(BigInteger $p, BigInteger $q, BigInteger $g, BigInteger $y)
{
if ($q->getLength() != 160) {
throw new \InvalidArgumentException('SSH only supports keys with an N (length of Group Order q) of 160');
}
return self::wrapPublicKey(Strings::packSSH2('iiii', $p, $q, $g, $y), 'ssh-dss');
}
}

View File

@@ -0,0 +1,78 @@
<?php
/**
* Raw DSA Key Handler
*
* PHP version 5
*
* Reads and creates arrays as DSA keys
*
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2015 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net
*/
namespace VendorDuplicator\phpseclib3\Crypt\DSA\Formats\Keys;
use VendorDuplicator\phpseclib3\Math\BigInteger;
/**
* Raw DSA Key Handler
*
* @author Jim Wigginton <terrafrost@php.net>
*/
abstract class Raw
{
/**
* Break a public or private key down into its constituent components
*
* @param array $key
* @param string $password optional
* @return array
*/
public static function load($key, $password = '')
{
if (!\is_array($key)) {
throw new \UnexpectedValueException('Key should be a array - not a ' . \gettype($key));
}
switch (\true) {
case !isset($key['p']) || !isset($key['q']) || !isset($key['g']):
case !$key['p'] instanceof BigInteger:
case !$key['q'] instanceof BigInteger:
case !$key['g'] instanceof BigInteger:
case !isset($key['x']) && !isset($key['y']):
case isset($key['x']) && !$key['x'] instanceof BigInteger:
case isset($key['y']) && !$key['y'] instanceof BigInteger:
throw new \UnexpectedValueException('Key appears to be malformed');
}
$options = ['p' => 1, 'q' => 1, 'g' => 1, 'x' => 1, 'y' => 1];
return \array_intersect_key($key, $options);
}
/**
* Convert a private key to the appropriate format.
*
* @param \VendorDuplicator\phpseclib3\Math\BigInteger $p
* @param \VendorDuplicator\phpseclib3\Math\BigInteger $q
* @param \VendorDuplicator\phpseclib3\Math\BigInteger $g
* @param \VendorDuplicator\phpseclib3\Math\BigInteger $y
* @param \VendorDuplicator\phpseclib3\Math\BigInteger $x
* @param string $password optional
* @return string
*/
public static function savePrivateKey(BigInteger $p, BigInteger $q, BigInteger $g, BigInteger $y, BigInteger $x, $password = '')
{
return \compact('p', 'q', 'g', 'y', 'x');
}
/**
* Convert a public key to the appropriate format
*
* @param \VendorDuplicator\phpseclib3\Math\BigInteger $p
* @param \VendorDuplicator\phpseclib3\Math\BigInteger $q
* @param \VendorDuplicator\phpseclib3\Math\BigInteger $g
* @param \VendorDuplicator\phpseclib3\Math\BigInteger $y
* @return string
*/
public static function savePublicKey(BigInteger $p, BigInteger $q, BigInteger $g, BigInteger $y)
{
return \compact('p', 'q', 'g', 'y');
}
}

View File

@@ -0,0 +1,123 @@
<?php
/**
* XML Formatted DSA Key Handler
*
* While XKMS defines a private key format for RSA it does not do so for DSA. Quoting that standard:
*
* "[XKMS] does not specify private key parameters for the DSA signature algorithm since the algorithm only
* supports signature modes and so the application of server generated keys and key recovery is of limited
* value"
*
* PHP version 5
*
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2015 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net
*/
namespace VendorDuplicator\phpseclib3\Crypt\DSA\Formats\Keys;
use VendorDuplicator\phpseclib3\Common\Functions\Strings;
use VendorDuplicator\phpseclib3\Exception\BadConfigurationException;
use VendorDuplicator\phpseclib3\Math\BigInteger;
/**
* XML Formatted DSA Key Handler
*
* @author Jim Wigginton <terrafrost@php.net>
*/
abstract class XML
{
/**
* Break a public or private key down into its constituent components
*
* @param string $key
* @param string $password optional
* @return array
*/
public static function load($key, $password = '')
{
if (!Strings::is_stringable($key)) {
throw new \UnexpectedValueException('Key should be a string - not a ' . \gettype($key));
}
if (!\class_exists('DOMDocument')) {
throw new BadConfigurationException('The dom extension is not setup correctly on this system');
}
$use_errors = \libxml_use_internal_errors(\true);
$dom = new \DOMDocument();
if (\substr($key, 0, 5) != '<?xml') {
$key = '<xml>' . $key . '</xml>';
}
if (!$dom->loadXML($key)) {
\libxml_use_internal_errors($use_errors);
throw new \UnexpectedValueException('Key does not appear to contain XML');
}
$xpath = new \DOMXPath($dom);
$keys = ['p', 'q', 'g', 'y', 'j', 'seed', 'pgencounter'];
foreach ($keys as $key) {
// $dom->getElementsByTagName($key) is case-sensitive
$temp = $xpath->query("//*[translate(local-name(), 'ABCDEFGHIJKLMNOPQRSTUVWXYZ','abcdefghijklmnopqrstuvwxyz')='{$key}']");
if (!$temp->length) {
continue;
}
$value = new BigInteger(Strings::base64_decode($temp->item(0)->nodeValue), 256);
switch ($key) {
case 'p':
// a prime modulus meeting the [DSS] requirements
// Parameters P, Q, and G can be public and common to a group of users. They might be known
// from application context. As such, they are optional but P and Q must either both appear
// or both be absent
$components['p'] = $value;
break;
case 'q':
// an integer in the range 2**159 < Q < 2**160 which is a prime divisor of P-1
$components['q'] = $value;
break;
case 'g':
// an integer with certain properties with respect to P and Q
$components['g'] = $value;
break;
case 'y':
// G**X mod P (where X is part of the private key and not made public)
$components['y'] = $value;
// the remaining options do not do anything
case 'j':
// (P - 1) / Q
// Parameter J is available for inclusion solely for efficiency as it is calculatable from
// P and Q
case 'seed':
// a DSA prime generation seed
// Parameters seed and pgenCounter are used in the DSA prime number generation algorithm
// specified in [DSS]. As such, they are optional but must either both be present or both
// be absent
case 'pgencounter':
}
}
\libxml_use_internal_errors($use_errors);
if (!isset($components['y'])) {
throw new \UnexpectedValueException('Key is missing y component');
}
switch (\true) {
case !isset($components['p']):
case !isset($components['q']):
case !isset($components['g']):
return ['y' => $components['y']];
}
return $components;
}
/**
* Convert a public key to the appropriate format
*
* See https://www.w3.org/TR/xmldsig-core/#sec-DSAKeyValue
*
* @param \VendorDuplicator\phpseclib3\Math\BigInteger $p
* @param \VendorDuplicator\phpseclib3\Math\BigInteger $q
* @param \VendorDuplicator\phpseclib3\Math\BigInteger $g
* @param \VendorDuplicator\phpseclib3\Math\BigInteger $y
* @return string
*/
public static function savePublicKey(BigInteger $p, BigInteger $q, BigInteger $g, BigInteger $y)
{
return "<DSAKeyValue>\r\n" . ' <P>' . Strings::base64_encode($p->toBytes()) . "</P>\r\n" . ' <Q>' . Strings::base64_encode($q->toBytes()) . "</Q>\r\n" . ' <G>' . Strings::base64_encode($g->toBytes()) . "</G>\r\n" . ' <Y>' . Strings::base64_encode($y->toBytes()) . "</Y>\r\n" . '</DSAKeyValue>';
}
}

View File

@@ -0,0 +1,57 @@
<?php
/**
* ASN1 Signature Handler
*
* PHP version 5
*
* Handles signatures in the format described in
* https://tools.ietf.org/html/rfc3279#section-2.2.2
*
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2016 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net
*/
namespace VendorDuplicator\phpseclib3\Crypt\DSA\Formats\Signature;
use VendorDuplicator\phpseclib3\File\ASN1 as Encoder;
use VendorDuplicator\phpseclib3\File\ASN1\Maps;
use VendorDuplicator\phpseclib3\Math\BigInteger;
/**
* ASN1 Signature Handler
*
* @author Jim Wigginton <terrafrost@php.net>
*/
abstract class ASN1
{
/**
* Loads a signature
*
* @param string $sig
* @return array|bool
*/
public static function load($sig)
{
if (!\is_string($sig)) {
return \false;
}
$decoded = Encoder::decodeBER($sig);
if (empty($decoded)) {
return \false;
}
$components = Encoder::asn1map($decoded[0], Maps\DssSigValue::MAP);
return $components;
}
/**
* Returns a signature in the appropriate format
*
* @param \VendorDuplicator\phpseclib3\Math\BigInteger $r
* @param \VendorDuplicator\phpseclib3\Math\BigInteger $s
* @return string
*/
public static function save(BigInteger $r, BigInteger $s)
{
return Encoder::encodeDER(\compact('r', 's'), Maps\DssSigValue::MAP);
}
}

View File

@@ -0,0 +1,23 @@
<?php
/**
* Raw DSA Signature Handler
*
* PHP version 5
*
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2016 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net
*/
namespace VendorDuplicator\phpseclib3\Crypt\DSA\Formats\Signature;
use VendorDuplicator\phpseclib3\Crypt\Common\Formats\Signature\Raw as Progenitor;
/**
* Raw DSA Signature Handler
*
* @author Jim Wigginton <terrafrost@php.net>
*/
abstract class Raw extends Progenitor
{
}

View File

@@ -0,0 +1,61 @@
<?php
/**
* SSH2 Signature Handler
*
* PHP version 5
*
* Handles signatures in the format used by SSH2
*
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2016 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net
*/
namespace VendorDuplicator\phpseclib3\Crypt\DSA\Formats\Signature;
use VendorDuplicator\phpseclib3\Common\Functions\Strings;
use VendorDuplicator\phpseclib3\Math\BigInteger;
/**
* SSH2 Signature Handler
*
* @author Jim Wigginton <terrafrost@php.net>
*/
abstract class SSH2
{
/**
* Loads a signature
*
* @param string $sig
* @return mixed
*/
public static function load($sig)
{
if (!\is_string($sig)) {
return \false;
}
$result = Strings::unpackSSH2('ss', $sig);
if ($result === \false) {
return \false;
}
list($type, $blob) = $result;
if ($type != 'ssh-dss' || \strlen($blob) != 40) {
return \false;
}
return ['r' => new BigInteger(\substr($blob, 0, 20), 256), 's' => new BigInteger(\substr($blob, 20), 256)];
}
/**
* Returns a signature in the appropriate format
*
* @param \VendorDuplicator\phpseclib3\Math\BigInteger $r
* @param \VendorDuplicator\phpseclib3\Math\BigInteger $s
* @return string
*/
public static function save(BigInteger $r, BigInteger $s)
{
if ($r->getLength() > 160 || $s->getLength() > 160) {
return \false;
}
return Strings::packSSH2('ss', 'ssh-dss', \str_pad($r->toBytes(), 20, "\x00", \STR_PAD_LEFT) . \str_pad($s->toBytes(), 20, "\x00", \STR_PAD_LEFT));
}
}

View File

@@ -0,0 +1,33 @@
<?php
/**
* DSA Parameters
*
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2015 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net
*/
namespace VendorDuplicator\phpseclib3\Crypt\DSA;
use VendorDuplicator\phpseclib3\Crypt\DSA;
/**
* DSA Parameters
*
* @author Jim Wigginton <terrafrost@php.net>
*/
final class Parameters extends DSA
{
/**
* Returns the parameters
*
* @param string $type
* @param array $options optional
* @return string
*/
public function toString($type = 'PKCS1', array $options = [])
{
$type = self::validatePlugin('Keys', 'PKCS1', 'saveParameters');
return $type::saveParameters($this->p, $this->q, $this->g, $options);
}
}

View File

@@ -0,0 +1,131 @@
<?php
/**
* DSA Private Key
*
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2015 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net
*/
namespace VendorDuplicator\phpseclib3\Crypt\DSA;
use VendorDuplicator\phpseclib3\Crypt\Common;
use VendorDuplicator\phpseclib3\Crypt\DSA;
use VendorDuplicator\phpseclib3\Crypt\DSA\Formats\Signature\ASN1 as ASN1Signature;
use VendorDuplicator\phpseclib3\Math\BigInteger;
/**
* DSA Private Key
*
* @author Jim Wigginton <terrafrost@php.net>
*/
final class PrivateKey extends DSA implements Common\PrivateKey
{
use Common\Traits\PasswordProtected;
/**
* DSA secret exponent x
*
* @var \VendorDuplicator\phpseclib3\Math\BigInteger
*/
protected $x;
/**
* Returns the public key
*
* If you do "openssl rsa -in private.rsa -pubout -outform PEM" you get a PKCS8 formatted key
* that contains a publicKeyAlgorithm AlgorithmIdentifier and a publicKey BIT STRING.
* An AlgorithmIdentifier contains an OID and a parameters field. With RSA public keys this
* parameters field is NULL. With DSA PKCS8 public keys it is not - it contains the p, q and g
* variables. The publicKey BIT STRING contains, simply, the y variable. This can be verified
* by getting a DSA PKCS8 public key:
*
* "openssl dsa -in private.dsa -pubout -outform PEM"
*
* ie. just swap out rsa with dsa in the rsa command above.
*
* A PKCS1 public key corresponds to the publicKey portion of the PKCS8 key. In the case of RSA
* the publicKey portion /is/ the key. In the case of DSA it is not. You cannot verify a signature
* without the parameters and the PKCS1 DSA public key format does not include the parameters.
*
* @see self::getPrivateKey()
* @return mixed
*/
public function getPublicKey()
{
$type = self::validatePlugin('Keys', 'PKCS8', 'savePublicKey');
if (!isset($this->y)) {
$this->y = $this->g->powMod($this->x, $this->p);
}
$key = $type::savePublicKey($this->p, $this->q, $this->g, $this->y);
return DSA::loadFormat('PKCS8', $key)->withHash($this->hash->getHash())->withSignatureFormat($this->shortFormat);
}
/**
* Create a signature
*
* @see self::verify()
* @param string $message
* @return mixed
*/
public function sign($message)
{
$format = $this->sigFormat;
if (self::$engines['OpenSSL'] && \in_array($this->hash->getHash(), \openssl_get_md_methods())) {
$signature = '';
$result = \openssl_sign($message, $signature, $this->toString('PKCS8'), $this->hash->getHash());
if ($result) {
if ($this->shortFormat == 'ASN1') {
return $signature;
}
\extract(ASN1Signature::load($signature));
return $format::save($r, $s);
}
}
$h = $this->hash->hash($message);
$h = $this->bits2int($h);
while (\true) {
$k = BigInteger::randomRange(self::$one, $this->q->subtract(self::$one));
$r = $this->g->powMod($k, $this->p);
list(, $r) = $r->divide($this->q);
if ($r->equals(self::$zero)) {
continue;
}
$kinv = $k->modInverse($this->q);
$temp = $h->add($this->x->multiply($r));
$temp = $kinv->multiply($temp);
list(, $s) = $temp->divide($this->q);
if (!$s->equals(self::$zero)) {
break;
}
}
// the following is an RFC6979 compliant implementation of deterministic DSA
// it's unused because it's mainly intended for use when a good CSPRNG isn't
// available. if phpseclib's CSPRNG isn't good then even key generation is
// suspect
/*
$h1 = $this->hash->hash($message);
$k = $this->computek($h1);
$r = $this->g->powMod($k, $this->p);
list(, $r) = $r->divide($this->q);
$kinv = $k->modInverse($this->q);
$h1 = $this->bits2int($h1);
$temp = $h1->add($this->x->multiply($r));
$temp = $kinv->multiply($temp);
list(, $s) = $temp->divide($this->q);
*/
return $format::save($r, $s);
}
/**
* Returns the private key
*
* @param string $type
* @param array $options optional
* @return string
*/
public function toString($type, array $options = [])
{
$type = self::validatePlugin('Keys', $type, 'savePrivateKey');
if (!isset($this->y)) {
$this->y = $this->g->powMod($this->x, $this->p);
}
return $type::savePrivateKey($this->p, $this->q, $this->g, $this->y, $this->x, $this->password, $options);
}
}

View File

@@ -0,0 +1,74 @@
<?php
/**
* DSA Public Key
*
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2015 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net
*/
namespace VendorDuplicator\phpseclib3\Crypt\DSA;
use VendorDuplicator\phpseclib3\Crypt\Common;
use VendorDuplicator\phpseclib3\Crypt\DSA;
use VendorDuplicator\phpseclib3\Crypt\DSA\Formats\Signature\ASN1 as ASN1Signature;
/**
* DSA Public Key
*
* @author Jim Wigginton <terrafrost@php.net>
*/
final class PublicKey extends DSA implements Common\PublicKey
{
use Common\Traits\Fingerprint;
/**
* Verify a signature
*
* @see self::verify()
* @param string $message
* @param string $signature
* @return mixed
*/
public function verify($message, $signature)
{
$format = $this->sigFormat;
$params = $format::load($signature);
if ($params === \false || \count($params) != 2) {
return \false;
}
\extract($params);
if (self::$engines['OpenSSL'] && \in_array($this->hash->getHash(), \openssl_get_md_methods())) {
$sig = $format != 'ASN1' ? ASN1Signature::save($r, $s) : $signature;
$result = \openssl_verify($message, $sig, $this->toString('PKCS8'), $this->hash->getHash());
if ($result != -1) {
return (bool) $result;
}
}
$q_1 = $this->q->subtract(self::$one);
if (!$r->between(self::$one, $q_1) || !$s->between(self::$one, $q_1)) {
return \false;
}
$w = $s->modInverse($this->q);
$h = $this->hash->hash($message);
$h = $this->bits2int($h);
list(, $u1) = $h->multiply($w)->divide($this->q);
list(, $u2) = $r->multiply($w)->divide($this->q);
$v1 = $this->g->powMod($u1, $this->p);
$v2 = $this->y->powMod($u2, $this->p);
list(, $v) = $v1->multiply($v2)->divide($this->p);
list(, $v) = $v->divide($this->q);
return $v->equals($r);
}
/**
* Returns the public key
*
* @param string $type
* @param array $options optional
* @return string
*/
public function toString($type, array $options = [])
{
$type = self::validatePlugin('Keys', $type, 'savePublicKey');
return $type::savePublicKey($this->p, $this->q, $this->g, $this->y, $options);
}
}

View File

@@ -0,0 +1,414 @@
<?php
/**
* Pure-PHP implementation of EC.
*
* PHP version 5
*
* Here's an example of how to create signatures and verify signatures with this library:
* <code>
* <?php
* include 'vendor/autoload.php';
*
* $private = \phpseclib3\Crypt\EC::createKey('secp256k1');
* $public = $private->getPublicKey();
*
* $plaintext = 'terrafrost';
*
* $signature = $private->sign($plaintext);
*
* echo $public->verify($plaintext, $signature) ? 'verified' : 'unverified';
* ?>
* </code>
*
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2016 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net
*/
namespace VendorDuplicator\phpseclib3\Crypt;
use VendorDuplicator\phpseclib3\Crypt\Common\AsymmetricKey;
use VendorDuplicator\phpseclib3\Crypt\EC\BaseCurves\Montgomery as MontgomeryCurve;
use VendorDuplicator\phpseclib3\Crypt\EC\BaseCurves\TwistedEdwards as TwistedEdwardsCurve;
use VendorDuplicator\phpseclib3\Crypt\EC\Curves\Curve25519;
use VendorDuplicator\phpseclib3\Crypt\EC\Curves\Ed25519;
use VendorDuplicator\phpseclib3\Crypt\EC\Curves\Ed448;
use VendorDuplicator\phpseclib3\Crypt\EC\Formats\Keys\PKCS1;
use VendorDuplicator\phpseclib3\Crypt\EC\Parameters;
use VendorDuplicator\phpseclib3\Crypt\EC\PrivateKey;
use VendorDuplicator\phpseclib3\Crypt\EC\PublicKey;
use VendorDuplicator\phpseclib3\Exception\UnsupportedAlgorithmException;
use VendorDuplicator\phpseclib3\Exception\UnsupportedCurveException;
use VendorDuplicator\phpseclib3\Exception\UnsupportedOperationException;
use VendorDuplicator\phpseclib3\File\ASN1;
use VendorDuplicator\phpseclib3\File\ASN1\Maps\ECParameters;
use VendorDuplicator\phpseclib3\Math\BigInteger;
/**
* Pure-PHP implementation of EC.
*
* @author Jim Wigginton <terrafrost@php.net>
*/
abstract class EC extends AsymmetricKey
{
/**
* Algorithm Name
*
* @var string
*/
const ALGORITHM = 'EC';
/**
* Public Key QA
*
* @var object[]
*/
protected $QA;
/**
* Curve
*
* @var \VendorDuplicator\phpseclib3\Crypt\EC\BaseCurves\Base
*/
protected $curve;
/**
* Signature Format
*
* @var string
*/
protected $format;
/**
* Signature Format (Short)
*
* @var string
*/
protected $shortFormat;
/**
* Curve Name
*
* @var string
*/
private $curveName;
/**
* Curve Order
*
* Used for deterministic ECDSA
*
* @var \VendorDuplicator\phpseclib3\Math\BigInteger
*/
protected $q;
/**
* Alias for the private key
*
* Used for deterministic ECDSA. AsymmetricKey expects $x. I don't like x because
* with x you have x * the base point yielding an (x, y)-coordinate that is the
* public key. But the x is different depending on which side of the equal sign
* you're on. It's less ambiguous if you do dA * base point = (x, y)-coordinate.
*
* @var \VendorDuplicator\phpseclib3\Math\BigInteger
*/
protected $x;
/**
* Context
*
* @var string
*/
protected $context;
/**
* Signature Format
*
* @var string
*/
protected $sigFormat;
/**
* Create public / private key pair.
*
* @param string $curve
* @return \VendorDuplicator\phpseclib3\Crypt\EC\PrivateKey
*/
public static function createKey($curve)
{
self::initialize_static_variables();
$class = new \ReflectionClass(static::class);
if ($class->isFinal()) {
throw new \RuntimeException('createKey() should not be called from final classes (' . static::class . ')');
}
if (!isset(self::$engines['PHP'])) {
self::useBestEngine();
}
$curve = \strtolower($curve);
if (self::$engines['libsodium'] && $curve == 'ed25519' && \function_exists('sodium_crypto_sign_keypair')) {
$kp = \sodium_crypto_sign_keypair();
$privatekey = EC::loadFormat('libsodium', \sodium_crypto_sign_secretkey($kp));
//$publickey = EC::loadFormat('libsodium', sodium_crypto_sign_publickey($kp));
$privatekey->curveName = 'Ed25519';
//$publickey->curveName = $curve;
return $privatekey;
}
$privatekey = new PrivateKey();
$curveName = $curve;
if (\preg_match('#(?:^curve|^ed)\\d+$#', $curveName)) {
$curveName = \ucfirst($curveName);
} elseif (\substr($curveName, 0, 10) == 'brainpoolp') {
$curveName = 'brainpoolP' . \substr($curveName, 10);
}
$curve = '\\VendorDuplicator\\phpseclib3\\Crypt\\EC\\Curves\\' . $curveName;
if (!\class_exists($curve)) {
throw new UnsupportedCurveException('Named Curve of ' . $curveName . ' is not supported');
}
$reflect = new \ReflectionClass($curve);
$curveName = $reflect->isFinal() ? $reflect->getParentClass()->getShortName() : $reflect->getShortName();
$curve = new $curve();
if ($curve instanceof TwistedEdwardsCurve) {
$arr = $curve->extractSecret(Random::string($curve instanceof Ed448 ? 57 : 32));
$privatekey->dA = $dA = $arr['dA'];
$privatekey->secret = $arr['secret'];
} else {
$privatekey->dA = $dA = $curve->createRandomMultiplier();
}
if ($curve instanceof Curve25519 && self::$engines['libsodium']) {
//$r = pack('H*', '0900000000000000000000000000000000000000000000000000000000000000');
//$QA = sodium_crypto_scalarmult($dA->toBytes(), $r);
$QA = \sodium_crypto_box_publickey_from_secretkey($dA->toBytes());
$privatekey->QA = [$curve->convertInteger(new BigInteger(\strrev($QA), 256))];
} else {
$privatekey->QA = $curve->multiplyPoint($curve->getBasePoint(), $dA);
}
$privatekey->curve = $curve;
//$publickey = clone $privatekey;
//unset($publickey->dA);
//unset($publickey->x);
$privatekey->curveName = $curveName;
//$publickey->curveName = $curveName;
if ($privatekey->curve instanceof TwistedEdwardsCurve) {
return $privatekey->withHash($curve::HASH);
}
return $privatekey;
}
/**
* OnLoad Handler
*
* @return bool
*/
protected static function onLoad(array $components)
{
if (!isset(self::$engines['PHP'])) {
self::useBestEngine();
}
if (!isset($components['dA']) && !isset($components['QA'])) {
$new = new Parameters();
$new->curve = $components['curve'];
return $new;
}
$new = isset($components['dA']) ? new PrivateKey() : new PublicKey();
$new->curve = $components['curve'];
$new->QA = $components['QA'];
if (isset($components['dA'])) {
$new->dA = $components['dA'];
$new->secret = $components['secret'];
}
if ($new->curve instanceof TwistedEdwardsCurve) {
return $new->withHash($components['curve']::HASH);
}
return $new;
}
/**
* Constructor
*
* PublicKey and PrivateKey objects can only be created from abstract RSA class
*/
protected function __construct()
{
$this->sigFormat = self::validatePlugin('Signature', 'ASN1');
$this->shortFormat = 'ASN1';
parent::__construct();
}
/**
* Returns the curve
*
* Returns a string if it's a named curve, an array if not
*
* @return string|array
*/
public function getCurve()
{
if ($this->curveName) {
return $this->curveName;
}
if ($this->curve instanceof MontgomeryCurve) {
$this->curveName = $this->curve instanceof Curve25519 ? 'Curve25519' : 'Curve448';
return $this->curveName;
}
if ($this->curve instanceof TwistedEdwardsCurve) {
$this->curveName = $this->curve instanceof Ed25519 ? 'Ed25519' : 'Ed448';
return $this->curveName;
}
$params = $this->getParameters()->toString('PKCS8', ['namedCurve' => \true]);
$decoded = ASN1::extractBER($params);
$decoded = ASN1::decodeBER($decoded);
$decoded = ASN1::asn1map($decoded[0], ECParameters::MAP);
if (isset($decoded['namedCurve'])) {
$this->curveName = $decoded['namedCurve'];
return $decoded['namedCurve'];
}
if (!$namedCurves) {
PKCS1::useSpecifiedCurve();
}
return $decoded;
}
/**
* Returns the key size
*
* Quoting https://tools.ietf.org/html/rfc5656#section-2,
*
* "The size of a set of elliptic curve domain parameters on a prime
* curve is defined as the number of bits in the binary representation
* of the field order, commonly denoted by p. Size on a
* characteristic-2 curve is defined as the number of bits in the binary
* representation of the field, commonly denoted by m. A set of
* elliptic curve domain parameters defines a group of order n generated
* by a base point P"
*
* @return int
*/
public function getLength()
{
return $this->curve->getLength();
}
/**
* Returns the current engine being used
*
* @see self::useInternalEngine()
* @see self::useBestEngine()
* @return string
*/
public function getEngine()
{
if (!isset(self::$engines['PHP'])) {
self::useBestEngine();
}
if ($this->curve instanceof TwistedEdwardsCurve) {
return $this->curve instanceof Ed25519 && self::$engines['libsodium'] && !isset($this->context) ? 'libsodium' : 'PHP';
}
return self::$engines['OpenSSL'] && \in_array($this->hash->getHash(), \openssl_get_md_methods()) ? 'OpenSSL' : 'PHP';
}
/**
* Returns the public key coordinates as a string
*
* Used by ECDH
*
* @return string
*/
public function getEncodedCoordinates()
{
if ($this->curve instanceof MontgomeryCurve) {
return \strrev($this->QA[0]->toBytes(\true));
}
if ($this->curve instanceof TwistedEdwardsCurve) {
return $this->curve->encodePoint($this->QA);
}
return "\x04" . $this->QA[0]->toBytes(\true) . $this->QA[1]->toBytes(\true);
}
/**
* Returns the parameters
*
* @see self::getPublicKey()
* @param string $type optional
* @return mixed
*/
public function getParameters($type = 'PKCS1')
{
$type = self::validatePlugin('Keys', $type, 'saveParameters');
$key = $type::saveParameters($this->curve);
return EC::load($key, 'PKCS1')->withHash($this->hash->getHash())->withSignatureFormat($this->shortFormat);
}
/**
* Determines the signature padding mode
*
* Valid values are: ASN1, SSH2, Raw
*
* @param string $format
*/
public function withSignatureFormat($format)
{
if ($this->curve instanceof MontgomeryCurve) {
throw new UnsupportedOperationException('Montgomery Curves cannot be used to create signatures');
}
$new = clone $this;
$new->shortFormat = $format;
$new->sigFormat = self::validatePlugin('Signature', $format);
return $new;
}
/**
* Returns the signature format currently being used
*
*/
public function getSignatureFormat()
{
return $this->shortFormat;
}
/**
* Sets the context
*
* Used by Ed25519 / Ed448.
*
* @see self::sign()
* @see self::verify()
* @param string $context optional
*/
public function withContext($context = null)
{
if (!$this->curve instanceof TwistedEdwardsCurve) {
throw new UnsupportedCurveException('Only Ed25519 and Ed448 support contexts');
}
$new = clone $this;
if (!isset($context)) {
$new->context = null;
return $new;
}
if (!\is_string($context)) {
throw new \InvalidArgumentException('setContext expects a string');
}
if (\strlen($context) > 255) {
throw new \LengthException('The context is supposed to be, at most, 255 bytes long');
}
$new->context = $context;
return $new;
}
/**
* Returns the signature format currently being used
*
*/
public function getContext()
{
return $this->context;
}
/**
* Determines which hashing function should be used
*
* @param string $hash
*/
public function withHash($hash)
{
if ($this->curve instanceof MontgomeryCurve) {
throw new UnsupportedOperationException('Montgomery Curves cannot be used to create signatures');
}
if ($this->curve instanceof Ed25519 && $hash != 'sha512') {
throw new UnsupportedAlgorithmException('Ed25519 only supports sha512 as a hash');
}
if ($this->curve instanceof Ed448 && $hash != 'shake256-912') {
throw new UnsupportedAlgorithmException('Ed448 only supports shake256 with a length of 114 bytes');
}
return parent::withHash($hash);
}
/**
* __toString() magic method
*
* @return string
*/
public function __toString()
{
if ($this->curve instanceof MontgomeryCurve) {
return '';
}
return parent::__toString();
}
}

View File

@@ -0,0 +1,192 @@
<?php
/**
* Curve methods common to all curves
*
* PHP version 5 and 7
*
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2017 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://pear.php.net/package/Math_BigInteger
*/
namespace VendorDuplicator\phpseclib3\Crypt\EC\BaseCurves;
use VendorDuplicator\phpseclib3\Math\BigInteger;
/**
* Base
*
* @author Jim Wigginton <terrafrost@php.net>
*/
abstract class Base
{
/**
* The Order
*
* @var BigInteger
*/
protected $order;
/**
* Finite Field Integer factory
*
* @var \VendorDuplicator\phpseclib3\Math\FiniteField\Integer
*/
protected $factory;
/**
* Returns a random integer
*
* @return object
*/
public function randomInteger()
{
return $this->factory->randomInteger();
}
/**
* Converts a BigInteger to a \phpseclib3\Math\FiniteField\Integer integer
*
* @return object
*/
public function convertInteger(BigInteger $x)
{
return $this->factory->newInteger($x);
}
/**
* Returns the length, in bytes, of the modulo
*
* @return integer
*/
public function getLengthInBytes()
{
return $this->factory->getLengthInBytes();
}
/**
* Returns the length, in bits, of the modulo
*
* @return integer
*/
public function getLength()
{
return $this->factory->getLength();
}
/**
* Multiply a point on the curve by a scalar
*
* Uses the montgomery ladder technique as described here:
*
* https://en.wikipedia.org/wiki/Elliptic_curve_point_multiplication#Montgomery_ladder
* https://github.com/phpecc/phpecc/issues/16#issuecomment-59176772
*
* @return array
*/
public function multiplyPoint(array $p, BigInteger $d)
{
$alreadyInternal = isset($p[2]);
$r = $alreadyInternal ? [[], $p] : [[], $this->convertToInternal($p)];
$d = $d->toBits();
for ($i = 0; $i < \strlen($d); $i++) {
$d_i = (int) $d[$i];
$r[1 - $d_i] = $this->addPoint($r[0], $r[1]);
$r[$d_i] = $this->doublePoint($r[$d_i]);
}
return $alreadyInternal ? $r[0] : $this->convertToAffine($r[0]);
}
/**
* Creates a random scalar multiplier
*
* @return BigInteger
*/
public function createRandomMultiplier()
{
static $one;
if (!isset($one)) {
$one = new BigInteger(1);
}
return BigInteger::randomRange($one, $this->order->subtract($one));
}
/**
* Performs range check
*/
public function rangeCheck(BigInteger $x)
{
static $zero;
if (!isset($zero)) {
$zero = new BigInteger();
}
if (!isset($this->order)) {
throw new \RuntimeException('setOrder needs to be called before this method');
}
if ($x->compare($this->order) > 0 || $x->compare($zero) <= 0) {
throw new \RangeException('x must be between 1 and the order of the curve');
}
}
/**
* Sets the Order
*/
public function setOrder(BigInteger $order)
{
$this->order = $order;
}
/**
* Returns the Order
*
* @return \VendorDuplicator\phpseclib3\Math\BigInteger
*/
public function getOrder()
{
return $this->order;
}
/**
* Use a custom defined modular reduction function
*
* @return object
*/
public function setReduction(callable $func)
{
$this->factory->setReduction($func);
}
/**
* Returns the affine point
*
* @return object[]
*/
public function convertToAffine(array $p)
{
return $p;
}
/**
* Converts an affine point to a jacobian coordinate
*
* @return object[]
*/
public function convertToInternal(array $p)
{
return $p;
}
/**
* Negates a point
*
* @return object[]
*/
public function negatePoint(array $p)
{
$temp = [$p[0], $p[1]->negate()];
if (isset($p[2])) {
$temp[] = $p[2];
}
return $temp;
}
/**
* Multiply and Add Points
*
* @return int[]
*/
public function multiplyAddPoints(array $points, array $scalars)
{
$p1 = $this->convertToInternal($points[0]);
$p2 = $this->convertToInternal($points[1]);
$p1 = $this->multiplyPoint($p1, $scalars[0]);
$p2 = $this->multiplyPoint($p2, $scalars[1]);
$r = $this->addPoint($p1, $p2);
return $this->convertToAffine($r);
}
}

View File

@@ -0,0 +1,324 @@
<?php
/**
* Curves over y^2 + x*y = x^3 + a*x^2 + b
*
* These are curves used in SEC 2 over prime fields: http://www.secg.org/SEC2-Ver-1.0.pdf
* The curve is a weierstrass curve with a[3] and a[2] set to 0.
*
* Uses Jacobian Coordinates for speed if able:
*
* https://en.wikipedia.org/wiki/Jacobian_curve
* https://en.wikibooks.org/wiki/Cryptography/Prime_Curve/Jacobian_Coordinates
*
* PHP version 5 and 7
*
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2017 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://pear.php.net/package/Math_BigInteger
*/
namespace VendorDuplicator\phpseclib3\Crypt\EC\BaseCurves;
use VendorDuplicator\phpseclib3\Math\BigInteger;
use VendorDuplicator\phpseclib3\Math\BinaryField;
use VendorDuplicator\phpseclib3\Math\BinaryField\Integer as BinaryInteger;
/**
* Curves over y^2 + x*y = x^3 + a*x^2 + b
*
* @author Jim Wigginton <terrafrost@php.net>
*/
class Binary extends Base
{
/**
* Binary Field Integer factory
*
* @var \VendorDuplicator\phpseclib3\Math\BinaryField
*/
protected $factory;
/**
* Cofficient for x^1
*
* @var object
*/
protected $a;
/**
* Cofficient for x^0
*
* @var object
*/
protected $b;
/**
* Base Point
*
* @var object
*/
protected $p;
/**
* The number one over the specified finite field
*
* @var object
*/
protected $one;
/**
* The modulo
*
* @var BigInteger
*/
protected $modulo;
/**
* The Order
*
* @var BigInteger
*/
protected $order;
/**
* Sets the modulo
*/
public function setModulo(...$modulo)
{
$this->modulo = $modulo;
$this->factory = new BinaryField(...$modulo);
$this->one = $this->factory->newInteger("\x01");
}
/**
* Set coefficients a and b
*
* @param string $a
* @param string $b
*/
public function setCoefficients($a, $b)
{
if (!isset($this->factory)) {
throw new \RuntimeException('setModulo needs to be called before this method');
}
$this->a = $this->factory->newInteger(\pack('H*', $a));
$this->b = $this->factory->newInteger(\pack('H*', $b));
}
/**
* Set x and y coordinates for the base point
*
* @param string|BinaryInteger $x
* @param string|BinaryInteger $y
*/
public function setBasePoint($x, $y)
{
switch (\true) {
case !\is_string($x) && !$x instanceof BinaryInteger:
throw new \UnexpectedValueException('Argument 1 passed to Binary::setBasePoint() must be a string or an instance of BinaryField\\Integer');
case !\is_string($y) && !$y instanceof BinaryInteger:
throw new \UnexpectedValueException('Argument 2 passed to Binary::setBasePoint() must be a string or an instance of BinaryField\\Integer');
}
if (!isset($this->factory)) {
throw new \RuntimeException('setModulo needs to be called before this method');
}
$this->p = [\is_string($x) ? $this->factory->newInteger(\pack('H*', $x)) : $x, \is_string($y) ? $this->factory->newInteger(\pack('H*', $y)) : $y];
}
/**
* Retrieve the base point as an array
*
* @return array
*/
public function getBasePoint()
{
if (!isset($this->factory)) {
throw new \RuntimeException('setModulo needs to be called before this method');
}
/*
if (!isset($this->p)) {
throw new \RuntimeException('setBasePoint needs to be called before this method');
}
*/
return $this->p;
}
/**
* Adds two points on the curve
*
* @return FiniteField[]
*/
public function addPoint(array $p, array $q)
{
if (!isset($this->factory)) {
throw new \RuntimeException('setModulo needs to be called before this method');
}
if (!\count($p) || !\count($q)) {
if (\count($q)) {
return $q;
}
if (\count($p)) {
return $p;
}
return [];
}
if (!isset($p[2]) || !isset($q[2])) {
throw new \RuntimeException('Affine coordinates need to be manually converted to "Jacobi" coordinates or vice versa');
}
if ($p[0]->equals($q[0])) {
return !$p[1]->equals($q[1]) ? [] : $this->doublePoint($p);
}
// formulas from http://hyperelliptic.org/EFD/g12o/auto-shortw-jacobian.html
list($x1, $y1, $z1) = $p;
list($x2, $y2, $z2) = $q;
$o1 = $z1->multiply($z1);
$b = $x2->multiply($o1);
if ($z2->equals($this->one)) {
$d = $y2->multiply($o1)->multiply($z1);
$e = $x1->add($b);
$f = $y1->add($d);
$z3 = $e->multiply($z1);
$h = $f->multiply($x2)->add($z3->multiply($y2));
$i = $f->add($z3);
$g = $z3->multiply($z3);
$p1 = $this->a->multiply($g);
$p2 = $f->multiply($i);
$p3 = $e->multiply($e)->multiply($e);
$x3 = $p1->add($p2)->add($p3);
$y3 = $i->multiply($x3)->add($g->multiply($h));
return [$x3, $y3, $z3];
}
$o2 = $z2->multiply($z2);
$a = $x1->multiply($o2);
$c = $y1->multiply($o2)->multiply($z2);
$d = $y2->multiply($o1)->multiply($z1);
$e = $a->add($b);
$f = $c->add($d);
$g = $e->multiply($z1);
$h = $f->multiply($x2)->add($g->multiply($y2));
$z3 = $g->multiply($z2);
$i = $f->add($z3);
$p1 = $this->a->multiply($z3->multiply($z3));
$p2 = $f->multiply($i);
$p3 = $e->multiply($e)->multiply($e);
$x3 = $p1->add($p2)->add($p3);
$y3 = $i->multiply($x3)->add($g->multiply($g)->multiply($h));
return [$x3, $y3, $z3];
}
/**
* Doubles a point on a curve
*
* @return FiniteField[]
*/
public function doublePoint(array $p)
{
if (!isset($this->factory)) {
throw new \RuntimeException('setModulo needs to be called before this method');
}
if (!\count($p)) {
return [];
}
if (!isset($p[2])) {
throw new \RuntimeException('Affine coordinates need to be manually converted to "Jacobi" coordinates or vice versa');
}
// formulas from http://hyperelliptic.org/EFD/g12o/auto-shortw-jacobian.html
list($x1, $y1, $z1) = $p;
$a = $x1->multiply($x1);
$b = $a->multiply($a);
if ($z1->equals($this->one)) {
$x3 = $b->add($this->b);
$z3 = clone $x1;
$p1 = $a->add($y1)->add($z3)->multiply($this->b);
$p2 = $a->add($y1)->multiply($b);
$y3 = $p1->add($p2);
return [$x3, $y3, $z3];
}
$c = $z1->multiply($z1);
$d = $c->multiply($c);
$x3 = $b->add($this->b->multiply($d->multiply($d)));
$z3 = $x1->multiply($c);
$p1 = $b->multiply($z3);
$p2 = $a->add($y1->multiply($z1))->add($z3)->multiply($x3);
$y3 = $p1->add($p2);
return [$x3, $y3, $z3];
}
/**
* Returns the X coordinate and the derived Y coordinate
*
* Not supported because it is covered by patents.
* Quoting https://www.openssl.org/docs/man1.1.0/apps/ecparam.html ,
*
* "Due to patent issues the compressed option is disabled by default for binary curves
* and can be enabled by defining the preprocessor macro OPENSSL_EC_BIN_PT_COMP at
* compile time."
*
* @return array
*/
public function derivePoint($m)
{
throw new \RuntimeException('Point compression on binary finite field elliptic curves is not supported');
}
/**
* Tests whether or not the x / y values satisfy the equation
*
* @return boolean
*/
public function verifyPoint(array $p)
{
list($x, $y) = $p;
$lhs = $y->multiply($y);
$lhs = $lhs->add($x->multiply($y));
$x2 = $x->multiply($x);
$x3 = $x2->multiply($x);
$rhs = $x3->add($this->a->multiply($x2))->add($this->b);
return $lhs->equals($rhs);
}
/**
* Returns the modulo
*
* @return \VendorDuplicator\phpseclib3\Math\BigInteger
*/
public function getModulo()
{
return $this->modulo;
}
/**
* Returns the a coefficient
*
* @return \VendorDuplicator\phpseclib3\Math\PrimeField\Integer
*/
public function getA()
{
return $this->a;
}
/**
* Returns the a coefficient
*
* @return \VendorDuplicator\phpseclib3\Math\PrimeField\Integer
*/
public function getB()
{
return $this->b;
}
/**
* Returns the affine point
*
* A Jacobian Coordinate is of the form (x, y, z).
* To convert a Jacobian Coordinate to an Affine Point
* you do (x / z^2, y / z^3)
*
* @return \VendorDuplicator\phpseclib3\Math\PrimeField\Integer[]
*/
public function convertToAffine(array $p)
{
if (!isset($p[2])) {
return $p;
}
list($x, $y, $z) = $p;
$z = $this->one->divide($z);
$z2 = $z->multiply($z);
return [$x->multiply($z2), $y->multiply($z2)->multiply($z)];
}
/**
* Converts an affine point to a jacobian coordinate
*
* @return \VendorDuplicator\phpseclib3\Math\PrimeField\Integer[]
*/
public function convertToInternal(array $p)
{
if (isset($p[2])) {
return $p;
}
$p[2] = clone $this->one;
$p['fresh'] = \true;
return $p;
}
}

View File

@@ -0,0 +1,273 @@
<?php
/**
* Generalized Koblitz Curves over y^2 = x^3 + b.
*
* According to http://www.secg.org/SEC2-Ver-1.0.pdf Koblitz curves are over the GF(2**m)
* finite field. Both the $a$ and $b$ coefficients are either 0 or 1. However, SEC2
* generalizes the definition to include curves over GF(P) "which possess an efficiently
* computable endomorphism".
*
* For these generalized Koblitz curves $b$ doesn't have to be 0 or 1. Whether or not $a$
* has any restrictions on it is unclear, however, for all the GF(P) Koblitz curves defined
* in SEC2 v1.0 $a$ is $0$ so all of the methods defined herein will assume that it is.
*
* I suppose we could rename the $b$ coefficient to $a$, however, the documentation refers
* to $b$ so we'll just keep it.
*
* If a later version of SEC2 comes out wherein some $a$ values are non-zero we can create a
* new method for those. eg. KoblitzA1Prime.php or something.
*
* PHP version 5 and 7
*
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2017 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://pear.php.net/package/Math_BigInteger
*/
namespace VendorDuplicator\phpseclib3\Crypt\EC\BaseCurves;
use VendorDuplicator\phpseclib3\Math\BigInteger;
use VendorDuplicator\phpseclib3\Math\PrimeField;
/**
* Curves over y^2 = x^3 + b
*
* @author Jim Wigginton <terrafrost@php.net>
*/
class KoblitzPrime extends Prime
{
/**
* Basis
*
* @var list<array{a: BigInteger, b: BigInteger}>
*/
protected $basis;
/**
* Beta
*
* @var PrimeField\Integer
*/
protected $beta;
// don't overwrite setCoefficients() with one that only accepts one parameter so that
// one might be able to switch between KoblitzPrime and Prime more easily (for benchmarking
// purposes).
/**
* Multiply and Add Points
*
* Uses a efficiently computable endomorphism to achieve a slight speedup
*
* Adapted from:
* https://github.com/indutny/elliptic/blob/725bd91/lib/elliptic/curve/short.js#L219
*
* @return int[]
*/
public function multiplyAddPoints(array $points, array $scalars)
{
static $zero, $one, $two;
if (!isset($two)) {
$two = new BigInteger(2);
$one = new BigInteger(1);
}
if (!isset($this->beta)) {
// get roots
$inv = $this->one->divide($this->two)->negate();
$s = $this->three->negate()->squareRoot()->multiply($inv);
$betas = [$inv->add($s), $inv->subtract($s)];
$this->beta = $betas[0]->compare($betas[1]) < 0 ? $betas[0] : $betas[1];
//echo strtoupper($this->beta->toHex(true)) . "\n"; exit;
}
if (!isset($this->basis)) {
$factory = new PrimeField($this->order);
$tempOne = $factory->newInteger($one);
$tempTwo = $factory->newInteger($two);
$tempThree = $factory->newInteger(new BigInteger(3));
$inv = $tempOne->divide($tempTwo)->negate();
$s = $tempThree->negate()->squareRoot()->multiply($inv);
$lambdas = [$inv->add($s), $inv->subtract($s)];
$lhs = $this->multiplyPoint($this->p, $lambdas[0])[0];
$rhs = $this->p[0]->multiply($this->beta);
$lambda = $lhs->equals($rhs) ? $lambdas[0] : $lambdas[1];
$this->basis = static::extendedGCD($lambda->toBigInteger(), $this->order);
///*
foreach ($this->basis as $basis) {
echo \strtoupper($basis['a']->toHex(\true)) . "\n";
echo \strtoupper($basis['b']->toHex(\true)) . "\n\n";
}
exit;
//*/
}
$npoints = $nscalars = [];
for ($i = 0; $i < \count($points); $i++) {
$p = $points[$i];
$k = $scalars[$i]->toBigInteger();
// begin split
list($v1, $v2) = $this->basis;
$c1 = $v2['b']->multiply($k);
list($c1, $r) = $c1->divide($this->order);
if ($this->order->compare($r->multiply($two)) <= 0) {
$c1 = $c1->add($one);
}
$c2 = $v1['b']->negate()->multiply($k);
list($c2, $r) = $c2->divide($this->order);
if ($this->order->compare($r->multiply($two)) <= 0) {
$c2 = $c2->add($one);
}
$p1 = $c1->multiply($v1['a']);
$p2 = $c2->multiply($v2['a']);
$q1 = $c1->multiply($v1['b']);
$q2 = $c2->multiply($v2['b']);
$k1 = $k->subtract($p1)->subtract($p2);
$k2 = $q1->add($q2)->negate();
// end split
$beta = [$p[0]->multiply($this->beta), $p[1], clone $this->one];
if (isset($p['naf'])) {
$beta['naf'] = \array_map(function ($p) {
return [$p[0]->multiply($this->beta), $p[1], clone $this->one];
}, $p['naf']);
$beta['nafwidth'] = $p['nafwidth'];
}
if ($k1->isNegative()) {
$k1 = $k1->negate();
$p = $this->negatePoint($p);
}
if ($k2->isNegative()) {
$k2 = $k2->negate();
$beta = $this->negatePoint($beta);
}
$pos = 2 * $i;
$npoints[$pos] = $p;
$nscalars[$pos] = $this->factory->newInteger($k1);
$pos++;
$npoints[$pos] = $beta;
$nscalars[$pos] = $this->factory->newInteger($k2);
}
return parent::multiplyAddPoints($npoints, $nscalars);
}
/**
* Returns the numerator and denominator of the slope
*
* @return FiniteField[]
*/
protected function doublePointHelper(array $p)
{
$numerator = $this->three->multiply($p[0])->multiply($p[0]);
$denominator = $this->two->multiply($p[1]);
return [$numerator, $denominator];
}
/**
* Doubles a jacobian coordinate on the curve
*
* See http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-dbl-2009-l
*
* @return FiniteField[]
*/
protected function jacobianDoublePoint(array $p)
{
list($x1, $y1, $z1) = $p;
$a = $x1->multiply($x1);
$b = $y1->multiply($y1);
$c = $b->multiply($b);
$d = $x1->add($b);
$d = $d->multiply($d)->subtract($a)->subtract($c)->multiply($this->two);
$e = $this->three->multiply($a);
$f = $e->multiply($e);
$x3 = $f->subtract($this->two->multiply($d));
$y3 = $e->multiply($d->subtract($x3))->subtract($this->eight->multiply($c));
$z3 = $this->two->multiply($y1)->multiply($z1);
return [$x3, $y3, $z3];
}
/**
* Doubles a "fresh" jacobian coordinate on the curve
*
* See http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-mdbl-2007-bl
*
* @return FiniteField[]
*/
protected function jacobianDoublePointMixed(array $p)
{
list($x1, $y1) = $p;
$xx = $x1->multiply($x1);
$yy = $y1->multiply($y1);
$yyyy = $yy->multiply($yy);
$s = $x1->add($yy);
$s = $s->multiply($s)->subtract($xx)->subtract($yyyy)->multiply($this->two);
$m = $this->three->multiply($xx);
$t = $m->multiply($m)->subtract($this->two->multiply($s));
$x3 = $t;
$y3 = $s->subtract($t);
$y3 = $m->multiply($y3)->subtract($this->eight->multiply($yyyy));
$z3 = $this->two->multiply($y1);
return [$x3, $y3, $z3];
}
/**
* Tests whether or not the x / y values satisfy the equation
*
* @return boolean
*/
public function verifyPoint(array $p)
{
list($x, $y) = $p;
$lhs = $y->multiply($y);
$temp = $x->multiply($x)->multiply($x);
$rhs = $temp->add($this->b);
return $lhs->equals($rhs);
}
/**
* Calculates the parameters needed from the Euclidean algorithm as discussed at
* http://diamond.boisestate.edu/~liljanab/MATH308/GuideToECC.pdf#page=148
*
* @param BigInteger $u
* @param BigInteger $v
* @return BigInteger[]
*/
protected static function extendedGCD(BigInteger $u, BigInteger $v)
{
$one = new BigInteger(1);
$zero = new BigInteger();
$a = clone $one;
$b = clone $zero;
$c = clone $zero;
$d = clone $one;
$stop = $v->bitwise_rightShift($v->getLength() >> 1);
$a1 = clone $zero;
$b1 = clone $zero;
$a2 = clone $zero;
$b2 = clone $zero;
$postGreatestIndex = 0;
while (!$v->equals($zero)) {
list($q) = $u->divide($v);
$temp = $u;
$u = $v;
$v = $temp->subtract($v->multiply($q));
$temp = $a;
$a = $c;
$c = $temp->subtract($a->multiply($q));
$temp = $b;
$b = $d;
$d = $temp->subtract($b->multiply($q));
if ($v->compare($stop) > 0) {
$a0 = $v;
$b0 = $c;
} else {
$postGreatestIndex++;
}
if ($postGreatestIndex == 1) {
$a1 = $v;
$b1 = $c->negate();
}
if ($postGreatestIndex == 2) {
$rhs = $a0->multiply($a0)->add($b0->multiply($b0));
$lhs = $v->multiply($v)->add($b->multiply($b));
if ($lhs->compare($rhs) <= 0) {
$a2 = $a0;
$b2 = $b0->negate();
} else {
$a2 = $v;
$b2 = $c->negate();
}
break;
}
}
return [['a' => $a1, 'b' => $b1], ['a' => $a2, 'b' => $b2]];
}
}

View File

@@ -0,0 +1,246 @@
<?php
/**
* Curves over y^2 = x^3 + a*x + x
*
* Technically, a Montgomery curve has a coefficient for y^2 but for Curve25519 and Curve448 that
* coefficient is 1.
*
* Curve25519 and Curve448 do not make use of the y coordinate, which makes it unsuitable for use
* with ECDSA / EdDSA. A few other differences between Curve25519 and Ed25519 are discussed at
* https://crypto.stackexchange.com/a/43058/4520
*
* More info:
*
* https://en.wikipedia.org/wiki/Montgomery_curve
*
* PHP version 5 and 7
*
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2019 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://pear.php.net/package/Math_BigInteger
*/
namespace VendorDuplicator\phpseclib3\Crypt\EC\BaseCurves;
use VendorDuplicator\phpseclib3\Crypt\EC\Curves\Curve25519;
use VendorDuplicator\phpseclib3\Math\BigInteger;
use VendorDuplicator\phpseclib3\Math\PrimeField;
use VendorDuplicator\phpseclib3\Math\PrimeField\Integer as PrimeInteger;
/**
* Curves over y^2 = x^3 + a*x + x
*
* @author Jim Wigginton <terrafrost@php.net>
*/
class Montgomery extends Base
{
/**
* Prime Field Integer factory
*
* @var \VendorDuplicator\phpseclib3\Math\PrimeField
*/
protected $factory;
/**
* Cofficient for x
*
* @var object
*/
protected $a;
/**
* Constant used for point doubling
*
* @var object
*/
protected $a24;
/**
* The Number Zero
*
* @var object
*/
protected $zero;
/**
* The Number One
*
* @var object
*/
protected $one;
/**
* Base Point
*
* @var object
*/
protected $p;
/**
* The modulo
*
* @var BigInteger
*/
protected $modulo;
/**
* The Order
*
* @var BigInteger
*/
protected $order;
/**
* Sets the modulo
*/
public function setModulo(BigInteger $modulo)
{
$this->modulo = $modulo;
$this->factory = new PrimeField($modulo);
$this->zero = $this->factory->newInteger(new BigInteger());
$this->one = $this->factory->newInteger(new BigInteger(1));
}
/**
* Set coefficients a
*/
public function setCoefficients(BigInteger $a)
{
if (!isset($this->factory)) {
throw new \RuntimeException('setModulo needs to be called before this method');
}
$this->a = $this->factory->newInteger($a);
$two = $this->factory->newInteger(new BigInteger(2));
$four = $this->factory->newInteger(new BigInteger(4));
$this->a24 = $this->a->subtract($two)->divide($four);
}
/**
* Set x and y coordinates for the base point
*
* @param BigInteger|PrimeInteger $x
* @param BigInteger|PrimeInteger $y
* @return PrimeInteger[]
*/
public function setBasePoint($x, $y)
{
switch (\true) {
case !$x instanceof BigInteger && !$x instanceof PrimeInteger:
throw new \UnexpectedValueException('Argument 1 passed to Prime::setBasePoint() must be an instance of either BigInteger or PrimeField\\Integer');
case !$y instanceof BigInteger && !$y instanceof PrimeInteger:
throw new \UnexpectedValueException('Argument 2 passed to Prime::setBasePoint() must be an instance of either BigInteger or PrimeField\\Integer');
}
if (!isset($this->factory)) {
throw new \RuntimeException('setModulo needs to be called before this method');
}
$this->p = [$x instanceof BigInteger ? $this->factory->newInteger($x) : $x, $y instanceof BigInteger ? $this->factory->newInteger($y) : $y];
}
/**
* Retrieve the base point as an array
*
* @return array
*/
public function getBasePoint()
{
if (!isset($this->factory)) {
throw new \RuntimeException('setModulo needs to be called before this method');
}
/*
if (!isset($this->p)) {
throw new \RuntimeException('setBasePoint needs to be called before this method');
}
*/
return $this->p;
}
/**
* Doubles and adds a point on a curve
*
* See https://tools.ietf.org/html/draft-ietf-tls-curve25519-01#appendix-A.1.3
*
* @return FiniteField[][]
*/
private function doubleAndAddPoint(array $p, array $q, PrimeInteger $x1)
{
if (!isset($this->factory)) {
throw new \RuntimeException('setModulo needs to be called before this method');
}
if (!\count($p) || !\count($q)) {
return [];
}
if (!isset($p[1])) {
throw new \RuntimeException('Affine coordinates need to be manually converted to XZ coordinates');
}
list($x2, $z2) = $p;
list($x3, $z3) = $q;
$a = $x2->add($z2);
$aa = $a->multiply($a);
$b = $x2->subtract($z2);
$bb = $b->multiply($b);
$e = $aa->subtract($bb);
$c = $x3->add($z3);
$d = $x3->subtract($z3);
$da = $d->multiply($a);
$cb = $c->multiply($b);
$temp = $da->add($cb);
$x5 = $temp->multiply($temp);
$temp = $da->subtract($cb);
$z5 = $x1->multiply($temp->multiply($temp));
$x4 = $aa->multiply($bb);
$temp = static::class == Curve25519::class ? $bb : $aa;
$z4 = $e->multiply($temp->add($this->a24->multiply($e)));
return [[$x4, $z4], [$x5, $z5]];
}
/**
* Multiply a point on the curve by a scalar
*
* Uses the montgomery ladder technique as described here:
*
* https://en.wikipedia.org/wiki/Elliptic_curve_point_multiplication#Montgomery_ladder
* https://github.com/phpecc/phpecc/issues/16#issuecomment-59176772
*
* @return array
*/
public function multiplyPoint(array $p, BigInteger $d)
{
$p1 = [$this->one, $this->zero];
$alreadyInternal = isset($x[1]);
$p2 = $this->convertToInternal($p);
$x = $p[0];
$b = $d->toBits();
$b = \str_pad($b, 256, '0', \STR_PAD_LEFT);
for ($i = 0; $i < \strlen($b); $i++) {
$b_i = (int) $b[$i];
if ($b_i) {
list($p2, $p1) = $this->doubleAndAddPoint($p2, $p1, $x);
} else {
list($p1, $p2) = $this->doubleAndAddPoint($p1, $p2, $x);
}
}
return $alreadyInternal ? $p1 : $this->convertToAffine($p1);
}
/**
* Converts an affine point to an XZ coordinate
*
* From https://hyperelliptic.org/EFD/g1p/auto-montgom-xz.html
*
* XZ coordinates represent x y as X Z satsfying the following equations:
*
* x=X/Z
*
* @return \VendorDuplicator\phpseclib3\Math\PrimeField\Integer[]
*/
public function convertToInternal(array $p)
{
if (empty($p)) {
return [clone $this->zero, clone $this->one];
}
if (isset($p[1])) {
return $p;
}
$p[1] = clone $this->one;
return $p;
}
/**
* Returns the affine point
*
* @return \VendorDuplicator\phpseclib3\Math\PrimeField\Integer[]
*/
public function convertToAffine(array $p)
{
if (!isset($p[1])) {
return $p;
}
list($x, $z) = $p;
return [$x->divide($z)];
}
}

View File

@@ -0,0 +1,695 @@
<?php
/**
* Curves over y^2 = x^3 + a*x + b
*
* These are curves used in SEC 2 over prime fields: http://www.secg.org/SEC2-Ver-1.0.pdf
* The curve is a weierstrass curve with a[1], a[3] and a[2] set to 0.
*
* Uses Jacobian Coordinates for speed if able:
*
* https://en.wikipedia.org/wiki/Jacobian_curve
* https://en.wikibooks.org/wiki/Cryptography/Prime_Curve/Jacobian_Coordinates
*
* PHP version 5 and 7
*
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2017 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://pear.php.net/package/Math_BigInteger
*/
namespace VendorDuplicator\phpseclib3\Crypt\EC\BaseCurves;
use VendorDuplicator\phpseclib3\Common\Functions\Strings;
use VendorDuplicator\phpseclib3\Math\BigInteger;
use VendorDuplicator\phpseclib3\Math\Common\FiniteField\Integer;
use VendorDuplicator\phpseclib3\Math\PrimeField;
use VendorDuplicator\phpseclib3\Math\PrimeField\Integer as PrimeInteger;
/**
* Curves over y^2 = x^3 + a*x + b
*
* @author Jim Wigginton <terrafrost@php.net>
*/
class Prime extends Base
{
/**
* Prime Field Integer factory
*
* @var \VendorDuplicator\phpseclib3\Math\PrimeFields
*/
protected $factory;
/**
* Cofficient for x^1
*
* @var object
*/
protected $a;
/**
* Cofficient for x^0
*
* @var object
*/
protected $b;
/**
* Base Point
*
* @var object
*/
protected $p;
/**
* The number one over the specified finite field
*
* @var object
*/
protected $one;
/**
* The number two over the specified finite field
*
* @var object
*/
protected $two;
/**
* The number three over the specified finite field
*
* @var object
*/
protected $three;
/**
* The number four over the specified finite field
*
* @var object
*/
protected $four;
/**
* The number eight over the specified finite field
*
* @var object
*/
protected $eight;
/**
* The modulo
*
* @var BigInteger
*/
protected $modulo;
/**
* The Order
*
* @var BigInteger
*/
protected $order;
/**
* Sets the modulo
*/
public function setModulo(BigInteger $modulo)
{
$this->modulo = $modulo;
$this->factory = new PrimeField($modulo);
$this->two = $this->factory->newInteger(new BigInteger(2));
$this->three = $this->factory->newInteger(new BigInteger(3));
// used by jacobian coordinates
$this->one = $this->factory->newInteger(new BigInteger(1));
$this->four = $this->factory->newInteger(new BigInteger(4));
$this->eight = $this->factory->newInteger(new BigInteger(8));
}
/**
* Set coefficients a and b
*/
public function setCoefficients(BigInteger $a, BigInteger $b)
{
if (!isset($this->factory)) {
throw new \RuntimeException('setModulo needs to be called before this method');
}
$this->a = $this->factory->newInteger($a);
$this->b = $this->factory->newInteger($b);
}
/**
* Set x and y coordinates for the base point
*
* @param BigInteger|PrimeInteger $x
* @param BigInteger|PrimeInteger $y
* @return PrimeInteger[]
*/
public function setBasePoint($x, $y)
{
switch (\true) {
case !$x instanceof BigInteger && !$x instanceof PrimeInteger:
throw new \UnexpectedValueException('Argument 1 passed to Prime::setBasePoint() must be an instance of either BigInteger or PrimeField\\Integer');
case !$y instanceof BigInteger && !$y instanceof PrimeInteger:
throw new \UnexpectedValueException('Argument 2 passed to Prime::setBasePoint() must be an instance of either BigInteger or PrimeField\\Integer');
}
if (!isset($this->factory)) {
throw new \RuntimeException('setModulo needs to be called before this method');
}
$this->p = [$x instanceof BigInteger ? $this->factory->newInteger($x) : $x, $y instanceof BigInteger ? $this->factory->newInteger($y) : $y];
}
/**
* Retrieve the base point as an array
*
* @return array
*/
public function getBasePoint()
{
if (!isset($this->factory)) {
throw new \RuntimeException('setModulo needs to be called before this method');
}
/*
if (!isset($this->p)) {
throw new \RuntimeException('setBasePoint needs to be called before this method');
}
*/
return $this->p;
}
/**
* Adds two "fresh" jacobian form on the curve
*
* @return FiniteField[]
*/
protected function jacobianAddPointMixedXY(array $p, array $q)
{
list($u1, $s1) = $p;
list($u2, $s2) = $q;
if ($u1->equals($u2)) {
if (!$s1->equals($s2)) {
return [];
} else {
return $this->doublePoint($p);
}
}
$h = $u2->subtract($u1);
$r = $s2->subtract($s1);
$h2 = $h->multiply($h);
$h3 = $h2->multiply($h);
$v = $u1->multiply($h2);
$x3 = $r->multiply($r)->subtract($h3)->subtract($v->multiply($this->two));
$y3 = $r->multiply($v->subtract($x3))->subtract($s1->multiply($h3));
return [$x3, $y3, $h];
}
/**
* Adds one "fresh" jacobian form on the curve
*
* The second parameter should be the "fresh" one
*
* @return FiniteField[]
*/
protected function jacobianAddPointMixedX(array $p, array $q)
{
list($u1, $s1, $z1) = $p;
list($x2, $y2) = $q;
$z12 = $z1->multiply($z1);
$u2 = $x2->multiply($z12);
$s2 = $y2->multiply($z12->multiply($z1));
if ($u1->equals($u2)) {
if (!$s1->equals($s2)) {
return [];
} else {
return $this->doublePoint($p);
}
}
$h = $u2->subtract($u1);
$r = $s2->subtract($s1);
$h2 = $h->multiply($h);
$h3 = $h2->multiply($h);
$v = $u1->multiply($h2);
$x3 = $r->multiply($r)->subtract($h3)->subtract($v->multiply($this->two));
$y3 = $r->multiply($v->subtract($x3))->subtract($s1->multiply($h3));
$z3 = $h->multiply($z1);
return [$x3, $y3, $z3];
}
/**
* Adds two jacobian coordinates on the curve
*
* @return FiniteField[]
*/
protected function jacobianAddPoint(array $p, array $q)
{
list($x1, $y1, $z1) = $p;
list($x2, $y2, $z2) = $q;
$z12 = $z1->multiply($z1);
$z22 = $z2->multiply($z2);
$u1 = $x1->multiply($z22);
$u2 = $x2->multiply($z12);
$s1 = $y1->multiply($z22->multiply($z2));
$s2 = $y2->multiply($z12->multiply($z1));
if ($u1->equals($u2)) {
if (!$s1->equals($s2)) {
return [];
} else {
return $this->doublePoint($p);
}
}
$h = $u2->subtract($u1);
$r = $s2->subtract($s1);
$h2 = $h->multiply($h);
$h3 = $h2->multiply($h);
$v = $u1->multiply($h2);
$x3 = $r->multiply($r)->subtract($h3)->subtract($v->multiply($this->two));
$y3 = $r->multiply($v->subtract($x3))->subtract($s1->multiply($h3));
$z3 = $h->multiply($z1)->multiply($z2);
return [$x3, $y3, $z3];
}
/**
* Adds two points on the curve
*
* @return FiniteField[]
*/
public function addPoint(array $p, array $q)
{
if (!isset($this->factory)) {
throw new \RuntimeException('setModulo needs to be called before this method');
}
if (!\count($p) || !\count($q)) {
if (\count($q)) {
return $q;
}
if (\count($p)) {
return $p;
}
return [];
}
// use jacobian coordinates
if (isset($p[2]) && isset($q[2])) {
if (isset($p['fresh']) && isset($q['fresh'])) {
return $this->jacobianAddPointMixedXY($p, $q);
}
if (isset($p['fresh'])) {
return $this->jacobianAddPointMixedX($q, $p);
}
if (isset($q['fresh'])) {
return $this->jacobianAddPointMixedX($p, $q);
}
return $this->jacobianAddPoint($p, $q);
}
if (isset($p[2]) || isset($q[2])) {
throw new \RuntimeException('Affine coordinates need to be manually converted to Jacobi coordinates or vice versa');
}
if ($p[0]->equals($q[0])) {
if (!$p[1]->equals($q[1])) {
return [];
} else {
// eg. doublePoint
list($numerator, $denominator) = $this->doublePointHelper($p);
}
} else {
$numerator = $q[1]->subtract($p[1]);
$denominator = $q[0]->subtract($p[0]);
}
$slope = $numerator->divide($denominator);
$x = $slope->multiply($slope)->subtract($p[0])->subtract($q[0]);
$y = $slope->multiply($p[0]->subtract($x))->subtract($p[1]);
return [$x, $y];
}
/**
* Returns the numerator and denominator of the slope
*
* @return FiniteField[]
*/
protected function doublePointHelper(array $p)
{
$numerator = $this->three->multiply($p[0])->multiply($p[0])->add($this->a);
$denominator = $this->two->multiply($p[1]);
return [$numerator, $denominator];
}
/**
* Doubles a jacobian coordinate on the curve
*
* @return FiniteField[]
*/
protected function jacobianDoublePoint(array $p)
{
list($x, $y, $z) = $p;
$x2 = $x->multiply($x);
$y2 = $y->multiply($y);
$z2 = $z->multiply($z);
$s = $this->four->multiply($x)->multiply($y2);
$m1 = $this->three->multiply($x2);
$m2 = $this->a->multiply($z2->multiply($z2));
$m = $m1->add($m2);
$x1 = $m->multiply($m)->subtract($this->two->multiply($s));
$y1 = $m->multiply($s->subtract($x1))->subtract($this->eight->multiply($y2->multiply($y2)));
$z1 = $this->two->multiply($y)->multiply($z);
return [$x1, $y1, $z1];
}
/**
* Doubles a "fresh" jacobian coordinate on the curve
*
* @return FiniteField[]
*/
protected function jacobianDoublePointMixed(array $p)
{
list($x, $y) = $p;
$x2 = $x->multiply($x);
$y2 = $y->multiply($y);
$s = $this->four->multiply($x)->multiply($y2);
$m1 = $this->three->multiply($x2);
$m = $m1->add($this->a);
$x1 = $m->multiply($m)->subtract($this->two->multiply($s));
$y1 = $m->multiply($s->subtract($x1))->subtract($this->eight->multiply($y2->multiply($y2)));
$z1 = $this->two->multiply($y);
return [$x1, $y1, $z1];
}
/**
* Doubles a point on a curve
*
* @return FiniteField[]
*/
public function doublePoint(array $p)
{
if (!isset($this->factory)) {
throw new \RuntimeException('setModulo needs to be called before this method');
}
if (!\count($p)) {
return [];
}
// use jacobian coordinates
if (isset($p[2])) {
if (isset($p['fresh'])) {
return $this->jacobianDoublePointMixed($p);
}
return $this->jacobianDoublePoint($p);
}
list($numerator, $denominator) = $this->doublePointHelper($p);
$slope = $numerator->divide($denominator);
$x = $slope->multiply($slope)->subtract($p[0])->subtract($p[0]);
$y = $slope->multiply($p[0]->subtract($x))->subtract($p[1]);
return [$x, $y];
}
/**
* Returns the X coordinate and the derived Y coordinate
*
* @return array
*/
public function derivePoint($m)
{
$y = \ord(Strings::shift($m));
$x = new BigInteger($m, 256);
$xp = $this->convertInteger($x);
switch ($y) {
case 2:
$ypn = \false;
break;
case 3:
$ypn = \true;
break;
default:
throw new \RuntimeException('Coordinate not in recognized format');
}
$temp = $xp->multiply($this->a);
$temp = $xp->multiply($xp)->multiply($xp)->add($temp);
$temp = $temp->add($this->b);
$b = $temp->squareRoot();
if (!$b) {
throw new \RuntimeException('Unable to derive Y coordinate');
}
$bn = $b->isOdd();
$yp = $ypn == $bn ? $b : $b->negate();
return [$xp, $yp];
}
/**
* Tests whether or not the x / y values satisfy the equation
*
* @return boolean
*/
public function verifyPoint(array $p)
{
list($x, $y) = $p;
$lhs = $y->multiply($y);
$temp = $x->multiply($this->a);
$temp = $x->multiply($x)->multiply($x)->add($temp);
$rhs = $temp->add($this->b);
return $lhs->equals($rhs);
}
/**
* Returns the modulo
*
* @return \VendorDuplicator\phpseclib3\Math\BigInteger
*/
public function getModulo()
{
return $this->modulo;
}
/**
* Returns the a coefficient
*
* @return \VendorDuplicator\phpseclib3\Math\PrimeField\Integer
*/
public function getA()
{
return $this->a;
}
/**
* Returns the a coefficient
*
* @return \VendorDuplicator\phpseclib3\Math\PrimeField\Integer
*/
public function getB()
{
return $this->b;
}
/**
* Multiply and Add Points
*
* Adapted from:
* https://github.com/indutny/elliptic/blob/725bd91/lib/elliptic/curve/base.js#L125
*
* @return int[]
*/
public function multiplyAddPoints(array $points, array $scalars)
{
$length = \count($points);
foreach ($points as &$point) {
$point = $this->convertToInternal($point);
}
$wnd = [$this->getNAFPoints($points[0], 7)];
$wndWidth = [isset($points[0]['nafwidth']) ? $points[0]['nafwidth'] : 7];
for ($i = 1; $i < $length; $i++) {
$wnd[] = $this->getNAFPoints($points[$i], 1);
$wndWidth[] = isset($points[$i]['nafwidth']) ? $points[$i]['nafwidth'] : 1;
}
$naf = [];
// comb all window NAFs
$max = 0;
for ($i = $length - 1; $i >= 1; $i -= 2) {
$a = $i - 1;
$b = $i;
if ($wndWidth[$a] != 1 || $wndWidth[$b] != 1) {
$naf[$a] = $scalars[$a]->getNAF($wndWidth[$a]);
$naf[$b] = $scalars[$b]->getNAF($wndWidth[$b]);
$max = \max(\count($naf[$a]), \count($naf[$b]), $max);
continue;
}
$comb = [
$points[$a],
// 1
null,
// 3
null,
// 5
$points[$b],
];
$comb[1] = $this->addPoint($points[$a], $points[$b]);
$comb[2] = $this->addPoint($points[$a], $this->negatePoint($points[$b]));
$index = [
-3,
/* -1 -1 */
-1,
/* -1 0 */
-5,
/* -1 1 */
-7,
/* 0 -1 */
0,
/* 0 -1 */
7,
/* 0 1 */
5,
/* 1 -1 */
1,
/* 1 0 */
3,
];
$jsf = self::getJSFPoints($scalars[$a], $scalars[$b]);
$max = \max(\count($jsf[0]), $max);
if ($max > 0) {
$naf[$a] = \array_fill(0, $max, 0);
$naf[$b] = \array_fill(0, $max, 0);
} else {
$naf[$a] = [];
$naf[$b] = [];
}
for ($j = 0; $j < $max; $j++) {
$ja = isset($jsf[0][$j]) ? $jsf[0][$j] : 0;
$jb = isset($jsf[1][$j]) ? $jsf[1][$j] : 0;
$naf[$a][$j] = $index[3 * ($ja + 1) + $jb + 1];
$naf[$b][$j] = 0;
$wnd[$a] = $comb;
}
}
$acc = [];
$temp = [0, 0, 0, 0];
for ($i = $max; $i >= 0; $i--) {
$k = 0;
while ($i >= 0) {
$zero = \true;
for ($j = 0; $j < $length; $j++) {
$temp[$j] = isset($naf[$j][$i]) ? $naf[$j][$i] : 0;
if ($temp[$j] != 0) {
$zero = \false;
}
}
if (!$zero) {
break;
}
$k++;
$i--;
}
if ($i >= 0) {
$k++;
}
while ($k--) {
$acc = $this->doublePoint($acc);
}
if ($i < 0) {
break;
}
for ($j = 0; $j < $length; $j++) {
$z = $temp[$j];
$p = null;
if ($z == 0) {
continue;
}
$p = $z > 0 ? $wnd[$j][$z - 1 >> 1] : $this->negatePoint($wnd[$j][-$z - 1 >> 1]);
$acc = $this->addPoint($acc, $p);
}
}
return $this->convertToAffine($acc);
}
/**
* Precomputes NAF points
*
* Adapted from:
* https://github.com/indutny/elliptic/blob/725bd91/lib/elliptic/curve/base.js#L351
*
* @return int[]
*/
private function getNAFPoints(array $point, $wnd)
{
if (isset($point['naf'])) {
return $point['naf'];
}
$res = [$point];
$max = (1 << $wnd) - 1;
$dbl = $max == 1 ? null : $this->doublePoint($point);
for ($i = 1; $i < $max; $i++) {
$res[] = $this->addPoint($res[$i - 1], $dbl);
}
$point['naf'] = $res;
/*
$str = '';
foreach ($res as $re) {
$re[0] = bin2hex($re[0]->toBytes());
$re[1] = bin2hex($re[1]->toBytes());
$str.= " ['$re[0]', '$re[1]'],\r\n";
}
file_put_contents('temp.txt', $str);
exit;
*/
return $res;
}
/**
* Precomputes points in Joint Sparse Form
*
* Adapted from:
* https://github.com/indutny/elliptic/blob/725bd91/lib/elliptic/utils.js#L96
*
* @return int[]
*/
private static function getJSFPoints(Integer $k1, Integer $k2)
{
static $three;
if (!isset($three)) {
$three = new BigInteger(3);
}
$jsf = [[], []];
$k1 = $k1->toBigInteger();
$k2 = $k2->toBigInteger();
$d1 = 0;
$d2 = 0;
while ($k1->compare(new BigInteger(-$d1)) > 0 || $k2->compare(new BigInteger(-$d2)) > 0) {
// first phase
$m14 = $k1->testBit(0) + 2 * $k1->testBit(1);
$m14 += $d1;
$m14 &= 3;
$m24 = $k2->testBit(0) + 2 * $k2->testBit(1);
$m24 += $d2;
$m24 &= 3;
if ($m14 == 3) {
$m14 = -1;
}
if ($m24 == 3) {
$m24 = -1;
}
$u1 = 0;
if ($m14 & 1) {
// if $m14 is odd
$m8 = $k1->testBit(0) + 2 * $k1->testBit(1) + 4 * $k1->testBit(2);
$m8 += $d1;
$m8 &= 7;
$u1 = ($m8 == 3 || $m8 == 5) && $m24 == 2 ? -$m14 : $m14;
}
$jsf[0][] = $u1;
$u2 = 0;
if ($m24 & 1) {
// if $m24 is odd
$m8 = $k2->testBit(0) + 2 * $k2->testBit(1) + 4 * $k2->testBit(2);
$m8 += $d2;
$m8 &= 7;
$u2 = ($m8 == 3 || $m8 == 5) && $m14 == 2 ? -$m24 : $m24;
}
$jsf[1][] = $u2;
// second phase
if (2 * $d1 == $u1 + 1) {
$d1 = 1 - $d1;
}
if (2 * $d2 == $u2 + 1) {
$d2 = 1 - $d2;
}
$k1 = $k1->bitwise_rightShift(1);
$k2 = $k2->bitwise_rightShift(1);
}
return $jsf;
}
/**
* Returns the affine point
*
* A Jacobian Coordinate is of the form (x, y, z).
* To convert a Jacobian Coordinate to an Affine Point
* you do (x / z^2, y / z^3)
*
* @return \VendorDuplicator\phpseclib3\Math\PrimeField\Integer[]
*/
public function convertToAffine(array $p)
{
if (!isset($p[2])) {
return $p;
}
list($x, $y, $z) = $p;
$z = $this->one->divide($z);
$z2 = $z->multiply($z);
return [$x->multiply($z2), $y->multiply($z2)->multiply($z)];
}
/**
* Converts an affine point to a jacobian coordinate
*
* @return \VendorDuplicator\phpseclib3\Math\PrimeField\Integer[]
*/
public function convertToInternal(array $p)
{
if (isset($p[2])) {
return $p;
}
$p[2] = clone $this->one;
$p['fresh'] = \true;
return $p;
}
}

View File

@@ -0,0 +1,190 @@
<?php
/**
* Curves over a*x^2 + y^2 = 1 + d*x^2*y^2
*
* http://www.secg.org/SEC2-Ver-1.0.pdf provides for curves with custom parameters.
* ie. the coefficients can be arbitrary set through specially formatted keys, etc.
* As such, Prime.php is built very generically and it's not able to take full
* advantage of curves with 0 coefficients to produce simplified point doubling,
* point addition. Twisted Edwards curves, in contrast, do not have a way, currently,
* to customize them. As such, we can omit the super generic stuff from this class
* and let the named curves (Ed25519 and Ed448) define their own custom tailored
* point addition and point doubling methods.
*
* More info:
*
* https://en.wikipedia.org/wiki/Twisted_Edwards_curve
*
* PHP version 5 and 7
*
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2017 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://pear.php.net/package/Math_BigInteger
*/
namespace VendorDuplicator\phpseclib3\Crypt\EC\BaseCurves;
use VendorDuplicator\phpseclib3\Math\BigInteger;
use VendorDuplicator\phpseclib3\Math\PrimeField;
use VendorDuplicator\phpseclib3\Math\PrimeField\Integer as PrimeInteger;
/**
* Curves over a*x^2 + y^2 = 1 + d*x^2*y^2
*
* @author Jim Wigginton <terrafrost@php.net>
*/
class TwistedEdwards extends Base
{
/**
* The modulo
*
* @var BigInteger
*/
protected $modulo;
/**
* Cofficient for x^2
*
* @var object
*/
protected $a;
/**
* Cofficient for x^2*y^2
*
* @var object
*/
protected $d;
/**
* Base Point
*
* @var object[]
*/
protected $p;
/**
* The number zero over the specified finite field
*
* @var object
*/
protected $zero;
/**
* The number one over the specified finite field
*
* @var object
*/
protected $one;
/**
* The number two over the specified finite field
*
* @var object
*/
protected $two;
/**
* Sets the modulo
*/
public function setModulo(BigInteger $modulo)
{
$this->modulo = $modulo;
$this->factory = new PrimeField($modulo);
$this->zero = $this->factory->newInteger(new BigInteger(0));
$this->one = $this->factory->newInteger(new BigInteger(1));
$this->two = $this->factory->newInteger(new BigInteger(2));
}
/**
* Set coefficients a and b
*/
public function setCoefficients(BigInteger $a, BigInteger $d)
{
if (!isset($this->factory)) {
throw new \RuntimeException('setModulo needs to be called before this method');
}
$this->a = $this->factory->newInteger($a);
$this->d = $this->factory->newInteger($d);
}
/**
* Set x and y coordinates for the base point
*/
public function setBasePoint($x, $y)
{
switch (\true) {
case !$x instanceof BigInteger && !$x instanceof PrimeInteger:
throw new \UnexpectedValueException('Argument 1 passed to Prime::setBasePoint() must be an instance of either BigInteger or PrimeField\\Integer');
case !$y instanceof BigInteger && !$y instanceof PrimeInteger:
throw new \UnexpectedValueException('Argument 2 passed to Prime::setBasePoint() must be an instance of either BigInteger or PrimeField\\Integer');
}
if (!isset($this->factory)) {
throw new \RuntimeException('setModulo needs to be called before this method');
}
$this->p = [$x instanceof BigInteger ? $this->factory->newInteger($x) : $x, $y instanceof BigInteger ? $this->factory->newInteger($y) : $y];
}
/**
* Returns the a coefficient
*
* @return \VendorDuplicator\phpseclib3\Math\PrimeField\Integer
*/
public function getA()
{
return $this->a;
}
/**
* Returns the a coefficient
*
* @return \VendorDuplicator\phpseclib3\Math\PrimeField\Integer
*/
public function getD()
{
return $this->d;
}
/**
* Retrieve the base point as an array
*
* @return array
*/
public function getBasePoint()
{
if (!isset($this->factory)) {
throw new \RuntimeException('setModulo needs to be called before this method');
}
/*
if (!isset($this->p)) {
throw new \RuntimeException('setBasePoint needs to be called before this method');
}
*/
return $this->p;
}
/**
* Returns the affine point
*
* @return \VendorDuplicator\phpseclib3\Math\PrimeField\Integer[]
*/
public function convertToAffine(array $p)
{
if (!isset($p[2])) {
return $p;
}
list($x, $y, $z) = $p;
$z = $this->one->divide($z);
return [$x->multiply($z), $y->multiply($z)];
}
/**
* Returns the modulo
*
* @return \VendorDuplicator\phpseclib3\Math\BigInteger
*/
public function getModulo()
{
return $this->modulo;
}
/**
* Tests whether or not the x / y values satisfy the equation
*
* @return boolean
*/
public function verifyPoint(array $p)
{
list($x, $y) = $p;
$x2 = $x->multiply($x);
$y2 = $y->multiply($y);
$lhs = $this->a->multiply($x2)->add($y2);
$rhs = $this->d->multiply($x2)->multiply($y2)->add($this->one);
return $lhs->equals($rhs);
}
}

View File

@@ -0,0 +1,73 @@
<?php
/**
* Curve25519
*
* PHP version 5 and 7
*
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2019 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://pear.php.net/package/Math_BigInteger
*/
namespace VendorDuplicator\phpseclib3\Crypt\EC\Curves;
use VendorDuplicator\phpseclib3\Crypt\EC\BaseCurves\Montgomery;
use VendorDuplicator\phpseclib3\Math\BigInteger;
class Curve25519 extends Montgomery
{
public function __construct()
{
// 2^255 - 19
$this->setModulo(new BigInteger('7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFED', 16));
$this->a24 = $this->factory->newInteger(new BigInteger('121666'));
$this->p = [$this->factory->newInteger(new BigInteger(9))];
// 2^252 + 0x14def9dea2f79cd65812631a5cf5d3ed
$this->setOrder(new BigInteger('1000000000000000000000000000000014DEF9DEA2F79CD65812631A5CF5D3ED', 16));
/*
$this->setCoefficients(
new BigInteger('486662'), // a
);
$this->setBasePoint(
new BigInteger(9),
new BigInteger('14781619447589544791020593568409986887264606134616475288964881837755586237401')
);
*/
}
/**
* Multiply a point on the curve by a scalar
*
* Modifies the scalar as described at https://tools.ietf.org/html/rfc7748#page-8
*
* @return array
*/
public function multiplyPoint(array $p, BigInteger $d)
{
//$r = strrev(sodium_crypto_scalarmult($d->toBytes(), strrev($p[0]->toBytes())));
//return [$this->factory->newInteger(new BigInteger($r, 256))];
$d = $d->toBytes();
$d &= "\xf8" . \str_repeat("\xff", 30) . "";
$d = \strrev($d);
$d |= "@";
$d = new BigInteger($d, -256);
return parent::multiplyPoint($p, $d);
}
/**
* Creates a random scalar multiplier
*
* @return BigInteger
*/
public function createRandomMultiplier()
{
return BigInteger::random(256);
}
/**
* Performs range check
*/
public function rangeCheck(BigInteger $x)
{
if ($x->getLength() > 256 || $x->isNegative()) {
throw new \RangeException('x must be a positive integer less than 256 bytes in length');
}
}
}

View File

@@ -0,0 +1,76 @@
<?php
/**
* Curve448
*
* PHP version 5 and 7
*
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2019 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://pear.php.net/package/Math_BigInteger
*/
namespace VendorDuplicator\phpseclib3\Crypt\EC\Curves;
use VendorDuplicator\phpseclib3\Crypt\EC\BaseCurves\Montgomery;
use VendorDuplicator\phpseclib3\Math\BigInteger;
class Curve448 extends Montgomery
{
public function __construct()
{
// 2^448 - 2^224 - 1
$this->setModulo(new BigInteger('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE' . 'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF', 16));
$this->a24 = $this->factory->newInteger(new BigInteger('39081'));
$this->p = [$this->factory->newInteger(new BigInteger(5))];
// 2^446 - 0x8335dc163bb124b65129c96fde933d8d723a70aadc873d6d54a7bb0d
$this->setOrder(new BigInteger('3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF' . '7CCA23E9C44EDB49AED63690216CC2728DC58F552378C292AB5844F3', 16));
/*
$this->setCoefficients(
new BigInteger('156326'), // a
);
$this->setBasePoint(
new BigInteger(5),
new BigInteger(
'355293926785568175264127502063783334808976399387714271831880898' .
'435169088786967410002932673765864550910142774147268105838985595290' .
'606362')
);
*/
}
/**
* Multiply a point on the curve by a scalar
*
* Modifies the scalar as described at https://tools.ietf.org/html/rfc7748#page-8
*
* @return array
*/
public function multiplyPoint(array $p, BigInteger $d)
{
//$r = strrev(sodium_crypto_scalarmult($d->toBytes(), strrev($p[0]->toBytes())));
//return [$this->factory->newInteger(new BigInteger($r, 256))];
$d = $d->toBytes();
$d[0] = $d[0] & "\xfc";
$d = \strrev($d);
$d |= "\x80";
$d = new BigInteger($d, 256);
return parent::multiplyPoint($p, $d);
}
/**
* Creates a random scalar multiplier
*
* @return BigInteger
*/
public function createRandomMultiplier()
{
return BigInteger::random(446);
}
/**
* Performs range check
*/
public function rangeCheck(BigInteger $x)
{
if ($x->getLength() > 448 || $x->isNegative()) {
throw new \RangeException('x must be a positive integer less than 446 bytes in length');
}
}
}

View File

@@ -0,0 +1,295 @@
<?php
/**
* Ed25519
*
* PHP version 5 and 7
*
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2017 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
*/
namespace VendorDuplicator\phpseclib3\Crypt\EC\Curves;
use VendorDuplicator\phpseclib3\Crypt\EC\BaseCurves\TwistedEdwards;
use VendorDuplicator\phpseclib3\Crypt\Hash;
use VendorDuplicator\phpseclib3\Crypt\Random;
use VendorDuplicator\phpseclib3\Math\BigInteger;
class Ed25519 extends TwistedEdwards
{
const HASH = 'sha512';
/*
Per https://tools.ietf.org/html/rfc8032#page-6 EdDSA has several parameters, one of which is b:
2. An integer b with 2^(b-1) > p. EdDSA public keys have exactly b
bits, and EdDSA signatures have exactly 2*b bits. b is
recommended to be a multiple of 8, so public key and signature
lengths are an integral number of octets.
SIZE corresponds to b
*/
const SIZE = 32;
public function __construct()
{
// 2^255 - 19
$this->setModulo(new BigInteger('7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFED', 16));
$this->setCoefficients(
// -1
new BigInteger('7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEC', 16),
// a
// -121665/121666
new BigInteger('52036CEE2B6FFE738CC740797779E89800700A4D4141D8AB75EB4DCA135978A3', 16)
);
$this->setBasePoint(new BigInteger('216936D3CD6E53FEC0A4E231FDD6DC5C692CC7609525A7B2C9562D608F25D51A', 16), new BigInteger('6666666666666666666666666666666666666666666666666666666666666658', 16));
$this->setOrder(new BigInteger('1000000000000000000000000000000014DEF9DEA2F79CD65812631A5CF5D3ED', 16));
// algorithm 14.47 from http://cacr.uwaterloo.ca/hac/about/chap14.pdf#page=16
/*
$this->setReduction(function($x) {
$parts = $x->bitwise_split(255);
$className = $this->className;
if (count($parts) > 2) {
list(, $r) = $x->divide($className::$modulo);
return $r;
}
$zero = new BigInteger();
$c = new BigInteger(19);
switch (count($parts)) {
case 2:
list($qi, $ri) = $parts;
break;
case 1:
$qi = $zero;
list($ri) = $parts;
break;
case 0:
return $zero;
}
$r = $ri;
while ($qi->compare($zero) > 0) {
$temp = $qi->multiply($c)->bitwise_split(255);
if (count($temp) == 2) {
list($qi, $ri) = $temp;
} else {
$qi = $zero;
list($ri) = $temp;
}
$r = $r->add($ri);
}
while ($r->compare($className::$modulo) > 0) {
$r = $r->subtract($className::$modulo);
}
return $r;
});
*/
}
/**
* Recover X from Y
*
* Implements steps 2-4 at https://tools.ietf.org/html/rfc8032#section-5.1.3
*
* Used by EC\Keys\Common.php
*
* @param BigInteger $y
* @param boolean $sign
* @return object[]
*/
public function recoverX(BigInteger $y, $sign)
{
$y = $this->factory->newInteger($y);
$y2 = $y->multiply($y);
$u = $y2->subtract($this->one);
$v = $this->d->multiply($y2)->add($this->one);
$x2 = $u->divide($v);
if ($x2->equals($this->zero)) {
if ($sign) {
throw new \RuntimeException('Unable to recover X coordinate (x2 = 0)');
}
return clone $this->zero;
}
// find the square root
/* we don't do $x2->squareRoot() because, quoting from
https://tools.ietf.org/html/rfc8032#section-5.1.1:
"For point decoding or "decompression", square roots modulo p are
needed. They can be computed using the Tonelli-Shanks algorithm or
the special case for p = 5 (mod 8). To find a square root of a,
first compute the candidate root x = a^((p+3)/8) (mod p)."
*/
$exp = $this->getModulo()->add(new BigInteger(3));
$exp = $exp->bitwise_rightShift(3);
$x = $x2->pow($exp);
// If v x^2 = -u (mod p), set x <-- x * 2^((p-1)/4), which is a square root.
if (!$x->multiply($x)->subtract($x2)->equals($this->zero)) {
$temp = $this->getModulo()->subtract(new BigInteger(1));
$temp = $temp->bitwise_rightShift(2);
$temp = $this->two->pow($temp);
$x = $x->multiply($temp);
if (!$x->multiply($x)->subtract($x2)->equals($this->zero)) {
throw new \RuntimeException('Unable to recover X coordinate');
}
}
if ($x->isOdd() != $sign) {
$x = $x->negate();
}
return [$x, $y];
}
/**
* Extract Secret Scalar
*
* Implements steps 1-3 at https://tools.ietf.org/html/rfc8032#section-5.1.5
*
* Used by the various key handlers
*
* @param string $str
* @return array
*/
public function extractSecret($str)
{
if (\strlen($str) != 32) {
throw new \LengthException('Private Key should be 32-bytes long');
}
// 1. Hash the 32-byte private key using SHA-512, storing the digest in
// a 64-octet large buffer, denoted h. Only the lower 32 bytes are
// used for generating the public key.
$hash = new Hash('sha512');
$h = $hash->hash($str);
$h = \substr($h, 0, 32);
// 2. Prune the buffer: The lowest three bits of the first octet are
// cleared, the highest bit of the last octet is cleared, and the
// second highest bit of the last octet is set.
$h[0] = $h[0] & \chr(0xf8);
$h = \strrev($h);
$h[0] = $h[0] & \chr(0x3f) | \chr(0x40);
// 3. Interpret the buffer as the little-endian integer, forming a
// secret scalar s.
$dA = new BigInteger($h, 256);
return ['dA' => $dA, 'secret' => $str];
}
/**
* Encode a point as a string
*
* @param array $point
* @return string
*/
public function encodePoint($point)
{
list($x, $y) = $point;
$y = $y->toBytes();
$y[0] = $y[0] & \chr(0x7f);
if ($x->isOdd()) {
$y[0] = $y[0] | \chr(0x80);
}
$y = \strrev($y);
return $y;
}
/**
* Creates a random scalar multiplier
*
* @return \VendorDuplicator\phpseclib3\Math\PrimeField\Integer
*/
public function createRandomMultiplier()
{
return $this->extractSecret(Random::string(32))['dA'];
}
/**
* Converts an affine point to an extended homogeneous coordinate
*
* From https://tools.ietf.org/html/rfc8032#section-5.1.4 :
*
* A point (x,y) is represented in extended homogeneous coordinates (X, Y, Z, T),
* with x = X/Z, y = Y/Z, x * y = T/Z.
*
* @return \VendorDuplicator\phpseclib3\Math\PrimeField\Integer[]
*/
public function convertToInternal(array $p)
{
if (empty($p)) {
return [clone $this->zero, clone $this->one, clone $this->one, clone $this->zero];
}
if (isset($p[2])) {
return $p;
}
$p[2] = clone $this->one;
$p[3] = $p[0]->multiply($p[1]);
return $p;
}
/**
* Doubles a point on a curve
*
* @return FiniteField[]
*/
public function doublePoint(array $p)
{
if (!isset($this->factory)) {
throw new \RuntimeException('setModulo needs to be called before this method');
}
if (!\count($p)) {
return [];
}
if (!isset($p[2])) {
throw new \RuntimeException('Affine coordinates need to be manually converted to "Jacobi" coordinates or vice versa');
}
// from https://tools.ietf.org/html/rfc8032#page-12
list($x1, $y1, $z1, $t1) = $p;
$a = $x1->multiply($x1);
$b = $y1->multiply($y1);
$c = $this->two->multiply($z1)->multiply($z1);
$h = $a->add($b);
$temp = $x1->add($y1);
$e = $h->subtract($temp->multiply($temp));
$g = $a->subtract($b);
$f = $c->add($g);
$x3 = $e->multiply($f);
$y3 = $g->multiply($h);
$t3 = $e->multiply($h);
$z3 = $f->multiply($g);
return [$x3, $y3, $z3, $t3];
}
/**
* Adds two points on the curve
*
* @return FiniteField[]
*/
public function addPoint(array $p, array $q)
{
if (!isset($this->factory)) {
throw new \RuntimeException('setModulo needs to be called before this method');
}
if (!\count($p) || !\count($q)) {
if (\count($q)) {
return $q;
}
if (\count($p)) {
return $p;
}
return [];
}
if (!isset($p[2]) || !isset($q[2])) {
throw new \RuntimeException('Affine coordinates need to be manually converted to "Jacobi" coordinates or vice versa');
}
if ($p[0]->equals($q[0])) {
return !$p[1]->equals($q[1]) ? [] : $this->doublePoint($p);
}
// from https://tools.ietf.org/html/rfc8032#page-12
list($x1, $y1, $z1, $t1) = $p;
list($x2, $y2, $z2, $t2) = $q;
$a = $y1->subtract($x1)->multiply($y2->subtract($x2));
$b = $y1->add($x1)->multiply($y2->add($x2));
$c = $t1->multiply($this->two)->multiply($this->d)->multiply($t2);
$d = $z1->multiply($this->two)->multiply($z2);
$e = $b->subtract($a);
$f = $d->subtract($c);
$g = $d->add($c);
$h = $b->add($a);
$x3 = $e->multiply($f);
$y3 = $g->multiply($h);
$t3 = $e->multiply($h);
$z3 = $f->multiply($g);
return [$x3, $y3, $z3, $t3];
}
}

View File

@@ -0,0 +1,222 @@
<?php
/**
* Ed448
*
* PHP version 5 and 7
*
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2017 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
*/
namespace VendorDuplicator\phpseclib3\Crypt\EC\Curves;
use VendorDuplicator\phpseclib3\Crypt\EC\BaseCurves\TwistedEdwards;
use VendorDuplicator\phpseclib3\Crypt\Hash;
use VendorDuplicator\phpseclib3\Crypt\Random;
use VendorDuplicator\phpseclib3\Math\BigInteger;
class Ed448 extends TwistedEdwards
{
const HASH = 'shake256-912';
const SIZE = 57;
public function __construct()
{
// 2^448 - 2^224 - 1
$this->setModulo(new BigInteger('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE' . 'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF', 16));
$this->setCoefficients(
new BigInteger(1),
// -39081
new BigInteger('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE' . 'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6756', 16)
);
$this->setBasePoint(new BigInteger('4F1970C66BED0DED221D15A622BF36DA9E146570470F1767EA6DE324' . 'A3D3A46412AE1AF72AB66511433B80E18B00938E2626A82BC70CC05E', 16), new BigInteger('693F46716EB6BC248876203756C9C7624BEA73736CA3984087789C1E' . '05A0C2D73AD3FF1CE67C39C4FDBD132C4ED7C8AD9808795BF230FA14', 16));
$this->setOrder(new BigInteger('3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF' . '7CCA23E9C44EDB49AED63690216CC2728DC58F552378C292AB5844F3', 16));
}
/**
* Recover X from Y
*
* Implements steps 2-4 at https://tools.ietf.org/html/rfc8032#section-5.2.3
*
* Used by EC\Keys\Common.php
*
* @param BigInteger $y
* @param boolean $sign
* @return object[]
*/
public function recoverX(BigInteger $y, $sign)
{
$y = $this->factory->newInteger($y);
$y2 = $y->multiply($y);
$u = $y2->subtract($this->one);
$v = $this->d->multiply($y2)->subtract($this->one);
$x2 = $u->divide($v);
if ($x2->equals($this->zero)) {
if ($sign) {
throw new \RuntimeException('Unable to recover X coordinate (x2 = 0)');
}
return clone $this->zero;
}
// find the square root
$exp = $this->getModulo()->add(new BigInteger(1));
$exp = $exp->bitwise_rightShift(2);
$x = $x2->pow($exp);
if (!$x->multiply($x)->subtract($x2)->equals($this->zero)) {
throw new \RuntimeException('Unable to recover X coordinate');
}
if ($x->isOdd() != $sign) {
$x = $x->negate();
}
return [$x, $y];
}
/**
* Extract Secret Scalar
*
* Implements steps 1-3 at https://tools.ietf.org/html/rfc8032#section-5.2.5
*
* Used by the various key handlers
*
* @param string $str
* @return array
*/
public function extractSecret($str)
{
if (\strlen($str) != 57) {
throw new \LengthException('Private Key should be 57-bytes long');
}
// 1. Hash the 57-byte private key using SHAKE256(x, 114), storing the
// digest in a 114-octet large buffer, denoted h. Only the lower 57
// bytes are used for generating the public key.
$hash = new Hash('shake256-912');
$h = $hash->hash($str);
$h = \substr($h, 0, 57);
// 2. Prune the buffer: The two least significant bits of the first
// octet are cleared, all eight bits the last octet are cleared, and
// the highest bit of the second to last octet is set.
$h[0] = $h[0] & \chr(0xfc);
$h = \strrev($h);
$h[0] = "\x00";
$h[1] = $h[1] | \chr(0x80);
// 3. Interpret the buffer as the little-endian integer, forming a
// secret scalar s.
$dA = new BigInteger($h, 256);
return ['dA' => $dA, 'secret' => $str];
$dA->secret = $str;
return $dA;
}
/**
* Encode a point as a string
*
* @param array $point
* @return string
*/
public function encodePoint($point)
{
list($x, $y) = $point;
$y = "\x00" . $y->toBytes();
if ($x->isOdd()) {
$y[0] = $y[0] | \chr(0x80);
}
$y = \strrev($y);
return $y;
}
/**
* Creates a random scalar multiplier
*
* @return \VendorDuplicator\phpseclib3\Math\PrimeField\Integer
*/
public function createRandomMultiplier()
{
return $this->extractSecret(Random::string(57))['dA'];
}
/**
* Converts an affine point to an extended homogeneous coordinate
*
* From https://tools.ietf.org/html/rfc8032#section-5.2.4 :
*
* A point (x,y) is represented in extended homogeneous coordinates (X, Y, Z, T),
* with x = X/Z, y = Y/Z, x * y = T/Z.
*
* @return \VendorDuplicator\phpseclib3\Math\PrimeField\Integer[]
*/
public function convertToInternal(array $p)
{
if (empty($p)) {
return [clone $this->zero, clone $this->one, clone $this->one];
}
if (isset($p[2])) {
return $p;
}
$p[2] = clone $this->one;
return $p;
}
/**
* Doubles a point on a curve
*
* @return FiniteField[]
*/
public function doublePoint(array $p)
{
if (!isset($this->factory)) {
throw new \RuntimeException('setModulo needs to be called before this method');
}
if (!\count($p)) {
return [];
}
if (!isset($p[2])) {
throw new \RuntimeException('Affine coordinates need to be manually converted to "Jacobi" coordinates or vice versa');
}
// from https://tools.ietf.org/html/rfc8032#page-18
list($x1, $y1, $z1) = $p;
$b = $x1->add($y1);
$b = $b->multiply($b);
$c = $x1->multiply($x1);
$d = $y1->multiply($y1);
$e = $c->add($d);
$h = $z1->multiply($z1);
$j = $e->subtract($this->two->multiply($h));
$x3 = $b->subtract($e)->multiply($j);
$y3 = $c->subtract($d)->multiply($e);
$z3 = $e->multiply($j);
return [$x3, $y3, $z3];
}
/**
* Adds two points on the curve
*
* @return FiniteField[]
*/
public function addPoint(array $p, array $q)
{
if (!isset($this->factory)) {
throw new \RuntimeException('setModulo needs to be called before this method');
}
if (!\count($p) || !\count($q)) {
if (\count($q)) {
return $q;
}
if (\count($p)) {
return $p;
}
return [];
}
if (!isset($p[2]) || !isset($q[2])) {
throw new \RuntimeException('Affine coordinates need to be manually converted to "Jacobi" coordinates or vice versa');
}
if ($p[0]->equals($q[0])) {
return !$p[1]->equals($q[1]) ? [] : $this->doublePoint($p);
}
// from https://tools.ietf.org/html/rfc8032#page-17
list($x1, $y1, $z1) = $p;
list($x2, $y2, $z2) = $q;
$a = $z1->multiply($z2);
$b = $a->multiply($a);
$c = $x1->multiply($x2);
$d = $y1->multiply($y2);
$e = $this->d->multiply($c)->multiply($d);
$f = $b->subtract($e);
$g = $b->add($e);
$h = $x1->add($y1)->multiply($x2->add($y2));
$x3 = $a->multiply($f)->multiply($h->subtract($c)->subtract($d));
$y3 = $a->multiply($g)->multiply($d->subtract($c));
$z3 = $f->multiply($g);
return [$x3, $y3, $z3];
}
}

View File

@@ -0,0 +1,26 @@
<?php
/**
* brainpoolP160r1
*
* PHP version 5 and 7
*
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2017 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://pear.php.net/package/Math_BigInteger
*/
namespace VendorDuplicator\phpseclib3\Crypt\EC\Curves;
use VendorDuplicator\phpseclib3\Crypt\EC\BaseCurves\Prime;
use VendorDuplicator\phpseclib3\Math\BigInteger;
class brainpoolP160r1 extends Prime
{
public function __construct()
{
$this->setModulo(new BigInteger('E95E4A5F737059DC60DFC7AD95B3D8139515620F', 16));
$this->setCoefficients(new BigInteger('340E7BE2A280EB74E2BE61BADA745D97E8F7C300', 16), new BigInteger('1E589A8595423412134FAA2DBDEC95C8D8675E58', 16));
$this->setBasePoint(new BigInteger('BED5AF16EA3F6A4F62938C4631EB5AF7BDBCDBC3', 16), new BigInteger('1667CB477A1A8EC338F94741669C976316DA6321', 16));
$this->setOrder(new BigInteger('E95E4A5F737059DC60DF5991D45029409E60FC09', 16));
}
}

Some files were not shown because too many files have changed in this diff Show More