{ "info": { "author": "Maciej Piku\u0142a", "author_email": "erupikus@gmail.com", "bugtrack_url": null, "classifiers": [ "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7" ], "description": "# asn1PERser\nThis library can parse ASN.1 text schemas into Python code. ASN.1 PER (Aligned) decoder/encoder is included to use with parsed schemas.\n\nSupported ASN.1 types and their constraints are:\n\n| ASN.1 Type | Single value | Value range | Value size | can be extended (...) | used Python contraint class |\n|:------------:|:------------:|:-----------:|:----------:|:---------------------:|:---------------------------:|\n| INTEGER | X | X | | X | ValueRange |\n| BOOLEAN | | | | | |\n| ENUMERATED | | | | X | ExtensionMarker |\n| BIT STRING | X | | X | X | ValueSize |\n| OCTET STRING | X | | X | X | ValueSize |\n| CHOICE | | | | X | ExtensionMarker |\n| SEQUENCE | | | | X | ExtensionMarker |\n| SEQUENCE OF | X | | X | X | SequenceOfValueSize |\n\nOn how to use them please see example down below.\n\n## Example\nFollowing ASN.1 schema:\n\n```python\nasn_schema = '''\\\nSimpleProtocol DEFINITIONS AUTOMATIC TAGS ::=\nBEGIN\nSimpleMessage ::= CHOICE {\n start Start,\n stop Stop,\n alive Alive,\n data Data,\n ...\n}\n\nStart ::= SEQUENCE {\n sequenceNumber SequenceNumber,\n timestamp UTC-Timestamp,\n srcPort Port,\n dstPort Port\n}\n\nStop ::= SEQUENCE {\n sequenceNumber SequenceNumber,\n timestamp UTC-Timestamp,\n srcPort Port,\n dstPort Port\n}\n\nAlive ::= SEQUENCE {\n timestamp UTC-Timestamp,\n ...\n}\n\nData ::= SEQUENCE {\n sequenceNumber SequenceNumber,\n swRelease ENUMERATED {rel1, rel2, rel3, ...},\n macroId BIT STRING (SIZE(20)) OPTIONAL,\n payload Payload\n}\n\nPort ::= INTEGER (10000..65535)\n\nSequenceNumber ::= INTEGER (0..65535)\n\nUTC-Timestamp ::= SEQUENCE {\n seconds INTEGER (0..4294967295),\n useconds INTEGER (0..4294967295)\n}\n\nPayload ::= SEQUENCE (SIZE(1..5)) OF Message\n\nMessage ::= OCTET STRING (SIZE(1..4))\n\nEND\n'''\n```\n\ncan be parsed into Python code like this:\n```python\nfrom asn1PERser import parse_asn1_schema\n\n\nparse_asn1_schema(asn1_schema=asn_schema, output_folder=r'C:/my_code/')\n```\n\nAbove code will create file 'SimpleProtocol.py' in folder (which must exist) 'C:/my_code/':\n```python\nfrom pyasn1.type.namedtype import NamedType, NamedTypes, OptionalNamedType, DefaultedNamedType\nfrom pyasn1.type.namedval import NamedValues\nfrom asn1PERser.classes.data.builtin import *\nfrom asn1PERser.classes.types.type import AdditiveNamedTypes\nfrom asn1PERser.classes.types.constraint import MIN, MAX, NoConstraint, ExtensionMarker, SequenceOfValueSize, \\\n ValueRange, SingleValue, ValueSize, ConstraintOr, ConstraintAnd\n\n\nclass Port(IntegerType):\n subtypeSpec = ValueRange(10000, 65535)\n\n\nclass SequenceNumber(IntegerType):\n subtypeSpec = ValueRange(0, 65535)\n\n\nclass Message(OctetStringType):\n subtypeSpec = ValueSize(1, 4)\n\n\nclass UTC_Timestamp(SequenceType):\n class seconds(IntegerType):\n subtypeSpec = ValueRange(0, 4294967295)\n\n class useconds(IntegerType):\n subtypeSpec = ValueRange(0, 4294967295)\n\n rootComponent = AdditiveNamedTypes(\n NamedType('seconds', seconds()),\n NamedType('useconds', useconds()),\n )\n componentType = rootComponent\n\n\nclass Start(SequenceType):\n rootComponent = AdditiveNamedTypes(\n NamedType('sequenceNumber', SequenceNumber()),\n NamedType('timestamp', UTC_Timestamp()),\n NamedType('srcPort', Port()),\n NamedType('dstPort', Port()),\n )\n componentType = rootComponent\n\n\nclass Stop(SequenceType):\n rootComponent = AdditiveNamedTypes(\n NamedType('sequenceNumber', SequenceNumber()),\n NamedType('timestamp', UTC_Timestamp()),\n NamedType('srcPort', Port()),\n NamedType('dstPort', Port()),\n )\n componentType = rootComponent\n\n\nclass Alive(SequenceType):\n subtypeSpec = ExtensionMarker(True)\n rootComponent = AdditiveNamedTypes(\n NamedType('timestamp', UTC_Timestamp()),\n )\n componentType = rootComponent\n\n\nclass Payload(SequenceOfType):\n subtypeSpec = SequenceOfValueSize(1, 5)\n componentType = Message()\n\n\nclass Data(SequenceType):\n class swRelease(EnumeratedType):\n subtypeSpec = ExtensionMarker(True)\n enumerationRoot = NamedValues(\n ('rel1', 0),\n ('rel2', 1),\n ('rel3', 2),\n )\n namedValues = enumerationRoot\n\n class macroId(BitStringType):\n subtypeSpec = ValueSize(20, 20)\n\n rootComponent = AdditiveNamedTypes(\n NamedType('sequenceNumber', SequenceNumber()),\n NamedType('swRelease', swRelease()),\n OptionalNamedType('macroId', macroId()),\n NamedType('payload', Payload()),\n )\n componentType = rootComponent\n\n\nclass SimpleMessage(ChoiceType):\n subtypeSpec = ExtensionMarker(True)\n rootComponent = AdditiveNamedTypes(\n NamedType('start', Start()),\n NamedType('stop', Stop()),\n NamedType('alive', Alive()),\n NamedType('data', Data()),\n )\n componentType = rootComponent\n\n\n\n```\n\nWhen schema is parsed it can be used - message can be created, encoded and decoded, using PER encoder/decoder, into bytes\nor Python structure:\n```python\nfrom asn1PERser import encode, decode\nfrom SimpleProtocol import *\n\n\n'''\nsimple_message SimpleMessage ::= alive : {\n timestamp {\n seconds 1557528149,\n useconds 12345\n }\n}\n'''\nutc_timestamp = UTC_Timestamp()\nutc_timestamp['seconds'] = UTC_Timestamp.seconds(1557528149)\nutc_timestamp['useconds'] = UTC_Timestamp.useconds(12345)\n\nmsg_alive = Alive()\nmsg_alive['timestamp'] = utc_timestamp\n\nsimple_message = SimpleMessage()\nsimple_message['alive'] = msg_alive\n\nper_bytes = encode(asn1Spec=simple_message)\nprint('encoded alive bytes as hex string:')\nprint(per_bytes.hex())\nprint('\\n')\n\ndecoded = decode(per_stream=per_bytes, asn1Spec=SimpleMessage())\nprint('decoded alive message structure as string...:')\nprint(decoded)\n\nprint('...can be accessed like dictionary:')\nprint(decoded['alive']['timestamp']['seconds'])\n```\n\nabove will output:\n```\nencoded alive bytes as hex string:\n4c5cd5fe55403039\n\n\nalive message structure as string...:\nSimpleMessage:\n alive=Alive:\n timestamp=UTC_Timestamp:\n seconds=1557528149\n useconds=12345\n\n\n\n...can be accessed like dictionary:\n1557528149\n```\n\nNext message:\n```python\n'''\nsimple_message SimpleMessage ::= start : {\n sequenceNumber 10,\n timestamp {\n seconds 1557528149,\n useconds 12345\n },\n srcPort 65533,\n dstPort 10000\n}\n'''\n\nutc_timestamp = UTC_Timestamp()\nutc_timestamp['seconds'] = UTC_Timestamp.seconds(1557528149)\nutc_timestamp['useconds'] = UTC_Timestamp.useconds(12345)\n\nmsg_start = Start()\nmsg_start['sequenceNumber'] = SequenceNumber(10)\nmsg_start['timestamp'] = utc_timestamp\nmsg_start['srcPort'] = Port(65533)\nmsg_start['dstPort'] = Port(10000)\n\nsimple_message = SimpleMessage()\nsimple_message['start'] = msg_start\n\nper_bytes = encode(asn1Spec=simple_message)\nprint('encoded start bytes as hex string:')\nprint(per_bytes.hex())\nprint('\\n')\n\ndecoded = decode(per_stream=per_bytes, asn1Spec=SimpleMessage())\nprint('start message structure as string...:')\nprint(decoded)\nprint('...can be accessed like dictionary:')\nprint(decoded['start']['srcPort'])\n```\n\nabove will output:\n```\nencoded start bytes as hex string:\n00000ac05cd5fe55403039d8ed0000\n\n\nstart message structure as string...:\nSimpleMessage:\n start=Start:\n sequenceNumber=10\n timestamp=UTC_Timestamp:\n seconds=1557528149\n useconds=12345\n\n srcPort=65533\n dstPort=10000\n\n\n...can be accessed like dictionary:\n65533\n```\n\nNext message:\n```python\n'''\nsimple_message SimpleMessage ::= data : {\n sequenceNumber 55555,\n swRelease rel2,\n macroId '11110000111100001111'B,\n payload {\n 'DEAD'H,\n 'BEEF'H,\n 'FEED'H,\n 'AA'H,\n 'BBBBBBBB'H\n }\n}\n'''\n\ndata_payload = Payload()\ndata_payload.extend([Message(hexValue='DEAD')])\ndata_payload.extend([Message(hexValue='BEEF')])\ndata_payload.extend([Message(hexValue='FEED')])\ndata_payload.extend([Message(hexValue='AA')])\ndata_payload.extend([Message(hexValue='BBBBBBBB')])\n\nmsg_data = Data()\nmsg_data['sequenceNumber'] = SequenceNumber(55555)\nmsg_data['swRelease'] = Data.swRelease('rel2')\nmsg_data['macroId'] = Data.macroId(binValue='11110000111100001111')\nmsg_data['payload'] = data_payload\n\nsimple_message = SimpleMessage()\nsimple_message['data'] = msg_data\n\nper_bytes = encode(asn1Spec=simple_message)\nprint('encoded data bytes as hex string:')\nprint(per_bytes.hex())\nprint('\\n')\n\ndecoded = decode(per_stream=per_bytes, asn1Spec=SimpleMessage())\nprint('data message structure as string...:')\nprint(decoded)\nprint('...can be accessed like dictionary:')\nprint(bytes(decoded['data']['payload'][0]).hex())\n```\n\nabove will output:\n```\nencoded data bytes as hex string:\n70d90320f0f0f880dead40beef40feed00aac0bbbbbbbb\n\n\ndata message structure as string...:\nSimpleMessage:\n data=Data:\n sequenceNumber=55555\n swRelease=rel2\n macroId=986895\n payload=Payload:\n 0xdead 0xbeef 0xfeed 0xaa 0xbbbbbbbb\n\n\n...can be accessed like dictionary:\ndead\n```\n\nNext message:\n```python\n'''\nsimple_message SimpleMessage ::= data : {\n sequenceNumber 256,\n swRelease rel3,\n payload {\n 'DEADBEEF'H\n }\n}\n'''\ndata_payload = Payload()\ndata_payload.extend([Message(hexValue='DEADBEEF')])\n\nmsg_data = Data()\nmsg_data['sequenceNumber'] = SequenceNumber(256)\nmsg_data['swRelease'] = Data.swRelease('rel3')\nmsg_data['payload'] = data_payload\n\nsimple_message = SimpleMessage()\nsimple_message['data'] = msg_data\n\nper_bytes = encode(asn1Spec=simple_message)\nprint('encoded data bytes as hex string:')\nprint(per_bytes.hex())\nprint('\\n')\n\ndecoded = decode(per_stream=per_bytes, asn1Spec=SimpleMessage())\nprint('data message structure as string...:')\nprint(decoded)\nprint('...can be accessed like dictionary:')\nprint(decoded['data']['swRelease'])\n```\n\nabove will output:\n```\nencoded data bytes as hex string:\n60010043deadbeef\n\n\ndata message structure as string...:\nSimpleMessage:\n data=Data:\n sequenceNumber=256\n swRelease=rel3\n payload=Payload:\n 0xdeadbeef\n\n\n...can be accessed like dictionary:\nrel3\n```\n\n## Additional information\n\nFor more examples please see library tests:\n- parsing tests, located in test/parsing/ folder.\n- coding/encoding tests, located in test/per folder.\n\nAll above examples and tests where checked using:\nhttps://asn1.io/asn1playground/\n\nThis library inherits extensively from pyasn1 library so BER and other encoding should also work here.\n\nParsing may take time - when trying to parse about 2000 lines of ASN.1 it took 15-20 minutes.\nTests for parsing also take time.\n\n\n", "description_content_type": "text/markdown", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/erupikus/asn1PERser", "keywords": "asn asn1 asn.1 PER decoder encoder", "license": "", "maintainer": "", "maintainer_email": "", "name": "asn1PERser", "package_url": "https://pypi.org/project/asn1PERser/", "platform": "", "project_url": "https://pypi.org/project/asn1PERser/", "project_urls": { "Homepage": "https://github.com/erupikus/asn1PERser" }, "release_url": "https://pypi.org/project/asn1PERser/0.2.0/", "requires_dist": [ "pyasn1", "pyparsing", "Jinja2" ], "requires_python": "", "summary": "Parse ASN.1 schemas into Python code and encode/decode them using PER encoder", "version": "0.2.0" }, "last_serial": 5286544, "releases": { "0.2.0": [ { "comment_text": "", "digests": { "md5": "a63896d80a26bcb2919c032783e4a451", "sha256": "e3b890a7afa2d676e4d295d93df0bdd5f974fb8cc6bcc4d739bd04b7d0c5523f" }, "downloads": -1, "filename": "asn1PERser-0.2.0-py3-none-any.whl", "has_sig": false, "md5_digest": "a63896d80a26bcb2919c032783e4a451", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 50566, "upload_time": "2019-05-18T20:17:18", "url": "https://files.pythonhosted.org/packages/37/66/f188f1f16ffd91659525afdf870cd2de2aec556508774e97d2f0f7f9388c/asn1PERser-0.2.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "4b89df683a0851a813a634814198182f", "sha256": "632f0aefe9f89d1684f2d0b4d23640274bd65a15badcd13a47e9a41606fb9bba" }, "downloads": -1, "filename": "asn1PERser-0.2.0.tar.gz", "has_sig": false, "md5_digest": "4b89df683a0851a813a634814198182f", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 29643, "upload_time": "2019-05-18T20:17:21", "url": "https://files.pythonhosted.org/packages/ae/6f/d10c561d0361a09b7c0ef7cdc1c3623ae748fc755934541f3c602486aa66/asn1PERser-0.2.0.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "a63896d80a26bcb2919c032783e4a451", "sha256": "e3b890a7afa2d676e4d295d93df0bdd5f974fb8cc6bcc4d739bd04b7d0c5523f" }, "downloads": -1, "filename": "asn1PERser-0.2.0-py3-none-any.whl", "has_sig": false, "md5_digest": "a63896d80a26bcb2919c032783e4a451", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 50566, "upload_time": "2019-05-18T20:17:18", "url": "https://files.pythonhosted.org/packages/37/66/f188f1f16ffd91659525afdf870cd2de2aec556508774e97d2f0f7f9388c/asn1PERser-0.2.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "4b89df683a0851a813a634814198182f", "sha256": "632f0aefe9f89d1684f2d0b4d23640274bd65a15badcd13a47e9a41606fb9bba" }, "downloads": -1, "filename": "asn1PERser-0.2.0.tar.gz", "has_sig": false, "md5_digest": "4b89df683a0851a813a634814198182f", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 29643, "upload_time": "2019-05-18T20:17:21", "url": "https://files.pythonhosted.org/packages/ae/6f/d10c561d0361a09b7c0ef7cdc1c3623ae748fc755934541f3c602486aa66/asn1PERser-0.2.0.tar.gz" } ] }