{"id":18600920,"url":"https://github.com/cloudtools/tinyber","last_synced_at":"2025-04-11T04:52:16.467Z","repository":{"id":57475709,"uuid":"39220631","full_name":"cloudtools/tinyber","owner":"cloudtools","description":"ASN.1 BER codec and compiler (C/Python) for embedded/small systems","archived":false,"fork":false,"pushed_at":"2015-07-27T23:37:17.000Z","size":316,"stargazers_count":15,"open_issues_count":1,"forks_count":7,"subscribers_count":8,"default_branch":"master","last_synced_at":"2025-03-25T03:01:37.231Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cloudtools.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-07-16T21:09:06.000Z","updated_at":"2024-11-23T15:10:00.000Z","dependencies_parsed_at":"2022-09-07T13:51:35.740Z","dependency_job_id":null,"html_url":"https://github.com/cloudtools/tinyber","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cloudtools%2Ftinyber","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cloudtools%2Ftinyber/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cloudtools%2Ftinyber/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cloudtools%2Ftinyber/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cloudtools","download_url":"https://codeload.github.com/cloudtools/tinyber/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247987108,"owners_count":21028891,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-07T02:06:26.301Z","updated_at":"2025-04-11T04:52:16.452Z","avatar_url":"https://github.com/cloudtools.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"\nTinyBER\n=======\n\n![tinyber logo](http://www.rps.org/~/media/Exhibitions/2013/June/25/Images%20for%20Science/019_Tardigr_Pm_Craterl_400x2_2010_Nicole_Ottawa.ashx?bc=White\u0026mw=400 \"tardigrade\")\n\nTinyBER is a very small, limited ASN.1 BER codec and code generator\nmeant for use on embedded devices (or anywhere code size is\nrestricted).  The generated code uses fixed-size structures and makes\nno calls to malloc or free.\n\nInstall\n-------\n\n```shell\n$ sudo python setup.py install\n```\n\nUsage\n-----\n\nTinyBER can be used for ad-hoc encoding and decoding of data, but it\nalso comes with a limited code generator.\n\nBuffers\n-------\n\nA simple ``buf_t`` structure is used for both input and output::\n\n```c\n    typedef struct {\n      uint8_t * buffer;\n      unsigned int pos;\n      unsigned int size;\n    } buf_t;\n```\n\nEncoding\n--------\n\nEncoding is a little unusual.  In the interest of efficiency, data can\nbe encoded directly into an output buffer - backwards.  Because asn.1\nstructures tend to accumulate in reverse (the Type and Length precede\nthe Value in the stream), the most efficient way to *encode* them is to\ndo so in reverse.\n\nFor example, to encode a SEQUENCE of objects there are three steps::\n\n```c\n    int mark0 = obuf.pos;\n    CHECK (encode_OCTET_STRING (\u0026obuf, (uint8_t *) \"ghi\", 3));\n    CHECK (encode_OCTET_STRING (\u0026obuf, (uint8_t *) \"def\", 3));\n    CHECK (encode_OCTET_STRING (\u0026obuf, (uint8_t *) \"abc\", 3));\n    CHECK (encode_TLV (\u0026obuf, mark0, TAG_SEQUENCE));\n```\n\n1. Remember the stream's position (record the value of obuf.pos).\n2. Encode each item of the SEQUENCE in reverse.\n3. Emit the type and length for the entire sequence.\n\nNote that the ``buf_t`` object is used in a 'predecrement' mode. When\nyou initialize a buffer for output, its ``pos`` field points to the\n*end* of the buffer.  As data is written, ``pos`` moves backward.\n\n\nDecoding\n--------\n\nWhen decoding an object, first call ``decode_TLV()`` to get the type,\nlength, and value pointers to the object::\n\n```c\n    buf_t src;\n    init_ibuf (\u0026src, data, length);\n    asn1raw dst;\n    int r = decode_TLV (\u0026dst, \u0026src);\n```\n\nNow examine the type tag - if it is the expected type, then you may\nfurther decode the value.  If the value itself makes up a more complex\nstructure, continue the procedure recursively.\n\nA simple utility structure, ``asn1raw`` is used to represent a TLV::\n\n```c\n    typedef struct {\n      uint8_t type;\n      int length;\n      uint8_t * value;\n      } asn1raw;\n```\n\nTo decode a 'structured' element (i.e., a SEQUENCE or SET), create an\narray of ``asn1raw`` objects, and pass it to ``decode_structured()``::\n\n```c\n    asn1raw subs[50];\n    int n = 50;\n    int i;\n    CHECK (decode_structured (ob, \u0026subs[0], \u0026n));\n```\n\nIn this example we allow up to 50 sub-elements.  If more are present\nin the stream an error will be returned.  If there are less than 50\nthe actual number will be set in ``n`` (i.e., ``n`` is an in-out\nparam).\n\nNow that you have the metadata for each sub-element, you may\nrecursively continue decoding each one in turn.  (This could be viewed\nas a form of recursive-descent parser).\n\nLimitations\n-----------\n\nThis is not a full BER codec by any stretch: for example it supports\nonly definite-length (i.e., actual length is always prepended), and as\nsuch it can be used for DER encoding as long as care is taken to\nfollow the rules.\n\nIt does not support INTEGERs larger than a machine int (int64_t by default).\n\nStill missing are direct support for SET, APPLICATION, BITSTRING,\nOIDs, etc... though if you are familiar with BER they can be\nimplemented with relative ease.\n\nBecause tinyber requires fixed-sized elements for all structures (to\navoid malloc \u0026 free), using recursive (or mutually recursive) types is\nimpossible::\n\n```asn1\n    List ::= SEQUENCE {\n        car INTEGER,\n\t    cdr List OPTIONAL\n    }\n```\n\nTinyber can't make a fixed-sized structure that might hold a\npotentially infinite list, so it cannot handle this kind of\nconstruction.\n\nCode Generation\n---------------\n\nIncluded is a code generator, ``tinyber_gen.py``, which can generate\ntype definitions and BER encoders/decoders for a limited subset of the\nASN.1 specification language (X.680) in C and Python.\n\n```text\nusage: tinyber_gen [-h] [-o OUTDIR] [-l LANG] [-ns] FILE\n\ntinyber ASN.1 BER/DER code generator.\n\npositional arguments:\n  FILE                  asn.1 spec\n\noptional arguments:\n  -h, --help            show this help message and exit\n  -o OUTDIR, --outdir OUTDIR\n                        output directory (defaults to location of input file)\n  -l LANG, --lang LANG  output language ('c' or 'python')\n  -ns, --no-standalone  [python only] do not insert codec.py into output file.\n```\n\nFor example::\n\n```bash\n    beast:tinyber rushing$ python tinyber_gen.py -l c thing.asn1\n    beast:tinyber rushing$ ls -l thing.[ch]\n    -rw-r--r--  1 rushing  staff  20240 Jan 20 13:08 thing.c\n    -rw-r--r--  1 rushing  staff   4939 Jan 20 13:08 thing.h\n    beast:tinyber rushing$\n```\n\n\nThe code generator requires the\n[asn1ate package](https://github.com/kimgr/asn1ate) to be installed.\n``asn1ate`` is a parser for X.680 designed for use by code generators.\n\n\nModule Design\n-------------\n\nIf your goal is to keep your codec as small as possible, a good approach is\nto segregate your packet types into 'server' and 'client' groups.  Otherwise\nthe outermost CHOICE PDU will force the inclusion of both server and client\nencoders and decoders on both sides.  If you use two different PDU's, you will\nget only the encoders and decoders needed for each side.  For example::\n\n```asn1\n    ThingModule DEFINITIONS ::= BEGIN\n\n      ThingClientMessage ::= CHOICE {\n        login-request  [0] LoginRequest,\n        status-request [1] StatusRequest,\n\t  }\n\n      ThingServerMessage ::= CHOICE {\n          login-reply  [0] LoginReply,\n          status-reply [1] StatusReply\n      }\n```\n\nLicensing\n---------\nThis software is licensed under the Apache 2 license. However, the output,\nwhich is included into other projects, is not encumbered with any license\nrestrictions. See the LICENSE.txt for more details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcloudtools%2Ftinyber","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcloudtools%2Ftinyber","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcloudtools%2Ftinyber/lists"}