# dkekey
Make [DKE](https://dke.langsyn.com/) store keys on your own machine.
The dashboard makes store keys in your browser. `dkekey` makes the same keys
in a program you run yourself, for when you would rather not trust a page to
do it, or have no browser at all: a CI job, an agent, a server.
```
dkekey mint --store notes --label ci-reader --level read --email you@example.com
```
## What it sends, and what it does not
A store key is made here, from your machine's random source. To add it to a
store, `dkekey` opens the store with a key that already opens it, wraps the
store's data key under the new key, and sends the account service two things:
the new key's SHA-256 hash, and that wrap. The key itself is never sent. It is
written to standard output, or to the file you name, and nowhere else.
The key that opens the store is never sent either: only its hash, to fetch the
store's wrap for it, which is opened here. Your password is never sent: it
derives, here, the proof the account checks and the key your customer key is
kept under, as the dashboard does.
## Getting it
Releases are served, with this source and the signed digest list, at
.
Each release is a single binary for each of Linux, macOS and Windows, on amd64
and arm64. They need Linux 3.2 or later, macOS 12 or later, or Windows 10 or
later, and nothing else installed. With them come a `SHA256SUMS` file listing
their digests and two signatures over that list, made with LangSyn's two
asset-signing keys: `SHA256SUMS.sig` by the Ed25519 key, and
`SHA256SUMS.mldsa65.sig` by the ML-DSA-65 key, the signature scheme of FIPS 204,
which is designed to stay secure against a quantum computer. Their public halves
are served at and
, and the same
two keys sign the list of scripts the LangSyn sites serve. A download is ours
only when both signatures verify.
To check a download, with OpenSSL 3.5 or later (the first with ML-DSA) and the
public keys saved as `asset-signing-key.pub` and `asset-signing-key.mldsa65.pub`:
```
openssl base64 -d -A -in SHA256SUMS.sig -out SHA256SUMS.sig.bin
openssl pkeyutl -verify -pubin -inkey asset-signing-key.pub -rawin \
-in SHA256SUMS -sigfile SHA256SUMS.sig.bin
openssl base64 -d -A -in SHA256SUMS.mldsa65.sig -out SHA256SUMS.mldsa65.sig.bin
openssl pkeyutl -verify -pubin -inkey asset-signing-key.mldsa65.pub -rawin \
-in SHA256SUMS -sigfile SHA256SUMS.mldsa65.sig.bin
sha256sum -c --ignore-missing SHA256SUMS
```
Each `pkeyutl` line prints `Signature Verified Successfully`. With OpenSSL 3.0 to
3.4 the first one works and the second does not, because those versions have no
ML-DSA.
On macOS, use `shasum -a 256 -c` for the last line. The binaries carry no
Apple or Microsoft signature, so macOS and Windows warn the first time one is
run.
### Building it yourself
With Go 1.26 or later:
```
make test
make build
```
The release binaries are built with `make dist`, which builds every platform
with no C toolchain, no build paths, no build id and no version-control stamp.
With the same Go release, you get the same bytes, and can compare them with
`SHA256SUMS`. A release's binaries were built with the Go release
`go version dkekey` names.
## Signing in
Sign in one of two ways.
**With your password**, for a person at a terminal: `--email ADDRESS`. The
password is asked for on the terminal, with typing hidden, or read from
standard input with `--password-stdin`.
**With an account token**, for a program: make one in the dashboard, under
Account tokens, and give it to `dkekey` in a file with `--token-file FILE`, or
in the environment as `DKEKEY_TOKEN`. A token can only add keys to stores that
exist, and only up to the level it was made with. It is not a key: it opens no
store by itself.
A token or a key is never taken as a command-line argument, where other
programs on the machine could read it.
`dkekey` does not follow a redirect. Every request carries your token, your
session or, when signing in, your login proof, and following a redirect would
send it on to whatever address the redirect names. A redirect stops the
command instead, and says where it pointed. Version 0.1.0 followed them.
## Opening the store
A new key wraps the store's data key, so `dkekey` has to open the store first,
with a key that already opens it:
- signed in with your password and given nothing else, it opens your customer
key with your password, and the store with your customer key, as the
dashboard does;
- otherwise, give it a key with `--open-with FILE` (`-` reads standard input),
or in the environment as `DKEKEY_OPEN_KEY`: either one of the store's keys
(`dke_s_...`) or your customer key (`dke_c_...`).
## Levels
`--level` says what the new key may do:
| Level | The key may |
|---|---|
| `read` (the default) | answer questions, and change nothing |
| `read-add` | add facts, and change or delete none already recorded |
| `read-write` | add facts and revise them, and delete nothing |
| `read-write-delete` | add, revise and delete; what it deletes is gone for good |
A key opens one store. You can change its level or revoke it in the dashboard.
A file named with `--out` must not exist yet, so a key is never written over
another. On Linux and macOS it is readable by you alone. On Windows it takes
the access rules of the folder it is written in, so write it in a folder only
you can read, such as one under your user folder.
## Examples
A person, at a terminal:
```
dkekey mint --store notes --label laptop --level read-write --email you@example.com
```
A CI job with a token, opening the store with one of its keys, and saving the
new key to a file that must not exist yet:
```
DKEKEY_TOKEN=$(cat token) dkekey mint --store notes --label nightly \
--open-with notes.key --out nightly.key
```
## The key format
`dkekey version` names the format the keys it makes are in. If LangSyn moves to
a new format, the account service refuses to take a key made in the old one,
by name, and says to update `dkekey`, rather than taking a key that would not
work.
## Exit status
`0` the key was made; `1` it was not, and standard error says why; `2` the
command line was wrong.
## Licence
MIT. See `LICENSE`.