Commit bc3335e6 authored by Szilárd Pfeiffer's avatar Szilárd Pfeiffer
Browse files

Merge branch '48-hassh-value-generation-for-ssh-key-exchange-init-message'

Closes: #48
parents c606b97b 6bce709e
Loading
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
# Changelog

## 0.8.2

- SSH (`ssh`)
  - Public Keys (`pubkeys`)
    - [HASSH fingerprint](https://engineering.salesforce.com/open-sourcing-hassh-abed3ae5044c/) calculation (\#48)

## 0.8.0 - 2022-01-18

- SSH (`ssh`)
+2 −0
Original line number Diff line number Diff line
@@ -117,6 +117,8 @@ Only features that cannot be or difficultly implemented by some of the most popu
#### Cipher Suites

1.  identifies as much encryption algorithms as possible (more than 200, compared to 70+ currently supported by OpenSSH)
2.  supports [HASSH fingerprint](https://engineering.salesforce.com/open-sourcing-hassh-abed3ae5044c/) calculation
    (\#96)

## License

+9 −6
Original line number Diff line number Diff line
@@ -463,7 +463,7 @@ class VectorString(ArrayBase):
        vector_param = self.get_param()

        body_composer = ComposerText(vector_param.encoding)
        body_composer.compose_parsable_array(self._items, vector_param.separator)
        body_composer.compose_parsable_array(self._items, vector_param.separator, vector_param.fallback_class)

        header_composer = ComposerBinary()
        header_composer.compose_numeric(body_composer.composed_length, self.param.item_num_size)
@@ -677,7 +677,7 @@ class StringEnumParsableBase(ParsableBaseNoABC):
        enum_items.sort(key=lambda color: len(color.value.code), reverse=True)

        try:
            code = parsable.decode('ascii')
            code = six.ensure_text(parsable, 'ascii')
        except UnicodeDecodeError as e:
            six.raise_from(InvalidValue(parsable, cls), e)

@@ -688,7 +688,7 @@ class StringEnumParsableBase(ParsableBaseNoABC):
        raise InvalidValue(parsable, cls, 'code')

    def compose(self):
        return self._asdict().encode('ascii')
        return six.ensure_binary(self._asdict(), 'ascii')

    def _asdict(self):
        return getattr(self, 'value').code
@@ -783,7 +783,10 @@ class OpaqueEnumParsable(Vector):
    @classmethod
    def _parse(cls, parsable):
        opaque, parsed_length = super(OpaqueEnumParsable, cls)._parse(parsable)
        code = bytearray(opaque).decode(cls.get_encoding())
        code = six.ensure_text(
            b''.join([six.int2byte(opaque_item) for opaque_item in opaque]),
            cls.get_encoding()
        )

        try:
            parsed_object = next(iter([
@@ -792,7 +795,7 @@ class OpaqueEnumParsable(Vector):
                if enum_item.value.code == code
            ]))
        except StopIteration as e:
            six.raise_from(InvalidValue(code.encode(cls.get_encoding()), cls), e)
            six.raise_from(InvalidValue(code, cls), e)

        return parsed_object, parsed_length

@@ -812,7 +815,7 @@ class OpaqueEnumComposer(enum.Enum):

    def compose(self):
        composer = ComposerBinary()
        value = self.value.code.encode(self.get_encoding())  # pylint: disable=no-member
        value = six.ensure_binary(self.value.code, self.get_encoding())  # pylint: disable=no-member

        composer.compose_bytes(value, 1)

+28 −17
Original line number Diff line number Diff line
@@ -15,7 +15,7 @@ import dateutil
import dateutil.parser
import dateutil.tz

from cryptoparser.common.exception import NotEnoughData, TooMuchData, InvalidValue
from cryptoparser.common.exception import NotEnoughData, TooMuchData, InvalidType, InvalidValue
import cryptoparser.common.utils


@@ -155,7 +155,7 @@ class ParserBase(collections_abc.Mapping):

        value = self._parsable[self._parsed_length:self._parsed_length + parsable_length]
        try:
            value = value.decode(encoding)
            value = six.ensure_text(value, encoding)
            if converter != str:
                value = converter(value)
            self._parsed_values[name] = value
@@ -180,7 +180,7 @@ class ParserText(ParserBase):
            min_count,
            max_count
    ):
        separators = separators.encode(self._encoding)
        separators = six.ensure_binary(separators, self._encoding)

        count = 0
        actual_offset = count_offset
@@ -273,14 +273,14 @@ class ParserText(ParserBase):
            may_end):
        try:
            if not isinstance(item_class, type):
                item = item_class(self._parsable[item_offset:item_end].decode(self._encoding))
                item = item_class(six.ensure_text(self._parsable[item_offset:item_end], self._encoding))
            elif issubclass(item_class, ParsableBaseNoABC):
                item, parsed_length = item_class.parse_immutable(self._parsable[item_offset:item_end])
                item_end = item_offset + parsed_length
            elif issubclass(item_class, str):
                item = self._parsable[item_offset:item_end].decode(self._encoding)
            elif issubclass(item_class, six.string_types):
                item = six.ensure_text(self._parsable[item_offset:item_end], self._encoding)
            else:
                item = item_class(self._parsable[item_offset:item_end].decode(self._encoding))
                item = item_class(six.ensure_text(self._parsable[item_offset:item_end], self._encoding))
        except (InvalidValue, ValueError, UnicodeError) as e:
            if fallback_class is not None:
                parsed_value, parsed_length = self._parse_string_until_separator(
@@ -304,7 +304,7 @@ class ParserText(ParserBase):
            separator_spaces=''
    ):
        item_end = None
        byte_separators = [separator.encode(self._encoding) for separator in separators]
        byte_separators = [six.ensure_binary(separator, self._encoding) for separator in separators]

        for separator_end in range(item_offset, len(self._parsable) + 1):
            for separator in byte_separators:
@@ -320,7 +320,7 @@ class ParserText(ParserBase):
            item_end = len(self._parsable)

        separator_space_count = 0
        byte_separator_spaces = separator_spaces.encode(self._encoding)
        byte_separator_spaces = six.ensure_binary(separator_spaces, self._encoding)
        while (item_end > item_offset and
                self._parsable[
                    item_end - separator_space_count - 1:
@@ -427,7 +427,7 @@ class ParserText(ParserBase):
    def parse_date_time(self, name):
        try:
            value = self._parsable[self._parsed_length:]
            date_time = dateutil.parser.parse(value.decode(self._encoding))
            date_time = dateutil.parser.parse(six.ensure_text(value, self._encoding))
        except ValueError as e:
            six.raise_from(InvalidValue(value, type(self), 'value'), e)

@@ -646,7 +646,7 @@ class ComposerBase(object):
        return len(self._composed)

    def _compose_string_array(self, values, encoding, separator):
        separator = bytearray(separator.encode(encoding))
        separator = bytearray(six.ensure_binary(separator, encoding))
        composed_str = bytearray()

        for value in values:
@@ -654,7 +654,7 @@ class ComposerBase(object):
                if isinstance(value, ParsableBaseNoABC):
                    composed_str += value.compose()
                else:
                    composed_str += six.text_type(value).encode(encoding)
                    composed_str += six.ensure_binary(six.text_type(value), encoding)
            except UnicodeError as e:
                six.raise_from(InvalidValue(value, type(self)), e)

@@ -674,7 +674,7 @@ class ComposerText(ComposerBase):
        for value in values:
            composed_str += '{:d}{}'.format(value, separator)

        self._composed += composed_str[:len(composed_str) - len(separator)].encode(self._encoding)
        self._composed += six.ensure_binary(composed_str[:len(composed_str) - len(separator)], self._encoding)

    def compose_numeric(self, value):
        self._compose_numeric_array([value, ], separator='')
@@ -691,10 +691,21 @@ class ComposerText(ComposerBase):
    def compose_parsable(self, value):
        self._composed += value.compose()

    def compose_parsable_array(self, values, separator=','):
        separator = separator.encode(self._encoding)
    def compose_parsable_array(self, values, separator=',', fallback_class=None):
        separator = six.ensure_binary(separator, self._encoding)

        self._composed += bytearray(separator).join(map(lambda item: item.compose(), values))
        composed_items = []
        for item in values:
            if isinstance(item, (ComposerBase, ParsableBase, ParsableBaseNoABC)):
                composed_item = item.compose()
            elif fallback_class is not None and isinstance(item, fallback_class):
                composed_item = six.ensure_binary(item, self._encoding)
            else:
                raise InvalidType()

            composed_items.append(composed_item)

        self._composed += bytearray(separator).join(composed_items)

    def compose_separator(self, value):
        self.compose_string(value)
@@ -768,7 +779,7 @@ class ComposerBinary(ComposerBase):

    def compose_string(self, value, encoding, item_size):
        try:
            value = value.encode(encoding)
            value = six.ensure_binary(value, encoding)
        except UnicodeError as e:
            six.raise_from(InvalidValue(value, type(self)), e)

+11 −0
Original line number Diff line number Diff line
@@ -2,6 +2,8 @@

import inspect

import six


def get_leaf_classes(base_class):

@@ -18,3 +20,12 @@ def get_leaf_classes(base_class):
        return subclasses

    return _get_leaf_classes(base_class)


def bytes_to_hex_string(byte_array, separator='', lowercase=False):
    if lowercase:
        format_str = '{:02x}'
    else:
        format_str = '{:02X}'

    return separator.join([format_str.format(x) for x in six.iterbytes(byte_array)])
Loading