{"id":16701483,"url":"https://github.com/ferd/hairnet","last_synced_at":"2025-07-08T23:33:43.642Z","repository":{"id":54877555,"uuid":"57150319","full_name":"ferd/hairnet","owner":"ferd","description":"An Erlang library wrapping AES-GCM (AEAD) crypto in a Fernet-like interface","archived":false,"fork":false,"pushed_at":"2021-01-22T20:50:22.000Z","size":13,"stargazers_count":29,"open_issues_count":0,"forks_count":6,"subscribers_count":3,"default_branch":"master","last_synced_at":"2024-03-14T17:32:23.620Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Erlang","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/ferd.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-04-26T17:58:05.000Z","updated_at":"2024-03-14T17:32:23.621Z","dependencies_parsed_at":"2022-08-14T05:30:46.239Z","dependency_job_id":null,"html_url":"https://github.com/ferd/hairnet","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ferd%2Fhairnet","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ferd%2Fhairnet/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ferd%2Fhairnet/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ferd%2Fhairnet/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ferd","download_url":"https://codeload.github.com/ferd/hairnet/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245116006,"owners_count":20563264,"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-10-12T18:44:15.771Z","updated_at":"2025-03-23T14:31:45.890Z","avatar_url":"https://github.com/ferd.png","language":"Erlang","funding_links":[],"categories":[],"sub_categories":[],"readme":"hairnet\n=====\n\nA take on [fernet](https://github.com/fernet/fernet-erl) using AES-GCM\n([AEAD](https://en.wikipedia.org/wiki/Authenticated_encryption))\nrather than fernet's AES-128 in CBC mode + HMAC.\n\nThe idea is to take what is now a fairly weak crypto library and bring\nit up to a higher standard while maintaining a similar interface.\n\nThe objective is to:\n\n\u003e \"takes a user-provided message (an arbitrary sequence of\n\u003e bytes), a key (256 bits), and the current time, and produces a token, which\n\u003e contains the message in a form that can't be read or altered without the key.\"\n\nIn terms of AEAD, the PlainText will be the user-provided message, the key\nshould be any Erlang binary (please use a different one from the one in\n`fernet` if you are upgrading), and the current time is going to be used as\nthe additional authenticated data (AAD), which can be used by the party\ndoing decryption to validate for staleness.\n\n\n## Interface\n\n```erlang\n1\u003e Key = hairnet:generate_encoded_key().\n\u003c\u003c\"BVt1_R20scbTwz9t05PrtE4EFAauMeRKTxbwYmUiafY=\"\u003e\u003e\n2\u003e Token = hairnet:generate_token(\"hello\", Key).\n\u003c\u003c\"AQAAAABXH4wKw8DqUtDjJxAX3BuEHGP9xke0tfY-73uzVCpa1iT5f1wgAAAABbhBUeFl\"\u003e\u003e\n3\u003e hairnet:verify_and_decrypt_token(Token, Key, infinity).\n{ok, \u003c\u003c\"hello\"\u003e\u003e}\n4\u003e TTL = 10. % 10 Seconds\n10\n5\u003e hairnet:verify_and_decrypt_token(Token, Key, TTL).\n{error, too_old}\n```\n\n### Difference from fernet\n\n- `encode_key/2` is gone, since there is no longer a distinction between\n  a signing and an encryption key; the AES-GCM algorithm handles this.\n- The format changed since the data size is more variable given the AAD,\n  and prefixed lengths are being used to carry the content.\n- pkcs7 is no longer needed, and the padding-related errors are no longer\n  returnable, since this is all handled by the crypto library.\n- block sizes warnings are gone, instead an overall `payload_format`\n  error value can be returned.\n- Dropped compatibility for pre-18 Erlang/OTP copies\n\nBuild\n-----\n\n    $ rebar3 compile\n\nTest\n----\n\n    $ rebar3 do eunit, dialyzer\n\nWarnings\n--------\n\nThe [publications from NIST on the\nalgorithm](http://csrc.nist.gov/publications/nistpubs/800-38D/SP-800-38D.pdf)\nhave the following specifications:\n\n\u003e The following requirement applies to all implementations that use either 1) the\n\u003e deterministic construction with IVs whose length is not 96, or 2) the RBG-based\n\u003e construction, for IVs of any length. In other words, unless an implementation\n\u003e only uses 96-bit IVs that are generated by the deterministic construction:\n\u003e \n\u003e **The total number of invocations of the authenticated encryption function shall\n\u003e not exceed 2^32, including all IV lengths and all instances of the\n\u003e authenticated encryption function with the given key.**\n\u003e \n\u003e This is a “global” requirement that can be achieved by appropriate “local”\n\u003e limits on each instance of the authenticated encryption function with a given\n\u003e key. For example, suppose an implementation consists of 2^10 devices that only\n\u003e support 64-bit, 96-bit, and 128-bit IVs. One way to satisfy the above\n\u003e requirement would be to limit each device to 2^20 invocations with 64-bit IVs,\n\u003e 2^21 invocations with 96-bit IVs, and 2^20 invocations with 128-bit IVs.\n\nThis implementation uses Erlang's `crypto:strong_rand_bytes(16)` to generate\n128-bit IVs.\n\nAs such, it would be recommended to rotate the key used to encrypt content once\nsuch limits (2^21 calls locally, or 2^32 overall) are reached to avoid\nweakening the security of the private key.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fferd%2Fhairnet","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fferd%2Fhairnet","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fferd%2Fhairnet/lists"}