CryptoParser 1.0.2__tar.gz → 1.1.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {cryptoparser-1.0.2 → cryptoparser-1.1.1}/CHANGELOG.rst +25 -1
- {cryptoparser-1.0.2 → cryptoparser-1.1.1}/CryptoParser.egg-info/PKG-INFO +3 -3
- {cryptoparser-1.0.2 → cryptoparser-1.1.1}/CryptoParser.egg-info/SOURCES.txt +15 -0
- {cryptoparser-1.0.2 → cryptoparser-1.1.1}/CryptoParser.egg-info/requires.txt +1 -1
- {cryptoparser-1.0.2 → cryptoparser-1.1.1}/CryptoParser.egg-info/top_level.txt +1 -0
- {cryptoparser-1.0.2 → cryptoparser-1.1.1}/PKG-INFO +3 -3
- {cryptoparser-1.0.2 → cryptoparser-1.1.1}/cryptoparser/common/exception.py +6 -1
- {cryptoparser-1.0.2 → cryptoparser-1.1.1}/cryptoparser/common/parse.py +18 -5
- cryptoparser-1.1.1/cryptoparser/ike/common.py +235 -0
- cryptoparser-1.1.1/cryptoparser/ike/ikev1.py +755 -0
- cryptoparser-1.1.1/cryptoparser/ike/ikev2.py +1185 -0
- cryptoparser-1.1.1/cryptoparser/ike/isakmp.py +200 -0
- cryptoparser-1.1.1/cryptoparser/ike/version.py +85 -0
- {cryptoparser-1.0.2 → cryptoparser-1.1.1}/cryptoparser/ssh/key.py +5 -0
- {cryptoparser-1.0.2 → cryptoparser-1.1.1}/docs/features.rst +14 -2
- {cryptoparser-1.0.2 → cryptoparser-1.1.1}/docs/index.rst +3 -3
- {cryptoparser-1.0.2 → cryptoparser-1.1.1}/pyproject.toml +4 -3
- cryptoparser-1.1.1/test/ike/classes.py +231 -0
- cryptoparser-1.1.1/test/ike/test_ikev1_payload.py +1143 -0
- cryptoparser-1.1.1/test/ike/test_ikev1_sa.py +416 -0
- cryptoparser-1.1.1/test/ike/test_ikev2_notify.py +375 -0
- cryptoparser-1.1.1/test/ike/test_ikev2_payload.py +723 -0
- cryptoparser-1.1.1/test/ike/test_ikev2_sa.py +596 -0
- cryptoparser-1.1.1/test/ike/test_isakmp.py +311 -0
- cryptoparser-1.1.1/test/ike/test_version.py +73 -0
- cryptoparser-1.1.1/test/ssh/__init__.py +0 -0
- {cryptoparser-1.0.2 → cryptoparser-1.1.1}/test/ssh/test_key.py +3 -0
- cryptoparser-1.1.1/test/tls/__init__.py +0 -0
- {cryptoparser-1.0.2 → cryptoparser-1.1.1}/.coveragerc +0 -0
- {cryptoparser-1.0.2 → cryptoparser-1.1.1}/.flake8 +0 -0
- {cryptoparser-1.0.2 → cryptoparser-1.1.1}/.gitignore +0 -0
- {cryptoparser-1.0.2 → cryptoparser-1.1.1}/.gitlab-ci.yml +0 -0
- {cryptoparser-1.0.2 → cryptoparser-1.1.1}/.gitmodules +0 -0
- {cryptoparser-1.0.2 → cryptoparser-1.1.1}/.pylintrc +0 -0
- {cryptoparser-1.0.2 → cryptoparser-1.1.1}/.readthedocs.yaml +0 -0
- {cryptoparser-1.0.2 → cryptoparser-1.1.1}/CONTRIBUTING.rst +0 -0
- {cryptoparser-1.0.2 → cryptoparser-1.1.1}/CryptoParser.egg-info/dependency_links.txt +0 -0
- {cryptoparser-1.0.2 → cryptoparser-1.1.1}/LICENSE.txt +0 -0
- {cryptoparser-1.0.2 → cryptoparser-1.1.1}/MANIFEST.in +0 -0
- {cryptoparser-1.0.2 → cryptoparser-1.1.1}/README.rst +0 -0
- {cryptoparser-1.0.2 → cryptoparser-1.1.1}/cryptoparser/__init__.py +0 -0
- {cryptoparser-1.0.2 → cryptoparser-1.1.1}/cryptoparser/__setup__.py +0 -0
- {cryptoparser-1.0.2 → cryptoparser-1.1.1}/cryptoparser/common/__init__.py +0 -0
- {cryptoparser-1.0.2 → cryptoparser-1.1.1}/cryptoparser/common/base.py +0 -0
- {cryptoparser-1.0.2 → cryptoparser-1.1.1}/cryptoparser/common/classes.py +0 -0
- {cryptoparser-1.0.2 → cryptoparser-1.1.1}/cryptoparser/common/field.py +0 -0
- {cryptoparser-1.0.2 → cryptoparser-1.1.1}/cryptoparser/common/utils.py +0 -0
- {cryptoparser-1.0.2 → cryptoparser-1.1.1}/cryptoparser/common/x509.py +0 -0
- {cryptoparser-1.0.2 → cryptoparser-1.1.1}/cryptoparser/dnsrec/__init__.py +0 -0
- {cryptoparser-1.0.2 → cryptoparser-1.1.1}/cryptoparser/dnsrec/record.py +0 -0
- {cryptoparser-1.0.2 → cryptoparser-1.1.1}/cryptoparser/dnsrec/txt.py +0 -0
- {cryptoparser-1.0.2 → cryptoparser-1.1.1}/cryptoparser/httpx/__init__.py +0 -0
- {cryptoparser-1.0.2 → cryptoparser-1.1.1}/cryptoparser/httpx/header.py +0 -0
- {cryptoparser-1.0.2 → cryptoparser-1.1.1}/cryptoparser/httpx/parse.py +0 -0
- {cryptoparser-1.0.2 → cryptoparser-1.1.1}/cryptoparser/httpx/version.py +0 -0
- {cryptoparser-1.0.2/cryptoparser/ssh → cryptoparser-1.1.1/cryptoparser/ike}/__init__.py +0 -0
- {cryptoparser-1.0.2/cryptoparser/tls → cryptoparser-1.1.1/cryptoparser/ssh}/__init__.py +0 -0
- {cryptoparser-1.0.2 → cryptoparser-1.1.1}/cryptoparser/ssh/record.py +0 -0
- {cryptoparser-1.0.2 → cryptoparser-1.1.1}/cryptoparser/ssh/subprotocol.py +0 -0
- {cryptoparser-1.0.2 → cryptoparser-1.1.1}/cryptoparser/ssh/version.py +0 -0
- {cryptoparser-1.0.2/test → cryptoparser-1.1.1/cryptoparser/tls}/__init__.py +0 -0
- {cryptoparser-1.0.2 → cryptoparser-1.1.1}/cryptoparser/tls/algorithm.py +0 -0
- {cryptoparser-1.0.2 → cryptoparser-1.1.1}/cryptoparser/tls/ciphersuite.py +0 -0
- {cryptoparser-1.0.2 → cryptoparser-1.1.1}/cryptoparser/tls/extension.py +0 -0
- {cryptoparser-1.0.2 → cryptoparser-1.1.1}/cryptoparser/tls/grease.py +0 -0
- {cryptoparser-1.0.2 → cryptoparser-1.1.1}/cryptoparser/tls/ldap.py +0 -0
- {cryptoparser-1.0.2 → cryptoparser-1.1.1}/cryptoparser/tls/mysql.py +0 -0
- {cryptoparser-1.0.2 → cryptoparser-1.1.1}/cryptoparser/tls/openvpn.py +0 -0
- {cryptoparser-1.0.2 → cryptoparser-1.1.1}/cryptoparser/tls/postgresql.py +0 -0
- {cryptoparser-1.0.2 → cryptoparser-1.1.1}/cryptoparser/tls/rdp.py +0 -0
- {cryptoparser-1.0.2 → cryptoparser-1.1.1}/cryptoparser/tls/record.py +0 -0
- {cryptoparser-1.0.2 → cryptoparser-1.1.1}/cryptoparser/tls/subprotocol.py +0 -0
- {cryptoparser-1.0.2 → cryptoparser-1.1.1}/cryptoparser/tls/version.py +0 -0
- {cryptoparser-1.0.2 → cryptoparser-1.1.1}/docs/.gitignore +0 -0
- {cryptoparser-1.0.2 → cryptoparser-1.1.1}/docs/changelog.rst +0 -0
- {cryptoparser-1.0.2 → cryptoparser-1.1.1}/docs/conf.py +0 -0
- {cryptoparser-1.0.2 → cryptoparser-1.1.1}/docs/development.rst +0 -0
- {cryptoparser-1.0.2 → cryptoparser-1.1.1}/setup.cfg +0 -0
- {cryptoparser-1.0.2 → cryptoparser-1.1.1}/setup.py +0 -0
- {cryptoparser-1.0.2/test/common → cryptoparser-1.1.1/test}/__init__.py +0 -0
- {cryptoparser-1.0.2/test/dnsrec → cryptoparser-1.1.1/test/common}/__init__.py +0 -0
- {cryptoparser-1.0.2 → cryptoparser-1.1.1}/test/common/certs/ecc256.badssl.com.pem +0 -0
- {cryptoparser-1.0.2 → cryptoparser-1.1.1}/test/common/certs/rsa8192.badssl.com.pem +0 -0
- {cryptoparser-1.0.2 → cryptoparser-1.1.1}/test/common/certs/rsa8192.badssl.com_certificate.crt +0 -0
- {cryptoparser-1.0.2 → cryptoparser-1.1.1}/test/common/certs/rsa8192.badssl.com_root_ca.crt +0 -0
- {cryptoparser-1.0.2 → cryptoparser-1.1.1}/test/common/certs/snakeoil_cert.pem +0 -0
- {cryptoparser-1.0.2 → cryptoparser-1.1.1}/test/common/classes.py +0 -0
- {cryptoparser-1.0.2 → cryptoparser-1.1.1}/test/common/test_algorithm.py +0 -0
- {cryptoparser-1.0.2 → cryptoparser-1.1.1}/test/common/test_base.py +0 -0
- {cryptoparser-1.0.2 → cryptoparser-1.1.1}/test/common/test_classes.py +0 -0
- {cryptoparser-1.0.2 → cryptoparser-1.1.1}/test/common/test_exception.py +0 -0
- {cryptoparser-1.0.2 → cryptoparser-1.1.1}/test/common/test_field.py +0 -0
- {cryptoparser-1.0.2 → cryptoparser-1.1.1}/test/common/test_parse.py +0 -0
- {cryptoparser-1.0.2 → cryptoparser-1.1.1}/test/common/test_utils.py +0 -0
- {cryptoparser-1.0.2 → cryptoparser-1.1.1}/test/common/test_x509.py +0 -0
- {cryptoparser-1.0.2/test/httpx → cryptoparser-1.1.1/test/dnsrec}/__init__.py +0 -0
- {cryptoparser-1.0.2 → cryptoparser-1.1.1}/test/dnsrec/test_record.py +0 -0
- {cryptoparser-1.0.2 → cryptoparser-1.1.1}/test/dnsrec/test_txt.py +0 -0
- {cryptoparser-1.0.2/test/ssh → cryptoparser-1.1.1/test/httpx}/__init__.py +0 -0
- {cryptoparser-1.0.2 → cryptoparser-1.1.1}/test/httpx/classes.py +0 -0
- {cryptoparser-1.0.2 → cryptoparser-1.1.1}/test/httpx/test_header.py +0 -0
- {cryptoparser-1.0.2 → cryptoparser-1.1.1}/test/httpx/test_version.py +0 -0
- {cryptoparser-1.0.2/test/tls → cryptoparser-1.1.1/test/ike}/__init__.py +0 -0
- {cryptoparser-1.0.2 → cryptoparser-1.1.1}/test/ssh/test_ciphersuites.py +0 -0
- {cryptoparser-1.0.2 → cryptoparser-1.1.1}/test/ssh/test_record.py +0 -0
- {cryptoparser-1.0.2 → cryptoparser-1.1.1}/test/ssh/test_subprotocol.py +0 -0
- {cryptoparser-1.0.2 → cryptoparser-1.1.1}/test/ssh/test_version.py +0 -0
- {cryptoparser-1.0.2 → cryptoparser-1.1.1}/test/tls/classes.py +0 -0
- {cryptoparser-1.0.2 → cryptoparser-1.1.1}/test/tls/test_alert.py +0 -0
- {cryptoparser-1.0.2 → cryptoparser-1.1.1}/test/tls/test_application_data.py +0 -0
- {cryptoparser-1.0.2 → cryptoparser-1.1.1}/test/tls/test_change_cipher_spec.py +0 -0
- {cryptoparser-1.0.2 → cryptoparser-1.1.1}/test/tls/test_ciphersuite.py +0 -0
- {cryptoparser-1.0.2 → cryptoparser-1.1.1}/test/tls/test_extension.py +0 -0
- {cryptoparser-1.0.2 → cryptoparser-1.1.1}/test/tls/test_grease.py +0 -0
- {cryptoparser-1.0.2 → cryptoparser-1.1.1}/test/tls/test_handshake.py +0 -0
- {cryptoparser-1.0.2 → cryptoparser-1.1.1}/test/tls/test_ldap.py +0 -0
- {cryptoparser-1.0.2 → cryptoparser-1.1.1}/test/tls/test_mysql.py +0 -0
- {cryptoparser-1.0.2 → cryptoparser-1.1.1}/test/tls/test_openvpn.py +0 -0
- {cryptoparser-1.0.2 → cryptoparser-1.1.1}/test/tls/test_postgresql.py +0 -0
- {cryptoparser-1.0.2 → cryptoparser-1.1.1}/test/tls/test_rdp.py +0 -0
- {cryptoparser-1.0.2 → cryptoparser-1.1.1}/test/tls/test_record.py +0 -0
- {cryptoparser-1.0.2 → cryptoparser-1.1.1}/test/tls/test_version.py +0 -0
|
@@ -2,6 +2,30 @@
|
|
|
2
2
|
Changelog
|
|
3
3
|
=========
|
|
4
4
|
|
|
5
|
+
------------------
|
|
6
|
+
1.1.1 - 2026-05-03
|
|
7
|
+
------------------
|
|
8
|
+
|
|
9
|
+
Notable fixes
|
|
10
|
+
=============
|
|
11
|
+
|
|
12
|
+
- SSH
|
|
13
|
+
|
|
14
|
+
- add missing key size property (#96)
|
|
15
|
+
|
|
16
|
+
-------------------
|
|
17
|
+
1.1.0 - 2026-02-13
|
|
18
|
+
-------------------
|
|
19
|
+
|
|
20
|
+
Features
|
|
21
|
+
========
|
|
22
|
+
|
|
23
|
+
- IKE (``ike``)
|
|
24
|
+
|
|
25
|
+
- add ISAKMP header parsing (#91)
|
|
26
|
+
- add parser/composer for mandatory IKEv2 protocol elements (#91)
|
|
27
|
+
- add parser/composer for mandatory IKEv1 protocol elements (#91)
|
|
28
|
+
|
|
5
29
|
-------------------
|
|
6
30
|
1.0.2 - 2025-12-30
|
|
7
31
|
-------------------
|
|
@@ -33,7 +57,7 @@ Refactor
|
|
|
33
57
|
|
|
34
58
|
- Generic
|
|
35
59
|
|
|
36
|
-
- Support only Python version greater or
|
|
60
|
+
- Support only Python version greater than or equal to 3.9
|
|
37
61
|
- Use pyproject.toml instead of setup.py
|
|
38
62
|
|
|
39
63
|
-------------------
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: CryptoParser
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.1.1
|
|
4
4
|
Summary: An analysis oriented security protocol parser and generator
|
|
5
5
|
Author-email: Szilárd Pfeiffer <coroner@pfeifferszilard.hu>
|
|
6
6
|
Maintainer-email: Szilárd Pfeiffer <coroner@pfeifferszilard.hu>
|
|
@@ -10,7 +10,7 @@ Project-URL: Changelog, https://cryptoparser.readthedocs.io/en/latest/changelog
|
|
|
10
10
|
Project-URL: Documentation, https://cryptoparser.readthedocs.io/en/latest/
|
|
11
11
|
Project-URL: Issues, https://gitlab.com/coroner/cryptoparser/-/issues
|
|
12
12
|
Project-URL: Source, https://gitlab.com/coroner/cryptoparser
|
|
13
|
-
Keywords: ssl,tls,gost,ja3,ldap,rdp,ssh,hsts,dns
|
|
13
|
+
Keywords: ssl,tls,gost,ja3,ldap,rdp,ssh,hsts,dns,ike
|
|
14
14
|
Classifier: Development Status :: 5 - Production/Stable
|
|
15
15
|
Classifier: Environment :: Console
|
|
16
16
|
Classifier: Framework :: tox
|
|
@@ -40,7 +40,7 @@ Description-Content-Type: text/x-rst
|
|
|
40
40
|
License-File: LICENSE.txt
|
|
41
41
|
Requires-Dist: asn1crypto
|
|
42
42
|
Requires-Dist: attrs
|
|
43
|
-
Requires-Dist: cryptodatahub==1.
|
|
43
|
+
Requires-Dist: cryptodatahub==1.1.1
|
|
44
44
|
Requires-Dist: urllib3
|
|
45
45
|
Provides-Extra: tests
|
|
46
46
|
Requires-Dist: pyfakefs; extra == "tests"
|
|
@@ -34,6 +34,12 @@ cryptoparser/httpx/__init__.py
|
|
|
34
34
|
cryptoparser/httpx/header.py
|
|
35
35
|
cryptoparser/httpx/parse.py
|
|
36
36
|
cryptoparser/httpx/version.py
|
|
37
|
+
cryptoparser/ike/__init__.py
|
|
38
|
+
cryptoparser/ike/common.py
|
|
39
|
+
cryptoparser/ike/ikev1.py
|
|
40
|
+
cryptoparser/ike/ikev2.py
|
|
41
|
+
cryptoparser/ike/isakmp.py
|
|
42
|
+
cryptoparser/ike/version.py
|
|
37
43
|
cryptoparser/ssh/__init__.py
|
|
38
44
|
cryptoparser/ssh/key.py
|
|
39
45
|
cryptoparser/ssh/record.py
|
|
@@ -81,6 +87,15 @@ test/httpx/__init__.py
|
|
|
81
87
|
test/httpx/classes.py
|
|
82
88
|
test/httpx/test_header.py
|
|
83
89
|
test/httpx/test_version.py
|
|
90
|
+
test/ike/__init__.py
|
|
91
|
+
test/ike/classes.py
|
|
92
|
+
test/ike/test_ikev1_payload.py
|
|
93
|
+
test/ike/test_ikev1_sa.py
|
|
94
|
+
test/ike/test_ikev2_notify.py
|
|
95
|
+
test/ike/test_ikev2_payload.py
|
|
96
|
+
test/ike/test_ikev2_sa.py
|
|
97
|
+
test/ike/test_isakmp.py
|
|
98
|
+
test/ike/test_version.py
|
|
84
99
|
test/ssh/__init__.py
|
|
85
100
|
test/ssh/test_ciphersuites.py
|
|
86
101
|
test/ssh/test_key.py
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: CryptoParser
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.1.1
|
|
4
4
|
Summary: An analysis oriented security protocol parser and generator
|
|
5
5
|
Author-email: Szilárd Pfeiffer <coroner@pfeifferszilard.hu>
|
|
6
6
|
Maintainer-email: Szilárd Pfeiffer <coroner@pfeifferszilard.hu>
|
|
@@ -10,7 +10,7 @@ Project-URL: Changelog, https://cryptoparser.readthedocs.io/en/latest/changelog
|
|
|
10
10
|
Project-URL: Documentation, https://cryptoparser.readthedocs.io/en/latest/
|
|
11
11
|
Project-URL: Issues, https://gitlab.com/coroner/cryptoparser/-/issues
|
|
12
12
|
Project-URL: Source, https://gitlab.com/coroner/cryptoparser
|
|
13
|
-
Keywords: ssl,tls,gost,ja3,ldap,rdp,ssh,hsts,dns
|
|
13
|
+
Keywords: ssl,tls,gost,ja3,ldap,rdp,ssh,hsts,dns,ike
|
|
14
14
|
Classifier: Development Status :: 5 - Production/Stable
|
|
15
15
|
Classifier: Environment :: Console
|
|
16
16
|
Classifier: Framework :: tox
|
|
@@ -40,7 +40,7 @@ Description-Content-Type: text/x-rst
|
|
|
40
40
|
License-File: LICENSE.txt
|
|
41
41
|
Requires-Dist: asn1crypto
|
|
42
42
|
Requires-Dist: attrs
|
|
43
|
-
Requires-Dist: cryptodatahub==1.
|
|
43
|
+
Requires-Dist: cryptodatahub==1.1.1
|
|
44
44
|
Requires-Dist: urllib3
|
|
45
45
|
Provides-Extra: tests
|
|
46
46
|
Requires-Dist: pyfakefs; extra == "tests"
|
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
2
|
|
|
3
|
+
import typing
|
|
4
|
+
|
|
3
5
|
import attr
|
|
4
6
|
|
|
5
7
|
|
|
6
8
|
@attr.s
|
|
7
9
|
class InvalidDataLength(Exception):
|
|
8
|
-
bytes_needed = attr.ib(
|
|
10
|
+
bytes_needed: typing.Optional[int] = attr.ib(
|
|
11
|
+
default=None,
|
|
12
|
+
validator=attr.validators.optional(attr.validators.instance_of(int))
|
|
13
|
+
)
|
|
9
14
|
|
|
10
15
|
|
|
11
16
|
@attr.s
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
|
+
# pylint: disable=too-many-lines
|
|
2
3
|
|
|
3
4
|
import abc
|
|
4
5
|
import collections.abc
|
|
@@ -6,6 +7,7 @@ import datetime
|
|
|
6
7
|
import enum
|
|
7
8
|
import struct
|
|
8
9
|
import time
|
|
10
|
+
import typing
|
|
9
11
|
|
|
10
12
|
import attr
|
|
11
13
|
|
|
@@ -88,9 +90,12 @@ class ByteOrder(enum.Enum):
|
|
|
88
90
|
|
|
89
91
|
@attr.s
|
|
90
92
|
class ParserBase(collections.abc.Mapping):
|
|
91
|
-
_parsable
|
|
92
|
-
|
|
93
|
-
|
|
93
|
+
_parsable: typing.Union[bytes, bytearray] = attr.ib(
|
|
94
|
+
converter=bytes,
|
|
95
|
+
validator=attr.validators.instance_of((bytes, bytearray))
|
|
96
|
+
)
|
|
97
|
+
_parsed_length: int = attr.ib(init=False, default=0)
|
|
98
|
+
_parsed_values: typing.Dict[str, typing.Any] = attr.ib(init=False, default=None)
|
|
94
99
|
|
|
95
100
|
def __attrs_post_init__(self):
|
|
96
101
|
if self._parsed_values is None:
|
|
@@ -279,6 +284,7 @@ class ParserText(ParserBase):
|
|
|
279
284
|
name, min_length, max_length, self._encoding, str
|
|
280
285
|
)
|
|
281
286
|
except NotEnoughData as e:
|
|
287
|
+
assert e.bytes_needed is not None
|
|
282
288
|
raise InvalidValue(self._parsable[self._parsed_length:min_length - e.bytes_needed], type(self), name) from e
|
|
283
289
|
|
|
284
290
|
if value != actual_value:
|
|
@@ -489,7 +495,7 @@ class ParserText(ParserBase):
|
|
|
489
495
|
|
|
490
496
|
@attr.s
|
|
491
497
|
class ParserBinary(ParserBase):
|
|
492
|
-
byte_order = attr.ib(default=ByteOrder.NETWORK, validator=attr.validators.in_(ByteOrder))
|
|
498
|
+
byte_order: ByteOrder = attr.ib(default=ByteOrder.NETWORK, validator=attr.validators.in_(ByteOrder))
|
|
493
499
|
|
|
494
500
|
def parse_timestamp(self, name, milliseconds=False, item_size=8):
|
|
495
501
|
value, parsed_length = self._parse_numeric_array(name, 1, item_size, int)
|
|
@@ -543,6 +549,13 @@ class ParserBinary(ParserBase):
|
|
|
543
549
|
self._parsed_length += parsed_length
|
|
544
550
|
self._parsed_values[name] = value[0]
|
|
545
551
|
|
|
552
|
+
def parse_numeric_enum_coded(self, name, enum_class):
|
|
553
|
+
param = list(enum_class)[0].value
|
|
554
|
+
value, parsed_length = self._parse_numeric_array(name, 1, param.get_code_size(), enum_class.from_code)
|
|
555
|
+
|
|
556
|
+
self._parsed_length += parsed_length
|
|
557
|
+
self._parsed_values[name] = value[0]
|
|
558
|
+
|
|
546
559
|
def parse_numeric_array(self, name, item_num, item_size, converter=int):
|
|
547
560
|
value, parsed_length = self._parse_numeric_array(name, item_num, item_size, converter)
|
|
548
561
|
|
|
@@ -840,7 +853,7 @@ class ComposerText(ComposerBase):
|
|
|
840
853
|
|
|
841
854
|
@attr.s
|
|
842
855
|
class ComposerBinary(ComposerBase):
|
|
843
|
-
byte_order = attr.ib(default=ByteOrder.NETWORK, validator=attr.validators.in_(ByteOrder))
|
|
856
|
+
byte_order: ByteOrder = attr.ib(default=ByteOrder.NETWORK, validator=attr.validators.in_(ByteOrder))
|
|
844
857
|
|
|
845
858
|
def compose_timestamp(self, value, milliseconds=False, item_size=8):
|
|
846
859
|
if value is None:
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
import abc
|
|
2
|
+
import enum
|
|
3
|
+
import typing
|
|
4
|
+
|
|
5
|
+
import attr
|
|
6
|
+
|
|
7
|
+
from cryptodatahub.common.exception import InvalidValue
|
|
8
|
+
|
|
9
|
+
from cryptoparser.common.exception import InvalidType
|
|
10
|
+
from cryptoparser.common.parse import ParsableBase, ParserBinary, ComposerBinary
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@attr.s
|
|
14
|
+
class DataAttributeBase(ParsableBase):
|
|
15
|
+
"""Data attribute base parser.
|
|
16
|
+
|
|
17
|
+
.. code-block:: text
|
|
18
|
+
|
|
19
|
+
1 2 3
|
|
20
|
+
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
|
21
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
22
|
+
!A! Attribute Type ! AF=0 Attribute Length !
|
|
23
|
+
!F! ! AF=1 Attribute Value !
|
|
24
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
25
|
+
. AF=0 Attribute Value .
|
|
26
|
+
. AF=1 Not Transmitted .
|
|
27
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
@classmethod
|
|
31
|
+
@abc.abstractmethod
|
|
32
|
+
def _parse(cls, parsable):
|
|
33
|
+
raise NotImplementedError()
|
|
34
|
+
|
|
35
|
+
@abc.abstractmethod
|
|
36
|
+
def compose(self):
|
|
37
|
+
raise NotImplementedError()
|
|
38
|
+
|
|
39
|
+
@classmethod
|
|
40
|
+
@abc.abstractmethod
|
|
41
|
+
def get_type(cls):
|
|
42
|
+
raise NotImplementedError()
|
|
43
|
+
|
|
44
|
+
@classmethod
|
|
45
|
+
def _get_format(cls):
|
|
46
|
+
raise NotImplementedError()
|
|
47
|
+
|
|
48
|
+
@classmethod
|
|
49
|
+
def _parse_header(cls, parsable):
|
|
50
|
+
parser = ParserBinary(parsable)
|
|
51
|
+
|
|
52
|
+
parser.parse_numeric('format', 1, DataAttributeFormat)
|
|
53
|
+
if parser['format'] != cls._get_format():
|
|
54
|
+
raise InvalidType()
|
|
55
|
+
|
|
56
|
+
parser.parse_numeric_enum_coded('type', type(cls.get_type()))
|
|
57
|
+
if parser['type'] != cls.get_type():
|
|
58
|
+
raise InvalidType()
|
|
59
|
+
|
|
60
|
+
return parser
|
|
61
|
+
|
|
62
|
+
def _compose_header(self):
|
|
63
|
+
composer = ComposerBinary()
|
|
64
|
+
|
|
65
|
+
composer.compose_numeric(self._get_format().value, 1)
|
|
66
|
+
composer.compose_numeric_enum_coded(self.get_type())
|
|
67
|
+
|
|
68
|
+
return composer
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
class DataAttributeFormat(enum.IntEnum):
|
|
72
|
+
"""Data attribute types."""
|
|
73
|
+
TYPE_LENGTH_VALUE = 0x00
|
|
74
|
+
TYPE_VALUE = 0x80
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
@attr.s
|
|
78
|
+
class DataAttributeTypeValue(DataAttributeBase):
|
|
79
|
+
"""Data attribute type/value parser."""
|
|
80
|
+
|
|
81
|
+
@classmethod
|
|
82
|
+
@abc.abstractmethod
|
|
83
|
+
def get_type(cls):
|
|
84
|
+
raise NotImplementedError()
|
|
85
|
+
|
|
86
|
+
@classmethod
|
|
87
|
+
@abc.abstractmethod
|
|
88
|
+
def _parse(cls, parsable):
|
|
89
|
+
raise NotImplementedError()
|
|
90
|
+
|
|
91
|
+
@abc.abstractmethod
|
|
92
|
+
def compose(self):
|
|
93
|
+
raise NotImplementedError()
|
|
94
|
+
|
|
95
|
+
@classmethod
|
|
96
|
+
def _get_format(cls):
|
|
97
|
+
return DataAttributeFormat.TYPE_VALUE
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
@attr.s
|
|
101
|
+
class DataAttributeTypeValueEnumCoded(DataAttributeTypeValue):
|
|
102
|
+
"""Data attribute type/value parser where the type is an enum."""
|
|
103
|
+
|
|
104
|
+
value: typing.Any = attr.ib()
|
|
105
|
+
|
|
106
|
+
@classmethod
|
|
107
|
+
@abc.abstractmethod
|
|
108
|
+
def get_type(cls):
|
|
109
|
+
raise NotImplementedError()
|
|
110
|
+
|
|
111
|
+
@classmethod
|
|
112
|
+
@abc.abstractmethod
|
|
113
|
+
def _get_enum_type(cls):
|
|
114
|
+
raise NotImplementedError()
|
|
115
|
+
|
|
116
|
+
@value.validator
|
|
117
|
+
def _validate_value(self, _, value):
|
|
118
|
+
enum_type = self._get_enum_type()
|
|
119
|
+
if not isinstance(value, enum_type):
|
|
120
|
+
raise InvalidValue(value, type(self), 'value')
|
|
121
|
+
|
|
122
|
+
@classmethod
|
|
123
|
+
def _parse(cls, parsable):
|
|
124
|
+
parser = cls._parse_header(parsable)
|
|
125
|
+
|
|
126
|
+
parser.parse_numeric_enum_coded('value', cls._get_enum_type())
|
|
127
|
+
|
|
128
|
+
return cls(value=parser['value']), parser.parsed_length
|
|
129
|
+
|
|
130
|
+
def compose(self):
|
|
131
|
+
composer = self._compose_header()
|
|
132
|
+
|
|
133
|
+
composer.compose_numeric_enum_coded(self.value)
|
|
134
|
+
|
|
135
|
+
return composer.composed_bytes
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
@attr.s
|
|
139
|
+
class DataAttributeKeyLength(DataAttributeTypeValue):
|
|
140
|
+
"""Key Length transform attribute (TV format).
|
|
141
|
+
|
|
142
|
+
The Key Length attribute has the following format:
|
|
143
|
+
|
|
144
|
+
0 1 2 3
|
|
145
|
+
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
|
146
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
147
|
+
|A| Attribute Type | Key Length (in bits) |
|
|
148
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
149
|
+
|
|
150
|
+
:ivar key_length: Key length in bits
|
|
151
|
+
"""
|
|
152
|
+
|
|
153
|
+
value: int = attr.ib(validator=attr.validators.and_(
|
|
154
|
+
attr.validators.instance_of(int),
|
|
155
|
+
attr.validators.ge(0),
|
|
156
|
+
attr.validators.lt(2**64)
|
|
157
|
+
))
|
|
158
|
+
|
|
159
|
+
@classmethod
|
|
160
|
+
@abc.abstractmethod
|
|
161
|
+
def get_type(cls):
|
|
162
|
+
raise NotImplementedError()
|
|
163
|
+
|
|
164
|
+
@classmethod
|
|
165
|
+
def _parse(cls, parsable):
|
|
166
|
+
parser = cls._parse_header(parsable)
|
|
167
|
+
parser.parse_numeric('value', 2)
|
|
168
|
+
|
|
169
|
+
return cls(value=parser['value']), parser.parsed_length
|
|
170
|
+
|
|
171
|
+
def compose(self):
|
|
172
|
+
composer = self._compose_header()
|
|
173
|
+
|
|
174
|
+
composer.compose_numeric(self.value, 2)
|
|
175
|
+
|
|
176
|
+
return composer.composed_bytes
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
@attr.s
|
|
180
|
+
class DataAttributeLength(DataAttributeBase):
|
|
181
|
+
"""Length transform attribute (TLV format).
|
|
182
|
+
|
|
183
|
+
The Key Length attribute has the following format:
|
|
184
|
+
|
|
185
|
+
0 1 2 3
|
|
186
|
+
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
|
187
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
188
|
+
|A| Attribute Type | Key Length (in bits) |
|
|
189
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
190
|
+
|
|
191
|
+
:ivar key_length: Key length in bits
|
|
192
|
+
"""
|
|
193
|
+
|
|
194
|
+
value: int = attr.ib(validator=attr.validators.and_(
|
|
195
|
+
attr.validators.instance_of(int),
|
|
196
|
+
attr.validators.ge(0),
|
|
197
|
+
attr.validators.lt(2**64)
|
|
198
|
+
))
|
|
199
|
+
|
|
200
|
+
@classmethod
|
|
201
|
+
@abc.abstractmethod
|
|
202
|
+
def get_type(cls):
|
|
203
|
+
raise NotImplementedError()
|
|
204
|
+
|
|
205
|
+
@classmethod
|
|
206
|
+
@abc.abstractmethod
|
|
207
|
+
def _get_size(cls):
|
|
208
|
+
raise NotImplementedError()
|
|
209
|
+
|
|
210
|
+
@classmethod
|
|
211
|
+
def _get_format(cls):
|
|
212
|
+
return DataAttributeFormat.TYPE_VALUE
|
|
213
|
+
|
|
214
|
+
@classmethod
|
|
215
|
+
def _parse(cls, parsable):
|
|
216
|
+
parser = cls._parse_header(parsable)
|
|
217
|
+
|
|
218
|
+
if parser['format'] == DataAttributeFormat.TYPE_LENGTH_VALUE:
|
|
219
|
+
parser.parse_numeric('size', 2)
|
|
220
|
+
parser.parse_numeric('value', parser['size'])
|
|
221
|
+
else:
|
|
222
|
+
parser.parse_numeric('value', cls._get_size())
|
|
223
|
+
|
|
224
|
+
return cls(value=parser['value']), parser.parsed_length
|
|
225
|
+
|
|
226
|
+
def compose(self):
|
|
227
|
+
composer = self._compose_header()
|
|
228
|
+
|
|
229
|
+
if self._get_format() == DataAttributeFormat.TYPE_LENGTH_VALUE:
|
|
230
|
+
composer.compose_numeric(self._get_size(), 2)
|
|
231
|
+
composer.compose_numeric(self.value, self._get_size())
|
|
232
|
+
else:
|
|
233
|
+
composer.compose_numeric(self.value, self._get_size())
|
|
234
|
+
|
|
235
|
+
return composer.composed_bytes
|