{"id":14990834,"url":"https://github.com/stef/libopaque","last_synced_at":"2025-04-05T01:07:37.914Z","repository":{"id":37418324,"uuid":"313107076","full_name":"stef/libopaque","owner":"stef","description":"c implementation of the OPAQUE protocol with bindings for python, php, ruby, lua, zig, java, erlang, golang, js and SASL. also supports a threshold variants based on 2hashdh and 3hashtdh","archived":false,"fork":false,"pushed_at":"2025-03-01T23:54:05.000Z","size":4585,"stargazers_count":73,"open_issues_count":3,"forks_count":11,"subscribers_count":8,"default_branch":"master","last_synced_at":"2025-03-28T23:36:24.496Z","etag":null,"topics":["ake","authenticated-key-exchange","erlang","go","golang","ietf-cfrg","java","javascript","js","libsodium","lua","opaque","password","password-ake","php","python","ruby","sasl","sasl-mech","zig"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"lgpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/stef.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,"governance":null,"roadmap":null,"authors":"AUTHORS","dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-11-15T19:29:07.000Z","updated_at":"2025-02-25T15:38:11.000Z","dependencies_parsed_at":"2024-01-09T16:55:40.322Z","dependency_job_id":"4a2e7e45-f6a4-449f-8396-c826bd1c82e0","html_url":"https://github.com/stef/libopaque","commit_stats":{"total_commits":674,"total_committers":11,"mean_commits":61.27272727272727,"dds":"0.20474777448071213","last_synced_commit":"967041f542e940b53064d181c866fc79a76ed3c0"},"previous_names":[],"tags_count":11,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stef%2Flibopaque","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stef%2Flibopaque/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stef%2Flibopaque/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stef%2Flibopaque/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/stef","download_url":"https://codeload.github.com/stef/libopaque/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247271530,"owners_count":20911587,"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":["ake","authenticated-key-exchange","erlang","go","golang","ietf-cfrg","java","javascript","js","libsodium","lua","opaque","password","password-ake","php","python","ruby","sasl","sasl-mech","zig"],"created_at":"2024-09-24T14:20:56.327Z","updated_at":"2025-04-05T01:07:37.894Z","avatar_url":"https://github.com/stef.png","language":"C","readme":"# libopaque\n\nThis library implements the OPAQUE protocol as proposed in the IRTF\nCFRG draft at https://github.com/cfrg/draft-irtf-cfrg-opaque.\n\nIt comes with bindings for js, php7, ruby, java, erlang, lua, python, go and\nSASL.  There are also a 3rd party bindings for:\n - [dart](https://github.com/tibotix/opaque-dart)\n - rust [libopaque-sys](https://github.com/dnet/libopaque-sys) + [opaqueoxide](https://github.com/dnet/opaqueoxide/)\n\nSome more information about OPAQUE can be found in a series of blogposts:\n\n - [OPAQUE](https://www.ctrlc.hu/~stef/blog/posts/opaque.html)\n - [Why and how to use OPAQUE for user authentication](https://www.ctrlc.hu/~stef/blog/posts/Why_and_how_to_use_OPAQUE_for_user_authentication.html)\n - [opaque demo](https://www.ctrlc.hu/~stef/blog/posts/opaque_demo.html)\n\nThere is a [live demo](https://ctrlc.hu/opaque/) between a\npython/flask backend and a js/html frontend.\n\n## Dependencies\n\nlibopaque depends on libsodium\u003csup\u003e[1]\u003c/sup\u003e and on liboprf\u003csup\u003e[2]\u003c/sup\u003e\n\n[1]: https://github.com/jedisct1/libsodium\n[2]: https://github.com/stef/liboprf/\n\nBoth must be installed to use libopaque.\n\n## The OPAQUE Protocol\n\nThe OPAQUE protocol is an asymmetric password-authenticated\nkey-exchange. Essentially it allows a client to establish a shared\nsecret with a server based on only having a password. The client\ndoesn't need to store any state. The protocol has two phases:\n\n  - In the initialization phase a client registers with the server.\n  - In the AKE phase the client and server establish a shared secret.\n\nThe initialization only needs to be executed once, the key-exchange\ncan be executed as many times as necessary.\n\nThe following sections provide an abstract overview of the various\nsteps and their inputs and outputs, this is to provide an\nunderstanding of the protocol. The various language bindings have -\nlanguage-specific - slightly different APIs in the way the\ninput/output parameters are provided to the functions, see details in\nthe READMEs of the bindings sub-directories.\n\n### Initialization\n\nThe original paper and the IRTF CFRG draft differ, in the original\npaper a one-step registration is specified which allows the server\nduring initialization to inspect the password of the client in\ncleartext. This allows the server to enforce password sanity rules\n(e.g. not being listed in hacked user databases), however this also\nimplies that the client has to trust the server with this\npassword. The IRTF CFRG draft doesn't specify this registration,\ninstead it specifies a four-step protocol which results in exactly the\nsame result being stored on the server, without the client ever\nexposing the password to the server.\n\n#### One-step registration revealing password to server\n\nBefore calling the registration function the server should check the\nstrength of the password by obeying [NIST SP 800-63-3b](https://pages.nist.gov/800-63-3/sp800-63b.html#memsecret)) and if insufficient reject the registration.\n\nThe registration function takes the following parameters:\n\n - the client password\n - the optional long-term server private key skS\n - the IDs\n\nThe result of the registration is a record that the server should\nstore to be provided to the client in the key-exchange\nphase. Additionally an `export_key` is also generated which can be used\nto encrypt additional data that can be decrypted by the client in the\nkey-exchange phase. Where and how this additional `export_key` encrypted\ndata is stored and how it is retrieved by the client is out of scope\nof the protocol, for example this could be used to store additional\nkeys, personal data, or other sensitive client state.\n\n#### Password Privacy Preserving registration\n\nThis registration is a four step protocol which results in exactly the\nsame outcome as the one-step variant, without the server learning the\nclient password. It is recommended to have the client do a password\nstrength according to NIST SP 800-63-3b check before engaging in the\nfollowing protocol.\n\nThe following steps are executed, starting with the client:\n\n 1. client: sec, req = CreateRegistrationRequest(pwd)\n\nThe outputs in the first step are\n\n - a sensitive client context `sec` that is needed in step 3, this should\n   be kept secret as it also contains the plaintext password.\n - and request `req` that should be sent to the server, this request\n   does not need to be encrypted (it is already).\n\n 2. server: ssec, resp = CreateRegistrationResponse(req, skS)\n\nIn the second step the server takes the request and an optional\nlong-term server private key skS. In case no skS is supplied a\nuser-specific long-term server keypair is generated. The output of this step is:\n\n - a sensitive server context `ssec`, which must be kept secret and secure\n   until step 4 of this registration protocol.\n - a response, which needs to be sent back to the client, this\n   response does not need to be encrypted (it is already).\n\n 3. client: recU, export_key = FinalizeRequest(sec, resp, ids)\n\nIn the third step the client takes its context from step 1, the\nservers response from step 2, and the IDs of the server and client to\nassemble a record stub `recU` and an `export_key`. In case the client\nwishes to (and the server supports it) to encrypt and store additional\ndata at the server, it uses the `export_key` to encrypt it and sends\nit over to the server together with the record stub. The record stub\nmight or might not be needed to be encrypted, depending on the OPAQUE\nenvelope configuration.\n\n 4. server: rec = StoreUserRecord(ssec, recU, rec)\n\nIn the last - fourth - step of the registration protocol, the server\nreceives the record stub `recU` from the client step 3, it's own\nsensitive context `ssec` from step 2. These parameters are used to\ncomplete the record stub into a full record `rec`, which then the\nserver must store for later retrieval.\n\n### The key-exchange\n\nThe key-exchange is a three-step protocol with an optional fourth step\nfor explicit client authentication:\n\n  1. client: sec, req = CreateCredentialRequest(pwd)\n\nThe client initiates a key-exchange taking the password as input and\noutputting a sensitive client context `sec` which should be kept\nsecret until step 3 of this protocol. This step also produces a\nrequest `req` - which doesn't need to be encrypted (it is already) -\nto be passed to the server executing step 2:\n\n  2. server: resp, sk, ssec = CreateCredentialResponse(req, rec, ids, context)\n\nThe server receives a request from the client, retrieves record\nbelonging to the client, the IDs of itself and the client, and\na context string. Based on these inputs the server produces:\n\n - a response `resp` which needs to be sent to client,\n - its own copy of the shared key produced by the key-exchange, and\n - a sensitive context `ssec` which it needs to protect until the optional step 4.\n\n  3. client: sk, authU, export_key, ids = RecoverCredentials(resp, sec, context, ids)\n\nThe client receives the servers response `resp`, and\n - takes its own sensitive context `sec` from step 1.,\n - in case the envelope configuration has set the servers public key\n   set to not-packaged the servers public key,\n - a context string,\n - the ids of the server and client.\nProcessing all these inputs results in:\n - the shared secret key produced by the key exchange, which must be\n   the same as what the server has,\n - an authentication token `authU` which can be sent to the server in\n   case the optional fourth step of the protocol is needed to\n   explicitly authenticate the client to the server.\n - and finally the client also computes the `export_key` which was\n   used to encrypt additional data during the registration phase.\n\n  4. optionally server: UserAuth(ssec, authU)\n\nThis step is not needed in case the shared key is used for example to\nset up an encrypted channel between the server and client. Otherwise\nthe `authU` token is sent to the server, which using its previously\nstored sensitive context `ssec` verifies that the client has indeed\ncomputed the same shared secret as a result of the key-exchange and\nthus explicitly authenticating the client.\n\n## Installing\n\nInstall `libsodium-dev` and `pkgconf` using your operating system's package\nmanager.\n\nBuilding everything should (hopefully) be quite simple afterwards:\n\n```\ngit submodule update --init --recursive --remote\ncd src\nmake\n```\n\n## OPAQUE API\n\nThe API is described in the header file:\n[`src/opaque.h`](https://github.com/stef/libopaque/blob/master/src/opaque.h).\n\nThe library implements the OPAQUE protocol with the following deviations from\nthe original paper:\n\n0. It does not implement any persistence/lookup functionality.\n1. Instead of HMQV (which is patented), it implements a Triple-DH.\n2. It implements \"user iterated hashing\" from page 29 of the paper.\n3. It additionally implements a variant where U secrets never hit S\n   unprotected.\n\nFor more information, see the\n[IRTF CFRG specification](https://github.com/cfrg/draft-irtf-cfrg-opaque/blob/master/draft-irtf-cfrg-opaque.md),\nthe [original paper](https://github.com/stef/libopaque/blob/master/doc/opaque.pdf)\nand the\n[`src/tests/opaque-test.c`](https://github.com/stef/libopaque/blob/master/src/tests/opaque-test.c)\nexample file.\n\n## OPAQUE Parameters\n\nCurrently all parameters are hardcoded, but there is nothing stopping you from\nsetting stronger values for the password hash.\n\n### The Curve\n\nThis OPAQUE implementation is based on libsodium's ristretto25519 curve. This\nmeans currently all keys are 32 bytes long.\n\n### Other Crypto Building Blocks\n\nThis OPAQUE implementation relies on libsodium as a dependency to provide all\nother cryptographic primitives:\n\n- `crypto_pwhash`\u003csup\u003e[3]\u003c/sup\u003e uses the Argon2 function with\n  `crypto_pwhash_OPSLIMIT_INTERACTIVE` and\n  `crypto_pwhash_MEMLIMIT_INTERACTIVE` as security parameters.\n- `randombytes` attempts to use the cryptographic random source of\n  the underlying operating system\u003csup\u003e[4]\u003c/sup\u003e.\n\n[3]: https://doc.libsodium.org/password_hashing/default_phf\n[4]: https://download.libsodium.org/doc/generating_random_data\n\n## Debugging\n\nTo aid in debugging and testing, there are two macros available:\n\n| Macro      | Description                                       |\n| ---------- | ------------------------------------------------- |\n| `TRACE`    | outputs extra information to stderr for debugging |\n| `NORANDOM` | removes randomness for deterministic results      |\n\nTo use these macros, specify the `DEFINES` Makefile variable when calling\n`make`:\n\n```\n$ make DEFINES='-DTRACE -DNORANDOM' clean libopaque.so tests\n$ LD_LIBRARY_PATH=. ./tests/opaque-test\n```\n\nAs a shortcut, calling `make debug` also sets these variables. This code block\nis equivalent to the one above:\n\n```\n$ make clean debug\n$ LD_LIBRARY_PATH=. ./tests/opaque-test\n```\n\n## Credits\n\nThis project was funded through the NGI0 PET Fund, a fund established\nby NLnet with financial support from the European Commission's Next\nGeneration Internet programme, under the aegis of DG Communications\nNetworks, Content and Technology under grant agreement No 825310.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstef%2Flibopaque","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fstef%2Flibopaque","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstef%2Flibopaque/lists"}