123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130 |
- <?php
- /*
- * This file is part of the PHPASN1 library.
- *
- * Copyright © Friedrich Große <friedrich.grosse@gmail.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
- namespace FG\ASN1\Universal;
- use Exception;
- use FG\Utility\BigInteger;
- use FG\ASN1\Exception\ParserException;
- use FG\ASN1\ASNObject;
- use FG\ASN1\Parsable;
- use FG\ASN1\Identifier;
- class Integer extends ASNObject implements Parsable
- {
- /** @var int */
- private $value;
- /**
- * @param int $value
- *
- * @throws Exception if the value is not numeric
- */
- public function __construct($value)
- {
- if (is_numeric($value) == false) {
- throw new Exception("Invalid VALUE [{$value}] for ASN1_INTEGER");
- }
- $this->value = $value;
- }
- public function getType()
- {
- return Identifier::INTEGER;
- }
- public function getContent()
- {
- return $this->value;
- }
- protected function calculateContentLength()
- {
- return strlen($this->getEncodedValue());
- }
- protected function getEncodedValue()
- {
- $value = BigInteger::create($this->value, 10);
- $negative = $value->compare(0) < 0;
- if ($negative) {
- $value = $value->absoluteValue();
- $limit = 0x80;
- } else {
- $limit = 0x7f;
- }
- $mod = 0xff+1;
- $values = [];
- while($value->compare($limit) > 0) {
- $values[] = $value->modulus($mod)->toInteger();
- $value = $value->shiftRight(8);
- }
- $values[] = $value->modulus($mod)->toInteger();
- $numValues = count($values);
- if ($negative) {
- for ($i = 0; $i < $numValues; $i++) {
- $values[$i] = 0xff - $values[$i];
- }
- for ($i = 0; $i < $numValues; $i++) {
- $values[$i] += 1;
- if ($values[$i] <= 0xff) {
- break;
- }
- assert($i != $numValues - 1);
- $values[$i] = 0;
- }
- if ($values[$numValues - 1] == 0x7f) {
- $values[] = 0xff;
- }
- }
- $values = array_reverse($values);
- $r = pack("C*", ...$values);
- return $r;
- }
- private static function ensureMinimalEncoding($binaryData, $offsetIndex)
- {
- // All the first nine bits cannot equal 0 or 1, which would
- // be non-minimal encoding for positive and negative integers respectively
- if ((ord($binaryData[$offsetIndex]) == 0x00 && (ord($binaryData[$offsetIndex+1]) & 0x80) == 0) ||
- (ord($binaryData[$offsetIndex]) == 0xff && (ord($binaryData[$offsetIndex+1]) & 0x80) == 0x80)) {
- throw new ParserException("Integer not minimally encoded", $offsetIndex);
- }
- }
- public static function fromBinary(&$binaryData, &$offsetIndex = 0)
- {
- $parsedObject = new static(0);
- self::parseIdentifier($binaryData[$offsetIndex], $parsedObject->getType(), $offsetIndex++);
- $contentLength = self::parseContentLength($binaryData, $offsetIndex, 1);
- if ($contentLength > 1) {
- self::ensureMinimalEncoding($binaryData, $offsetIndex);
- }
- $isNegative = (ord($binaryData[$offsetIndex]) & 0x80) != 0x00;
- $number = BigInteger::create(ord($binaryData[$offsetIndex++]) & 0x7F);
- for ($i = 0; $i < $contentLength - 1; $i++) {
- $number = $number->multiply(0x100)->add(ord($binaryData[$offsetIndex++]));
- }
- if ($isNegative) {
- $number = $number->subtract(BigInteger::create(2)->toPower(8 * $contentLength - 1));
- }
- $parsedObject = new static((string)$number);
- $parsedObject->setContentLength($contentLength);
- return $parsedObject;
- }
- }
|