{"id":14156503,"url":"https://github.com/borgoat/farmfa","last_synced_at":"2026-01-12T00:52:30.052Z","repository":{"id":38885814,"uuid":"253859043","full_name":"borgoat/farmfa","owner":"borgoat","description":"TOTP MFA for teams: Shamir's Secret Sharing and zero trust OTP generation","archived":false,"fork":false,"pushed_at":"2024-07-18T16:14:12.000Z","size":1763,"stargazers_count":28,"open_issues_count":0,"forks_count":3,"subscribers_count":1,"default_branch":"develop","last_synced_at":"2025-07-10T18:23:28.559Z","etag":null,"topics":["hotp","least-privilege","mfa","otp","otp-generator","shamir-secret-sharing","totp","zero-trust"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/borgoat.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":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-04-07T17:02:06.000Z","updated_at":"2025-02-11T10:21:34.000Z","dependencies_parsed_at":"2024-08-17T08:17:54.275Z","dependency_job_id":null,"html_url":"https://github.com/borgoat/farmfa","commit_stats":null,"previous_names":["giorgioazzinnaro/farmfa"],"tags_count":6,"template":false,"template_full_name":null,"purl":"pkg:github/borgoat/farmfa","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/borgoat%2Ffarmfa","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/borgoat%2Ffarmfa/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/borgoat%2Ffarmfa/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/borgoat%2Ffarmfa/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/borgoat","download_url":"https://codeload.github.com/borgoat/farmfa/tar.gz/refs/heads/develop","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/borgoat%2Ffarmfa/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":266580304,"owners_count":23951195,"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","status":"online","status_checked_at":"2025-07-22T02:00:09.085Z","response_time":66,"last_error":null,"robots_txt_status":null,"robots_txt_updated_at":null,"robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["hotp","least-privilege","mfa","otp","otp-generator","shamir-secret-sharing","totp","zero-trust"],"created_at":"2024-08-17T08:05:32.296Z","updated_at":"2026-01-12T00:52:29.970Z","avatar_url":"https://github.com/borgoat.png","language":"Go","funding_links":[],"categories":["others"],"sub_categories":[],"readme":"# farMFA\n\n\u003e Secure, distributed Multi-Factor Authentication system based on TOTP and Shamir's Secret Sharing.\n\n![License](https://img.shields.io/github/license/borgoat/farmfa?color=blue\u0026style=flat-square)  \n![Go Report Card](https://goreportcard.com/badge/github.com/borgoat/farmfa)  \n![PkgGoDev](https://pkg.go.dev/badge/github.com/borgoat/farmfa)\n\n### 🚧 DISCLAIMER 🚧\n\n**WIP! farMFA is still in development and may not be suitable for production use.**\n\n![under contruction GIF from the 90s](docs/wip.gif)\n\nThe user experience is terrible, the code is not tested, and the documentation is incomplete.\n\nIt's here for [Umarells](https://en.wikipedia.org/wiki/Umarell) as myself, who like to take a look at half-baked projects.\n\nI believe you can trust the decryption to work in the future, as it's based on the [age](https://filippo.io/age) encryption tool.\nSo it's unlikely that your secrets will be lost or leaked.\n\nYou may also trust the Shamir's Secret Sharing implementation, as it's coming from the HashiCorp [Vault](https://github.com/hashicorp/vault) project.\n\nHowever, if you do feel like using this tool right now, please keep a copy of the code and the encrypted secrets in a safe place.\n\n\n## 💡 Concept\n\n![a desk with a six-digit combination lock on it, a clock, and pieces of papers with random ASCII strings on them](./docs/banner.png)\n\nMulti-Factor Authentication (MFA) is often implemented using the TOTP standard ([RFC6238](https://www.rfc-editor.org/info/rfc6238)) from OATH.\n\n1. The authentication server generates a secret key, stores it, and shows it to the user as a QR code or a Base32 string. The user stores it in a mobile app or password manager.\n2. Upon login, the user inputs a One-Time Password (OTP). The authenticator app or password manager generates this password by applying the TOTP algorithm to the secret key and the current time.\n3. The authentication server performs the same algorithm on the secret key and current time. If the output matches the user’s TOTP, the authentication is successful.\n\nThe generated One-Time Password may only be used once, or within a certain timeframe, depending on the server implementation.\n\nfarMFA is designed for shared environments where access to certain accounts should be restricted to very special occasions, such as accessing the root user of an AWS account. The goal is to restrict access so that multiple individuals are needed to grant authorization.\n\nFirst, we apply the *Shamir’s Secret Sharing* scheme ([Shamir 1979](https://doi.org/10.1145/359168.359176)) to the original TOTP secret key. For instance, at least 3 out of 5 holders must combine their shares to reconstruct the secret.\n\nAdditionally, farMFA implements a workflow to reassemble the TOTP secret on a server, allowing users to access only the generated TOTP code without risking accidental leaks of the secret.\n\n\n## 🚀 Getting Started\n\nThe two main workflows are:\n\n1. Getting the TOTP secret, splitting it, and sharing it with multiple parties (players). This is done locally.\n2. Combining the shares (Tocs) and generating the TOTP. This is done by the server/oracle.\n\n### Split TOTP Secret and Share\n\n![a diagram of the initial phase where TOTP secrets are split](docs/split.png)\n\nDuring this phase, farMFA encrypts the Tocs based on the intended recipient (player). The current encryption strategy uses [age](https://filippo.io/age).\n\nEach player generates their age keypair via [age-keygen](https://github.com/FiloSottile/age#readme):\n\n```shell\nage-keygen -o player_1.txt\n\n# And if you're now testing by yourself, generate a few more keys\nage-keygen -o player_2.txt\nage-keygen -o player_3.txt\n```\n\nPlayers then share their public key with the dealer.\n\nThe dealer starts the process, usually providing their own age public key and keeping one Toc for themselves:\n\n\n```shell\nfarmfa dealer \\\n  --totp-secret HXDMVJECJJWSRB3HWIZR4IFUGFTMXBOZ \\\n  -p player_1=age1ct885ya9458q63ea6fdl42ajl3rpkasj45c5hkkp5ccpf7c80cssk688fr \\\n  -p player_2=age1emv0n3j90658ke68ktrl7ne9w5gqwrcuetww5ac5rhdkeg638ykqg7uuhd \\\n  -p player_3=age1rl2ranstxv2dd8pmamvwukz35zrcv9p3knthp0kal3q47gyyea5qk0cl4q\n```\n\nThis generates encrypted Tocs, one per player. Each player then decrypts and inspects their Toc using the age CLI:\n\n```shell\nage -i player_1.txt --decrypt\n[paste the encrypted Toc - Ctrl+D]\n\n{\n    \"group_id\": \"7GCUCI2Y\",\n    \"group_size\": 3,\n    \"group_threshold\": 3,\n    \"note\":\"\",\n    \"share\":\"C2iCgb3pRfxPJw2a7od8p4ShkhrDWAm/Dt6ioQNAVFPZ\",\n    \"toc_id\":\"5oaAUX9b6aBE\"\n}\n```\n\nPlayers must store their Toc securely.\n\n### Generate a TOTP\n\n![a diagram showing the TOTP code generation phase](docs/generate.png)\n\nWhen a user wants to log in, they start a session. The user initiating the login is called the applicant.\n\n```shell\n# For testing purposes, we'll now start the server locally - in production, this should be a remote server\nfarmfa server \u0026\n\nhttp --body POST localhost:8080/sessions toc_zero:='{\"group_id\":\"J7UHQPZK\",\"group_size\":5,\"group_threshold\":2,\"share\":\"5Ovpu-PKEeYXx5ebiQhzU_AT0Z79POf8GGkskDp3its=urkBkVXr-pYjIvTt1ch2YJILCScAoRquLoX_VBxxps4=\",\"toc_id\":\"TFW52GAK\"}'\n{\n    \"complete\": false,\n    \"created_at\": \"2021-02-24T18:05:53.507396809+01:00\",\n    \"id\": \"V5K6QD4XUFLRGCZH\",\n    \"kek\": \"MIotBtYOWrXnQCj6o9rSNIkNeRfIPhNLjEdQtJDDemPRJcKUbme+iq5K2Hc6Ypil6Loi/K9rnN/YrJiKDT/tPi8kFq2WuAY8zl8=\",\n    \"tek\": \"age1cl5ndmdsq09vs09awlpt8nd4cdu6fpl33lpyyuv75syknqalkpdszwnwyc\",\n    \"toc_group_id\": \"J7UHQPZK\",\n    \"tocs_in_group\": 5,\n    \"tocs_provided\": 1,\n    \"tocs_threshold\": 2\n}\n```\n\nThe oracle returns:\n\n* A session ID.\n* A Toc Encryption Key (TEK) - a public key to encrypt individual Tocs.\n* A Key Encryption Key (KEK) - to decrypt the private part of the TEK.\n\nThe applicant shares the TEK and session ID with team members holding the other Tocs. These team members, who can authorize the applicant, are called constituents.\n\nConstituents encrypt and armor their Toc with TEK using age:\n\n```shell\nexport ENCTOC=$(echo '{\"group_id\":\"J7UHQPZK\",\"group_size\":5,\"group_threshold\":2,\"share\":\"zxRrozuUaCMgn_u6ajZStlV7RKwhp0keT9aQoXAEruI=nfx2CPJfKiFM32zLmtxHjV94OlZOgBevV1Whrx-lslU=\",\"toc_id\":\"K5FSSJSV\"}' | age -r age1cl5ndmdsq09vs09awlpt8nd4cdu6fpl33lpyyuv75syknqalkpdszwnwyc -a)\n```\n\nConstituents upload the encrypted Toc to the oracle, associating it with the existing session:\n\n```shell\nhttp POST localhost:8080/sessions/V5K6QD4XUFLRGCZH/tocs encrypted_toc=\"$ENCTOC\"\nHTTP/1.1 200 OK\n```\n\nOnce the oracle has enough Tocs, the applicant may query the oracle. The applicant provides the KEK to let the oracle decrypt the Tocs and generate the TOTP:\n\n```shell\nhttp --body POST localhost:8080/sessions/V5K6QD4XUFLRGCZH/totp kek=\"MIotBtYOWrXnQCj6o9rSNIkNeRfIPhNLjEdQtJDDemPRJcKUbme+iq5K2Hc6Ypil6Loi/K9rnN/YrJiKDT/tPi8kFq2WuAY8zl8=\"\n{\n    \"totp\": \"824588\"\n}\n```\n\n## 📖 References\n- [RFC6238](https://www.rfc-editor.org/info/rfc6238): M’Raihi, D., Machani, S., Pei, M., and J. Rydell, \"TOTP: Time-Based One-Time Password Algorithm\", RFC 6238, DOI 10.17487/RFC6238, May 2011.\n- [Shamir's Secret Sharing](https://doi.org/10.1145/359168.359176): Adi Shamir. 1979. \"How to share a secret\". Commun. ACM 22, 11 (Nov. 1979), 612–613.\n\n## 🔠 Glossary\n- **Secret:** A TOTP is a hash generated from a secret. This secret is usually shown as a QR code and shared between the prover and verifier. In farMFA, the prover is distributed among recipients who share the key material and an oracle that generates the TOTP.\n- **Toc:** The \"pieces\" in which a TOTP secret gets split.\n- **Deal:** The workflow in which a dealer splits a secret into Tocs and shares them with multiple players.\n- **Dealer:** Creates Tocs from a secret and shares them with players.\n- **Player:** Individuals who receive one of the Tocs during the Tocs creation phase.\n- **Session:** The workflow in which an applicant requires combining Tocs to generate a TOTP.\n- **Applicant:** Initiates a session to request access to a TOTP.\n- **Constituent:** Individuals who join a session to authorize an applicant to generate a TOTP by reaching a quorum/threshold.\n- **Oracle:** The entity that reconstructs Tocs into TOTP secrets and generates one-time passwords. Also called the prover, as defined in [RFC6238](https://www.rfc-editor.org/info/rfc6238).\n- **Server:** Synonym for oracle in this context.\n- **TOTP:** As defined in [RFC6238](https://www.rfc-editor.org/info/rfc6238): \"an extension of the One-Time Password (OTP) algorithm to support the time-based moving factor\". Used by many applications as a second authentication factor.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fborgoat%2Ffarmfa","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fborgoat%2Ffarmfa","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fborgoat%2Ffarmfa/lists"}