{"id":13781409,"url":"https://github.com/remko/age-plugin-se","last_synced_at":"2025-12-28T00:54:25.597Z","repository":{"id":65235160,"uuid":"586972173","full_name":"remko/age-plugin-se","owner":"remko","description":"Age plugin for Apple's Secure Enclave","archived":false,"fork":false,"pushed_at":"2024-09-22T07:27:54.000Z","size":444,"stargazers_count":120,"open_issues_count":1,"forks_count":4,"subscribers_count":8,"default_branch":"main","last_synced_at":"2024-11-01T09:20:51.047Z","etag":null,"topics":["age-encryption","cryptokit","encryption","mac","secure-enclave"],"latest_commit_sha":null,"homepage":"","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/remko.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-01-09T17:00:07.000Z","updated_at":"2024-10-30T18:42:58.000Z","dependencies_parsed_at":"2023-01-15T18:45:32.962Z","dependency_job_id":"6b04a0f3-7603-40ef-879d-2e69a7a5a448","html_url":"https://github.com/remko/age-plugin-se","commit_stats":null,"previous_names":[],"tags_count":10,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/remko%2Fage-plugin-se","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/remko%2Fage-plugin-se/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/remko%2Fage-plugin-se/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/remko%2Fage-plugin-se/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/remko","download_url":"https://codeload.github.com/remko/age-plugin-se/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244945617,"owners_count":20536297,"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":["age-encryption","cryptokit","encryption","mac","secure-enclave"],"created_at":"2024-08-03T18:01:25.726Z","updated_at":"2025-12-28T00:54:25.586Z","avatar_url":"https://github.com/remko.png","language":"Swift","funding_links":[],"categories":["Swift","Plugins"],"sub_categories":[],"readme":"# Age plugin for Apple's Secure Enclave\n\n[![Build](https://github.com/remko/age-plugin-se/actions/workflows/build-main.yml/badge.svg)](https://github.com/remko/age-plugin-se/actions/workflows/build-main.yml)\n[![Coverage](https://remko.github.io/age-plugin-se/ci/coverage.svg)](https://remko.github.io/age-plugin-se/ci/coverage.html)\n\n`age-plugin-se` is a plugin for [age](https://age-encryption.org),\nenabling encryption using [Apple's Secure\nEnclave](https://support.apple.com/en-gb/guide/security/sec59b0b31ff/web).\n\n    $ age-plugin-se keygen --access-control=any-biometry -o key.txt\n    Public key: age1se1qgg72x2qfk9wg3wh0qg9u0v7l5dkq4jx69fv80p6wdus3ftg6flwg5dz2dp\n    $ tar cvz ~/data | age -r age1se1qgg72x2qfk9wg3wh0qg9u0v7l5dkq4jx69fv80p6wdus3ftg6flwg5dz2dp -o data.tar.gz.age\n    $ age --decrypt -i key.txt -o data.tar.gz data.tar.gz.age\n\n\u003cdiv align=\"center\"\u003e\n\u003cimg src=\"https://raw.githubusercontent.com/remko/age-plugin-se/main/Documentation/img/screenshot-biometry.png\" alt=\"Biometry prompt\" width=350/\u003e\n\u003c/div\u003e\n\nBesides direct usage with age as above, you can use it with any tool\nthat uses age in the backend. For example, you can store your passwords\nwith [passage](https://github.com/FiloSottile/passage), and conveniently access\nthem with Touch ID.\n\n\n## Requirements\n\nTo generate identities (private keys) and decrypt encrypted files, you need a Mac\nrunning macOS 14 (Sonoma) with a Secure Enclave processor.\n\nFor encrypting files, you need macOS 14 (Sonoma), Linux, or Windows. A\nSecure Enclave processor is not necessary.\n\n## Installation\n\n### Homebrew\n\n    brew install age-plugin-se\n\n### Pre-built binary\n\n1.  Download a binary from [the releases\n    page](https://github.com/remko/age-plugin-se/releases)\n2.  Extract the package\n3.  (Windows only) Download and install\n    [Swift](https://www.swift.org/download/)\n4.  (macOS only) Trust `age-plugin-se` once by Control-clicking the file\n    in Finder, choosing *Open*, and confirming trust\n5.  Move `age-plugin-se` to somewhere on your executable path (e.g.\n    `/usr/local/bin`)\n\n### Alpine Linux\n\nFor Alpine Linux, there are also pre-built `.apk` packages available on [the releases page](https://github.com/remko/age-plugin-se/releases).\n\nTo instal them:\n\n1. Download the [package signing key](https://raw.githubusercontent.com/remko/age-plugin-se/main/Scripts/alpine/r%40mko.re-66596f64.rsa.pub), and install it in `/etc/apk/keys`.\n\n        doas wget -P /etc/apk/keys https://raw.githubusercontent.com/remko/age-plugin-se/main/Scripts/alpine/r@mko.re-66596f64.rsa.pub\n\n2. Download the binary (and optionally the `-doc`) `.apk` file from [the releases\npage](https://github.com/remko/age-plugin-se/releases).\n3. Install the downloaded package(s):\n    \n        doas apk add ./age-plugin-se-0.1.3-r0-x86_64.apk\n        doas apk add ./age-plugin-se-doc-0.1.3-r0-noarch.apk\n\n\n### Building from source\n\n1.  (non-macOS only) Download and install\n    [Swift](https://www.swift.org/download/)\n\n2.  Clone [the source code\n    repository](https://github.com/remko/age-plugin-se) or get a source\n    package from [the releases\n    page](https://github.com/remko/age-plugin-se/releases)\n\n3.  Build the plugin\n\n        make\n\n4.  Install the plugin\n\n        sudo make install PREFIX=/usr/local\n\n\n## Guide\n\nIn order to encrypt data using the Secure Enclave of your machine, you need to\ngenerate a private key that is bound to the Secure Enclave. You can generate\nsuch a private key for age using the `age-plugin-se keygen` command. When\ncreating such a key, you also specify which type of protection you want, which\nis a combination of biometry (e.g. Touch ID) and passcode:\n\n```\n$ age-plugin-se keygen --access-control=any-biometry -o key.txt\nPublic key: age1se1qfn44rsw0xvmez3pky46nghmnd5up0jpj97nd39zptlh83a0nja6skde3ak\n```\n\nThe **public** key (recipient) is printed on standard output. This is the key you\nneed to *encrypt* data, and can be freely distributed.\n\nThe **private** key is stored in `key.txt`:\n\n```\n# created: 2023-07-08T19:00:19Z\n# access control: any biometry\n# public key: age1se1qfn44rsw0xvmez3pky46nghmnd5up0jpj97nd39zptlh83a0nja6skde3ak\nAGE-PLUGIN-SE-1QJPQZLE3SGQHKVYP75X6KYPZPQ3N44RSW0XVMEZ3QYUNTXXQ7UVQTPSPKY6TYQSZDNVLMZYCYSRQRWP\n```\n\nThis is the key you need to be able to *decrypt* the data encrypted for the public\nkey. You have to keep this key private. \n\n\u003e ℹ️ The private key is bound to the secure enclave of your machine, so it cannot \n\u003e be transferred to another machine. This also means that you should take the \n\u003e necessary precautions, and make sure you also encrypt any long-term data to an\n\u003e alternate backup key.\n\nUsing the public key, you can now encrypt data from any machine (even machines\nwithout a Secure Enclave, or even machines running Linux or Windows):\n\n```\n$ tar cvz ~/data | age -r age1se1qfn44rsw0xvmez3pky46nghmnd5up0jpj97nd39zptlh83a0nja6skde3ak -o data.tar.gz.age\n```\n\nage will automatically pick up the plugin from your execution path, and detect that it\nneeds to use this plugin for encrypting to the specified recipient.\n\nTo decrypt the encrypted file, pass the private key as an identity to age \n(running on the machine with the corresponding Secure Enclave for the private key):\n\n```\n$ age --decrypt -i key.txt -o data.tar.gz data.tar.gz.age\n```\n\nThe decrypt operation will now require Touch ID to use the \nSecure Enclave to decrypt it:\n\n\u003cdiv align=\"center\"\u003e\n\u003cimg src=\"https://raw.githubusercontent.com/remko/age-plugin-se/main/Documentation/img/screenshot-biometry.png\" alt=\"Biometry prompt\" width=350/\u003e\n\u003c/div\u003e\n\n\n### Using `age-plugin-se` with passage\n\n[Passage](https://github.com/FiloSottile/passage) is a simple, file-based password manager that\nuses age for encrypting and decrypting secrets. Using `age-plugin-se` makes decrypting secrets\nin passage simple and convenient through Touch ID.\n\nTo use `age-plugin-se` with passage, start by creating a new private key:\n\n```\n$ age-plugin-se keygen -o $HOME/.passage/identities\nPublic key: age1se1qgg72x2qfk9wg3wh0qg9u0v7l5dkq4jx69fv80p6wdus3ftg6flwg5dz2dp\n```\n\nBecause this key is bound to your device, and your device may break or get lost, \nit's a good idea to also generate a regular age backup key (for example, a \npassword-protected one):\n\n```\n$ age-keygen | age -p \u003e $HOME/.passage/identities.backup\nPublic key: age1szwgh3vau33786pdp77yl2rx9hdl9p9v6t5aynzv9jepv2lqys6q24pcc4\n```\n\nConfigure your store to encrypt all entries to both keys:\n\n```\n$ cat \u003c\u003c EOF \u003e $HOME/.passage/store/.age-recipients\n# Backup key\nage1szwgh3vau33786pdp77yl2rx9hdl9p9v6t5aynzv9jepv2lqys6q24pcc4\n\n# Secure Enclave key\nage1se1qgg72x2qfk9wg3wh0qg9u0v7l5dkq4jx69fv80p6wdus3ftg6flwg5dz2dp\nEOF\n```\n\nDecrypting your passage entries will now ask for Touch ID.\n\nIf you should ever lose access to the device bound to your private key:\n\n1. Generate a new `age-plugin-se` key:\n\n   ```\n   $ age-plugin-se keygen -o $HOME/.passage/identities.new\n   Public key: age1se1qfs057x89v9fs2g2thcw3xlg0729q63ntrgwc9t29t54q5l93de2cq6t02s\n   ```\n\n2. Add the new public key to `.age-identities`:\n\n   ```\n   echo age1se1qfs057x89v9fs2g2thcw3xlg0729q63ntrgwc9t29t54q5l93de2cq6t02s \u003e\u003e \\\n     $HOME/.passage/store/.age-recipients\n   ```\n    \n3. Decrypt your backup key (to speed up re-encryption), and temporarily use it as your \n   identity for decrypting entries:\n\n   ```\n   age -d $HOME/.passage/identities.backup \u003e $HOME/.passage/identities\n   ```\n\n4. Re-encrypt your passage store:\n\n   ```\n   passage reencrypt\n   ```\n\n5. Use your new key for decrypting entries in the future:\n\n   ```\n   mv $HOME/.passage/identities.new $HOME/.passage/identities\n   ```\n\n\n### Converting `age-plugin-se` recipients to `age-plugin-tag` recipients\n\n`age-plugin-se` can generate two types of recipients (using the\n`--recipient-type` option): `se` (starting with `age1se1...`) and `tag`\n(starting with `age1tag1...`). `se` recipients require the `age-plugin-se`\nplugin to be installed on the system where encryption is performed, whereas\n`tag` recipients can be used natively by age (since age v1.3.0). Besides\navoiding the need for the plugin, `tag` recipients also obfuscate the fact\nthat the key is protected by Apple Secure Enclave.\n\nIf you have an existing `se` recipient, and you also have the corresponding\nidentity, you can retrieve a `tag` recipient for the same key using the\n`age-plugin-se recipients` command:\n\n```\n$ age-plugin-se recipients -i key.txt --recipient-type tag\nage1tag1qgg72x2qfk9wg3wh0qg9u0v7l5dkq4jx69fv80p6wdus3ftg6flwgjgtev8\n```\n\nIf you don't have the identity, you can use the [`ConvertBech32HRP.swift`](https://raw.githubusercontent.com/remko/age-plugin-se/main/Scripts/ConvertBech32HRP.swift)\nscript in this repository. \n\nFor example, to convert the recipient from earlier to a `age-plugin-tag` recipient:\n\n```\n$ ./Scripts/ConvertBech32HRP.swift \\\n      age1se1qgg72x2qfk9wg3wh0qg9u0v7l5dkq4jx69fv80p6wdus3ftg6flwg5dz2dp \\\n      age1tag\nage1tag1qgg72x2qfk9wg3wh0qg9u0v7l5dkq4jx69fv80p6wdus3ftg6flwgc25f05\n```\n\nThis key can now be used to encrypt data for the same private key:\n```\n$ tar cvz ~/data | age -r age1tag1qgg72x2qfk9wg3wh0qg9u0v7l5dkq4jx69fv80p6wdus3ftg6flwgc25f05\n$ age --decrypt -i key.txt data.tar.gz.age \u003e data.tar.gz\n```\n\nNote that, if you have a system without `age-plugin-se` or a recent age version, but you\ndo have `age-plugin-yubikey` installed, you can also convert the `se` recipient to \n`age1yubikey`, and use that to encrypt data for the same private key.\n\n\n## Usage\n\n    age-plugin-se keygen [--pq] [-o OUTPUT] [--access-control ACCESS_CONTROL] [--recipient-type RECIPIENT_TYPE]\n    age-plugin-se recipients [--pq] [-o OUTPUT] [-i INPUT] [--recipient-type RECIPIENT_TYPE]\n\n    The `keygen` subcommand generates a new private key bound to the current \n    Secure Enclave, with the given access controls, and outputs it to OUTPUT \n    or standard output.\n\n    The `recipients` subcommand reads an identity file from INPUT or standard \n    input, and outputs the corresponding recipient(s) to OUTPUT or to standard \n    output.\n\n\n    Options:\n      --access-control ACCESS_CONTROL   Access control for using the generated key.\n                                    \n            Supported values: none, passcode, \n              any-biometry, any-biometry-and-passcode, any-biometry-or-passcode,\n              current-biometry, current-biometry-and-passcode\n            Default: any-biometry-or-passcode.             \n\n            When using current biometry, adding or removing a fingerprint stops the\n            key from working. Removing an added fingerprint enables the key again. \n\n      -o, --output OUTPUT               Write the result to the file at path OUTPUT\n\n      -i, --input INPUT                 Read data from the file at path INPUT\n\n      --pq                              Generate post-quantum keys\n\n      --recipient-type RECIPIENT_TYPE   Recipient type to generate.\n\n                                        `tag` recipients use built-in support in\n                                        age (\u003e=v1.3.0), and don't require this plug-in to\n                                        be installed to encrypt.\n\n                                        Post-quantum keys (generated with `--pq`) always\n                                        use the `tag` recipient type.\n\n                                        Supported values: se, tag.\n                                        Default: se.\n                                        The default will change to `tag` in future versions.\n\n## Development\n\nBuild the plugin\n\n    make\n\nMake sure `.build/debug/age-plugin-se` is in your execution path (or\nsoftlinked from a folder in your path), so `age` can find the plugin.\n\n### Tests\n\nTo run the unit tests:\n\n    make test\n\nTo get a coverage report of the unit tests:\n\n    make test COVERAGE=1\n\nAnnotated coverage source code can be found in `.build/coverage.html`.\n\nTo run a smoke test:\n\n    make smoke-test\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fremko%2Fage-plugin-se","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fremko%2Fage-plugin-se","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fremko%2Fage-plugin-se/lists"}