summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorJoey Hess <joeyh@joeyh.name>2017-01-22 09:28:53 -0400
committerJoey Hess <joeyh@joeyh.name>2017-01-22 09:28:53 -0400
commit13e2d75c713eecf0184d621922f3f8cca4a25933 (patch)
tree8ba1688dc0c693d50d596c5bf06dff480f002b05
parentb76c1bd252721547e6365f96d87fe496eab673e1 (diff)
downloadkeysafe-13e2d75c713eecf0184d621922f3f8cca4a25933.tar.gz
Keysafe has a new website, https://keysafe.branchable.com/
-rw-r--r--CHANGELOG1
-rw-r--r--TODO2
-rw-r--r--doc/details.mdwn365
-rw-r--r--doc/faq.mdwn88
-rw-r--r--doc/index.mdwn81
-rw-r--r--doc/news/version_0.20160927.mdwn20
-rw-r--r--doc/news/version_0.20161006.mdwn10
-rw-r--r--doc/news/version_0.20161007.mdwn9
-rw-r--r--doc/news/version_0.20161022.mdwn12
-rw-r--r--doc/news/version_0.20161107.mdwn14
-rw-r--r--doc/screenshots.mdwn14
-rw-r--r--doc/screenshots/0.pngbin0 -> 21991 bytes
-rw-r--r--doc/screenshots/1.pngbin0 -> 22953 bytes
-rw-r--r--doc/screenshots/2.pngbin0 -> 32345 bytes
-rw-r--r--doc/screenshots/3.pngbin0 -> 30236 bytes
-rw-r--r--doc/screenshots/4.pngbin0 -> 27423 bytes
-rw-r--r--doc/screenshots/5.pngbin0 -> 20439 bytes
-rw-r--r--doc/screenshots/6.pngbin0 -> 11822 bytes
-rw-r--r--doc/screenshots/restore/1.pngbin0 -> 18277 bytes
-rw-r--r--doc/screenshots/restore/2.pngbin0 -> 25758 bytes
-rw-r--r--doc/screenshots/restore/3.pngbin0 -> 17254 bytes
-rw-r--r--doc/screenshots/restore/4.pngbin0 -> 20842 bytes
-rw-r--r--doc/servers.mdwn194
-rw-r--r--doc/todo.mdwn4
-rw-r--r--keysafe.12
-rw-r--r--keysafe.cabal4
-rw-r--r--keysafe.service2
27 files changed, 817 insertions, 5 deletions
diff --git a/CHANGELOG b/CHANGELOG
index 5baf899..d5feb76 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -5,6 +5,7 @@ keysafe (0.20161108) UNRELEASED; urgency=medium
to avoid polynomial's failure to build with ghc 8.0
(https://github.com/mokus0/polynomial/issues/8)
* Clarify that dollars in cost estimates are USD.
+ * Keysafe has a new website, https://keysafe.branchable.com/
-- Joey Hess <id@joeyh.name> Tue, 29 Nov 2016 22:27:01 -0400
diff --git a/TODO b/TODO
index e0190cc..18426bf 100644
--- a/TODO
+++ b/TODO
@@ -70,5 +70,5 @@ Wishlist:
shares was used, the attacker could upload other objects where they would
be found before the real objects. This could be used to prevent
restore from working. (It also makes a malicious data attack (as described
- in https://joeyh.name/keysafe/details/) possible by attackers who do not
+ in https://keysafe.branchable.com/details/) possible by attackers who do not
control the servers.
diff --git a/doc/details.mdwn b/doc/details.mdwn
new file mode 100644
index 0000000..e0f85e5
--- /dev/null
+++ b/doc/details.mdwn
@@ -0,0 +1,365 @@
+[[!toc]]
+
+## Storing a key
+
+* Input password and name from user. The name is a combination of their own
+ name and a more obscure name (such as the name of their high-school
+ sweetheart).
+* Get the keyid of the key. (This can be any a public value
+ unique to the private key, eg a gpg keyid. It's only used to allow
+ storing multiple keys under a given name. If a gpg public key is not on the
+ keyservers, or the key is not a gpg key, can use "" for the keyid.)
+* Generate N by argon2(name, salt=keyid), tuned to take 10 minutes.
+* Generate N1-N3 by sha256 of N+1,2,3
+* Generate decryption puzzle P, a byte chosen at random.
+* Generate K by argon2(password, salt=name+P), tuned to take 0.195 minutes.
+* AES encrypt (data + checksum) with K as the key.
+* Shamir the encrypted key with N=2, M=3, yeilding S1-S3.
+* Servers reject attempts to store an object under a name that is
+ already in use.
+* Servers do not allow enumerating all objects stored,
+ and require a proof of work to handle any request.
+* Upload S1-S3 to separate servers under the names N1-N3.
+ If any of the uploads is rejected as name already in use,
+ ask user to enter a different name or password.
+
+So, storing a key takes 10 minutes.
+
+## Recovering a key
+
+* Input password and name from user.
+* Calculate N and N1-N2
+* Request N1-N3 from servers until two objects are available.
+* Shamir recombine the objects.
+* Guess a value for P.
+* Generate K by argon2(password, salt=name+P)
+* AES decrypt
+* Repeat with new P until checksum verifies.
+
+This takes 10 minutes to calculate N, plus on average 128 guesses of P.
+Total recovery time varies from 10 minutes to 60 minutes, with an
+average of 35 minutes.
+
+## Difficulty of brute forcing a single encrypted key
+
+* Assume we know the name and keyid, or have otherwise found a way to
+ determine the shards of a key. Download and recombine the shards.
+* Guess a password.
+* For each possible value of P, AES decrypt with
+ K = argon2(password, salt=name+P), and check if checksum verifies.
+ This takes 0.195 minutes * 256 = 50 minutes total.
+* Repeat for next password.
+
+So, for a password with N entropy, the number of CPU-years of work
+is to crack it is: `2^(N-1)*50/60/24/365`
+
+* Strong password (50 entropy): 53553077761 CPU-years
+* Weak password (30 entropy): 51072 CPU-years
+* Super-weak password (19 entropy): 25 CPU-years
+
+So, if an attacker is able to find the right shards for a secret key, it's
+feasible for them to crack super-weak and weak passwords, assuming the
+secret key is worth the cost of doing do. Stronger passwords quickly
+become infeasible to crack.
+
+## Attack methods
+
+An attacker who wants to target a particular person can guess the name they
+used, derive N1-N3, download two of S1-S3 and start brute forcing the
+password soon after the object is stored. This is the most likely attack
+method, so any user who could potentially be targeted like this should
+choose a strong password. A name that attackers are unlikely to guess
+prevents this attack, which is why keysafe prompts for not only the
+user's name, but also a more obscure name. Each name guess that the
+attacker makes takes 10 minutes of CPU time to generate N, as well
+as whatever proof of work the servers require.
+
+The sharding prevents a single malicious server from blindly
+guessing weak passwords across its entire collection of objects.
+It takes two servers colluding to try to recombine their shards.
+
+If recombining two shards yielded data which could be checked to see if
+it's valid, then it would become fairly inexpensive to try all combinations
+of shards, and obtain all the encrypted keys for further cracking. So it's
+important that there not be any checksum or header in addition to the AES
+encrypted data. (AES encrypted data cannot be distinguised from random
+garbage except by block size.) Get that right, and with N keysafe users, an
+attacker would need to try `2^(N-1)` combinations of shards to find one on
+average, and would need to brute force the password of each combination.
+With only 20 keysafe users, assuming all users have super-weak passwords,
+this attack takes 13107200 years of CPU work `(2^19*25)` to crack one. With
+50 users, this jumps to quadrillions of years of CPU work.
+
+Colluding servers can try to correlate related objects based on access
+patterns and recombine pairs of those, and then brute force the password.
+The correlation needs to be very fine-grained for this to work.
+If 15 users' objects are all bucketed together by the correlation,
+then the attacker has 16384 combinations to try on average before
+finding a correct combination. Multiply by 5 years CPU work for cracking
+only super-weak passwords.
+
+Colluding servers who want to target a particular person
+can guess their N1-N3, check if those objects exist on the server, and
+begin brute-forcing the password. This is not much cheaper than the same
+attack performed by a third-party attacker, except that the attacker
+doesn't need to wait for an object to download from the server to check if
+it exists.
+
+A state-level entity may try to subpoena the entire contents of keysafe
+servers. Once 2 servers are compromised, the state-level entity can try the
+same attacks that colluding servers can use (but probably cannot use
+attacks involving correlation because the server operators should not be
+retaining the data needed for correlation). Of course, they probably have
+many more resources to throw at the problem. But with only 50 keysafe
+users, recombining shards and trying super-weak passwords would be
+prohibitively expensive as detailed above. So, a state-level entity
+will probably only find it feasible to target particular people.
+Since such an attack can be performed by anyone as discussed above,
+there seems to actually be no incentive for a state-level to subpoena data.
+
+A state-level entity's best bet at getting lots of keys is probably to use
+their resources to compromise keysafe servers, and modify them to log data.
+Then a correlation attack can be done as discussed above.
+
+A different kind of attack: Legal/extralegal action to get a
+particular person's key removed from storage servers to try to
+deny them access to it. Or, to entirely take down storage servers.
+
+### Malicious data attack
+
+Two servers could collude to serve up malicious data to try to exploit the
+user's system.
+
+For example, if the user is using their gpg key to encrypt emails,
+and they restore a different gpg key, they might use it to encrypt with and
+then what they said could be decrypted by the attacker.
+
+To perform this attack, the attacker first has to manage to crack the user's
+password. Then they can replace the objects with malicious versions, encrypted
+with the same password.
+
+So, this is not too useful for gpg key replacement, since the attacker
+must already know the secret key. However, perhaps they could exploit bugs
+in gpg to compromise the user's system.
+
+## Server list
+
+There's a server list shipped with the client, giving their tor onion address
+and the organization providing the server.
+
+Three of the servers in the list are recommended servers.
+Shards are stored on these unless overridden by other configuration.
+
+When recovering a key, the client tries the recommended servers first. But,
+if it fails to recover the key using those, it goes on to try other servers
+on the list. This way we don't need to remember which servers the shards
+were stored on, and can change the recommended servers when necessary.
+
+See [[servers]] for more on the server list.
+
+## Servers
+
+Servers run exclusively as tor hidden services. This prevents them from
+finding out the IP addresses of clients, as well as providing transport
+level encryption.
+
+Servers should avoid keeping any logs, and should santize
+the timestamps of any files stored on them. (Eg set back to epoch
+and store on filesystem mounted with noatime.)
+
+Only small objects are accepted to be stored. This is to prevent this from
+being used as a general purpose data storage system, and only be useful
+for storing keys.
+
+However, `gpg --export-secret-key` can be hundreds of KB in size
+when a key has a lot of signatures etc. While this size can be cut
+down to 4 KB using `paperkey` to only include the secret key, it's
+desirable to store the public and secret key together. This way,
+a user does not have to publish the key to keyservers, which makes some
+attack methods much less likely to try to crack their key.
+
+So, the object size should be at least a few tens of KB. 64kb seems
+reasonable. If keysafe needs to store a larger key, it can chunk it up.
+
+Objects shoud be padded to a fixed size before they are encrypted, to
+prevent attackers from correlating and targeting particular objects based
+on size.
+
+## client-server Proof of Work
+
+The Proof of Work prevents servers being flooded with requests.
+This is particularly important to prevent misuse of keysafe servers
+to store large data on them. It's also somewhat useful to prevent attackers
+guessing the name someone used to store a key; but the cost of generating
+N from a name makes the server's proof of work only a secondary line of
+defense against such an attack. Finally, PoW is useful to protect against
+DOS attacks.
+
+Assuming that the client communicates with the server over http:
+
+ PUT /keysafe/objects/N
+ GET /keysafe/objects/N
+
+The server's response can be either the result of the request,
+or a proof of work requirement, which specifies the difficulty D
+(number of 0's needed), random salt RS, and the number of argon2
+iterations. The client provides the proof of work in a query parameter,
+which is a string S such that argon2(N,S+RS) starts with a given number
+of 0's.
+
+(The server should only be able to control the number of iterations,
+not other argon2 parameters, to avoid forcing the client to use too much
+memory. Normally, the server will keep iterations small, probably 1,
+since it does need to calculate the argon2 hash once itself.)
+
+The server can use a [token bucket](https://en.wikipedia.org/wiki/Token_bucket)
+to throttle requests to a given rate. In fact, there can be a whole
+series of token buckets B0,B1.., for increasing difficulty proofs of work.
+
+A request without a proof of work is checked in B0. If that bucket is empty,
+the server responds with a proof of work requirement D=1, and
+the client makes a new request whose proof of work allows access to B1.
+If the server is under load, B1 might also be empty, and so the client
+will have to try again with D=2 to access B2, and so on.
+
+If there are 4 buckets, and each bucket refills at the rate of a
+token every minute, then the maximum allowed throughput is 4 requests
+per minute. If calculating the proof of work takes 2^D seconds on average,
+then it will take on average 16 minutes work to access B4.
+
+The server can generate a different RS for each request, and can
+insert them into a bloom filter to keep track of ones it has given out.
+Bloom filter false positives are not a problem because they are quite
+rare and so it is not efficient for a client to make up RS in hope that
+there will be a false positive.
+
+To guard against DOS attacks that reuse proofs of work, the server can
+maintain a second bloom filter, putting RS into it once it's used, and
+rejecting attempts that reuse a RS. Since the bloom filter will
+(with a low probability) yield a false positive, the server should reject
+an attempt by generating a new RS' and requesting a new proof of work from
+the client.
+
+## Avoiding correlations
+
+As noted above, the more objects that are stored, the more secure
+keysafe becomes, because it becomes harder to correlate objects
+that belong to a user.
+
+Ways the server could draw correlations include:
+
+* Time that the data was stored.
+ (Avoid by waiting some period of time between uploading
+ various objects, probably on the order of days. If every keysafe uploads
+ its objects at midnight GMT, the server will find it hard to correlate
+ them.)
+* IP address used to store the data.
+ (Using tor avoids this.)
+* When the data was retrieved.
+ (Avoid by waiting some period of time between retrieving shards.
+ Although, this makes key recovery take longer, which could be
+ frustrating..)
+* A user ID associated with the data.
+ (Avoid by allowing anyone to store data and don't associate data with
+ any user ID.)
+* Same sized objects may be related shares.
+ (Avoid by making all objects stored be a standard size.)
+
+## Detecting corrupt data
+
+ ori> if a single server is compromised, it can return bogus data when you request its fragment of the shared secret
+ ori> if you only have three servers, you can't know which two to trust, short of just trying
+ ori> you end up with three possible ways to reconstruct the secrets, A-B, A-C, B-C. only one is legit.
+
+This could also happen due to error not compromise. Or even due to
+asking the wrong server for an object and getting back a dummy response.
+
+To guard against this, include a sha256sum of the secret key in the
+data that is sharded. This way the validity of the restored key can be
+verified.
+
+Note that this may make it marginally easier for brute force attacks, since
+they can use that checksum to detect when the attack is successful. Only
+marginally easier because it's not hard to fingerprint a gpg secret key.
+Even the minimised raw key output by paperkey can be recognised by a parser.
+
+## Versioning
+
+The algorithms and parameters chosen by keysafe could turn out to be
+wrong, or need adjusting to keep up with technology. While we'd like to
+avoid this by getting the design right, it's important to have a plan in
+case it becomes necessary.
+
+The simplest approach would be to include a version number with each shard.
+But, this causes a problem: When switching to a new version, the early
+atopters of that version are a small group, and so it becomes easier to
+correlate their shards.
+
+The version number could instead be included in the data that is sharded.
+This avoids the above problem, but leads to an even worse problem:
+An attacker can look for the version number after combining some random
+shards, and if they see it, they know they picked shards that are actually
+related. As described in "Attack methods", if an attacker can do that,
+it becomes easy for two colliding servers to find the right combinations of
+all shards.
+
+A safe alternative to embedding a version number anywhere in the data is
+to adjust the parameters of the argon2 hash used to generate the shard
+names. Maintain a list of versions and their shard name argon2
+parameters (as well as other parameters etc). During key recovery,
+keysafe can try different versions in turn, use argon2 to generate the
+shard names, and see if those shards can be downloaded. Once it finds
+shards, it knows the version that created them, and the other parameters
+of how the data is encoded.
+
+The only downside to this method is that each new version added to the list
+makes recovering data from all older versions take 10 minutes longer, as
+the argon2 hash has to be run an additional time.
+
+Note that the argon2 hash parameters to vary between versions should not be
+merely the number of rounds, as that would allow an attacker to hash for
+each version's number of rounds in one pass. Instead, vary the hash
+memory parameter.
+
+## Ideas
+
+Some ideas for improvements to keysafe.
+
+### Assisted Password-based Key Derivation
+
+An idea from [Nigori](http://www.links.org/files/nigori/nigori-protocol-01.html#anchor15):
+
+If the user has an account at some server, the server can contribute part
+of the data used to generate the key encryption key K. So not only is the
+user's keysafe password needed for key recovery, but the user has to
+authenticate to the server. As well as adding entropy to K, the server
+can do rate limiting to prevent password guessing.
+
+Risks include:
+
+* The server becomes a target to be compromised.
+* If the server goes down, the user loses the ability to recover their gpg
+ key from keysafe.
+
+### Entangled objects
+
+An idea from Anthony Towns:
+
+Two or more objects stored on a keysafe server can be entangled.
+When one of them is requested, the server should delete the others.
+
+This could be used in several ways:
+
+* Keysafe could upload random objects entangled with a key's object,
+ and keep local records of the names of the random objects. Then if the
+ user wants to stop storing a key on keysafe servers, keysafe can request
+ the entangled objects to (hopefully) delete the real objects from the
+ server.
+* Keysafe could pick or prompt for some tripwire names that an attacker
+ might try if they were looking for a user's data. Then an attacker
+ risks deleting the data stored on the server. Although this also has
+ DOS potential.
+* The user could pick a real name and fake name and keysafe uploads
+ objects for both. If the user is being forced to give up their keysafe
+ name and password, they could provide the fake name, and if it were
+ used, their data would get deleted from the keysafe servers.
diff --git a/doc/faq.mdwn b/doc/faq.mdwn
new file mode 100644
index 0000000..4512be7
--- /dev/null
+++ b/doc/faq.mdwn
@@ -0,0 +1,88 @@
+[[!toc]]
+
+### How does keysafe compare with paperkey?
+
+Using paperkey to print out your gpg key and locking it in a safe is a great
+solution to gpg key backup. It requires a printer, a safe, and typing in many
+numbers to restore the key. It avoids all attack methods except physical
+theft, raids, and compromised printers. Gold standard.
+
+Using keysafe is analagous to storing the paperkey printout in a safety
+deposit box at a bank, and using a really really strong gpg passphrase.
+Since we don't trust a single bank (server), we shred the printout and
+evenly distribute the shreds among several banks. While the banks know the
+safety deposit boxes belong to you and could put the shreds back together,
+a keysafe server has very little identifying information to go on (it only
+knows when you made the deposit).
+
+### I copy secring.gpg to dropbox to back it up. Why bother with keysafe?
+
+So, you rely on your gpg passphrase for security.
+
+Gpg uses between 1024 and 65011712 rounds of SHA-1 hashing of
+the passphrase, with the default probably being 65536.
+In 2012, a GPU could calculate 2 billion SHA-1 hashes per second,
+so this is not much of an impediment to password cracking at all.
+
+Assuming 100 gpg passphrases can be tried per second, and gpg is
+configured to use the maximum rounds (which it normally is NOT):
+
+* Strong passphrase (50 entropy): 21421231 GPU-years
+* Weak passphrase (30 entropy): 10 GPU-years
+* Super-weak passphrase (19 entropy): 2 GPU-days
+
+So this might be secure enough for some, but only with a really good
+passphrase. Probably, most people who copy their secring.gpg to
+the cloud have either a weakish passphrase, or have not tuned gpg to
+use maximum SHA-1 rounds, or both. So, they can probably be cracked in
+days to weeks.
+
+Compare these numbers with the cost to crack keysafe passwords
+(explained in [[details]]):
+
+* Strong password (50 entropy): 53553077761 CPU-years
+* Weak password (30 entropy): 51072 CPU-years
+* Super-weak password (19 entropy): 25 CPU-years
+
+(Note that is a comparison between GPU years and CPU years; SHA-1 used by
+gpg can easily be run fast on GPUs, while keysafe uses argon2 which is
+designed to be GPU-resistent.)
+
+Big difference! Indeed, the design of gpg prevents a really expensive hash
+being used to protect against passphrase cracking, because it would slow down
+day-to-day use of gpg. Keysafe can make cracking the password much more
+expensive because it's only used for backup and restore.
+
+### Is keysafe suitable for backing up bitcoin wallets?
+
+Not recommended. Use a brain wallet.
+
+Keysafe might be more secure than a paper wallet in some situations.
+It's happened before that someone has stumbled over someone else's
+list of electrum words among their papers. Using keysafe avoids such
+scenarios.
+
+#### How is keysafe different from other systems for private key backup/sync?
+
+Here are some similar systems, and intial impressions (which may be
+inaccurate; corrections welcomed):
+
+* [Whiteout](https://blog.whiteout.io/2014/07/07/secure-pgp-key-sync-a-proposal/)
+ uses a 24 letter code to encrypt the secret key. This has to be written
+ down to back it up. Since it is high-entropy (256 bits), the encryption
+ can be fast, and so it can be used to sync private keys between devices.
+* [Nigori](http://www.links.org/files/nigori/nigori-protocol-01.html)
+ uses a password to encrypt and SSS to split the private key.
+ Its main protection against password guessing seems be to be
+ its "Assisted Password-based Key Derivation", where some separate server
+ that the user has an account at supplies part of the encryption key after
+ the user has authenticated at the server. This allows the server to
+ rate-limit logins and so avoid password cracking (except by the server).
+ (This idea is worth keysafe stealing!)
+* [LEAP](https://leap.se/en/docs/tech/hard-problems#availability-problem)'s
+ [Soledad](https://leap.se/soledad) uses a large secret to encrypt
+ private keys. This can be stored in a recovery document in a recovery
+ database, which anyone can make requests from. To prevent attacks,
+ the recovery database delays responses, and a recovery code is needed
+ to access a document. The recovery code is a 16 character code that the
+ user has to write down.
diff --git a/doc/index.mdwn b/doc/index.mdwn
new file mode 100644
index 0000000..d96bf9c
--- /dev/null
+++ b/doc/index.mdwn
@@ -0,0 +1,81 @@
+Keysafe securely backs up a gpg secret key or other short secret to the cloud.
+
+This is not intended for storing Debian Developer keys that yield root on
+ten million systems. It's about making it possible for users to use gpg who
+currently don't, and who would find it too hard to use `paperkey` to back
+up and restore their key as they reinstall their laptop.
+
+Not yet ready for production use! Needs security review!
+May run over your dog! Not suitable for bitcoin keys!
+
+## Screenshots
+
+See [[screenshots]]. (Keysafe can also run in text mode in a terminal.)
+
+## How it works, basically
+
+The secret key is encrypted using a password, and is split into three
+shards, and each is uploaded to a server run by a different entity. Any two
+of the shards are sufficient to recover the original key. So any one server
+can go down and you can still recover the key.
+
+Keysafe checks your password strength (using the excellent but not perfect
+[zxcvbn library](https://github.com/tsyrogit/zxcvbn-c)),
+and shows an estimate of the cost to crack your password,
+before backing up the key.
+
+[[screenshots/4.png]]
+(Above is for the password "makesad spindle stick")
+
+Keysafe is designed so that it should take millions of dollars of computer
+time to crack any fairly good password. (This is accomplished using
+[Argon2](https://en.wikipedia.org/wiki/Argon2).)
+With a truely good password, such as four random words, the cracking cost
+should be many trillions of dollars.
+
+The password is the most important line of defense, but keysafe's design
+also makes it hard for an attacker to even find your encrypted secret key.
+
+For a more in-depth explanation, and some analysis of different attack
+vectors (and how keysafe thwarts them), see [[details]].
+Also, there's a [[FAQ]].
+
+## News
+
+[[!inline pages="code/keysafe/news/* and !*/Discussion" show="3"]]
+
+## Git repository
+
+`git clone git://keysafe.branchable.com/ keysafe`
+
+All tags and commits in this repository are gpg signed, and you should
+verify the signature before using it.
+
+## Installation
+
+You should first install Haskell's stack tool, the readline and argon2
+libraries, and zenity. For example, on a Debian system:
+
+ sudo apt-get install haskell-stack libreadline-dev libargon2-0-dev zenity
+
+Then to build and install keysafe:
+
+ stack install keysafe
+
+Note that there is a manpage, but stack doesn't install it yet.
+
+## Reporting bugs
+
+Email <id@joeyh.name>
+
+## Servers
+
+See [[servers]] for information on the keysafe servers.
+
+## License
+
+Keysafe is licensed under the terms of the AGPL 3+
+
+## Thanks
+
+Thanks to Anthony Towns for his help with keysafe's design.
diff --git a/doc/news/version_0.20160927.mdwn b/doc/news/version_0.20160927.mdwn
new file mode 100644
index 0000000..1787aa5
--- /dev/null
+++ b/doc/news/version_0.20160927.mdwn
@@ -0,0 +1,20 @@
+keysafe 0.20160927 released with [[!toggle text="these changes"]]
+[[!toggleable text="""
+ * Makefile: Avoid rebuilding on make install, so that sudo make install works.
+ * Added --chaff-max-delay option for slower chaffing.
+ * Fix embedded copy of Argon2 to not use Word64, fixing build on 32 bit
+ systems.
+ * Randomize the server list.
+ * Don't upload more than neededshares-1 shares to Alternate servers
+ without asking the user if they want to do this potentially dangerous
+ action.
+ * Added a second keysafe server to the server list. It's provided
+ by Marek Isalski at Faelix. Currently located in UK, but planned move
+ to CH. Currently at Alternate level until verification is complete.
+ * Server: --motd can be used to provide a Message Of The Day.
+ * Added --check-servers mode, which is useful both at the command line
+ to see what servers keysafe knows about, and as a cron job.
+ * Server: Round number of objects down to the nearest thousand, to avoid
+ leaking too much data about when objects are uploaded to servers.
+ * Filter out escape sequences and any other unusual characters when
+ writing all messages to the console."""]] \ No newline at end of file
diff --git a/doc/news/version_0.20161006.mdwn b/doc/news/version_0.20161006.mdwn
new file mode 100644
index 0000000..2758b34
--- /dev/null
+++ b/doc/news/version_0.20161006.mdwn
@@ -0,0 +1,10 @@
+keysafe 0.20161006 released with [[!toggle text="these changes"]]
+[[!toggleable text="""
+ * New --add-storage-directory and --add-server options, which can be used
+ to make keysafe backup/restore using additional locations.
+ * Removed --store-local option; use --add-storage-directory instead.
+ * Fix bugs with entry of gpg keyid in the keysafe.log.
+ * Fix bug in --autostart that caused the full gpg keyid to be
+ used to generate object names, which made restores would only work
+ when --gpgkeyid was specifid.
+ * Remove embedded copy of argon2 binding, depend on fixed version of package."""]] \ No newline at end of file
diff --git a/doc/news/version_0.20161007.mdwn b/doc/news/version_0.20161007.mdwn
new file mode 100644
index 0000000..a7e8468
--- /dev/null
+++ b/doc/news/version_0.20161007.mdwn
@@ -0,0 +1,9 @@
+keysafe 0.20161007 released with [[!toggle text="these changes"]]
+[[!toggleable text="""
+ * Check if --store-local directory is writable.
+ * Removed dependency on crypto-random.
+ * Added a LSB init script, for non-systemd systems.
+ (It currently uses Debian's start-stop-daemon, so would need porting
+ for other distributions.)
+ * /etc/default/keysafe is read by both the systemd service file and the
+ init script, and contains configuration for the keysafe server."""]] \ No newline at end of file
diff --git a/doc/news/version_0.20161022.mdwn b/doc/news/version_0.20161022.mdwn
new file mode 100644
index 0000000..e54f26e
--- /dev/null
+++ b/doc/news/version_0.20161022.mdwn
@@ -0,0 +1,12 @@
+keysafe 0.20161022 released with [[!toggle text="these changes"]]
+[[!toggleable text="""
+ * Add keywords to desktop file.
+ Thanks, Sean Whitton
+ * Fix use of .IP macro in manpage.
+ Thanks, Sean Whitton
+ * Fix some mispellings.
+ Thanks, Sean Whitton
+ * Makefile: Propagate LDFLAGS, CFLAGS, and CPPFLAGS through ghc.
+ * Makefile: Allow setting BUILDER=./Setup to build w/o cabal or stack.
+ * Makefile: Allow setting BUILDEROPTIONS=-j1 to avoid concurrent
+ build, which should make build reproducible."""]] \ No newline at end of file
diff --git a/doc/news/version_0.20161107.mdwn b/doc/news/version_0.20161107.mdwn
new file mode 100644
index 0000000..d98987e
--- /dev/null
+++ b/doc/news/version_0.20161107.mdwn
@@ -0,0 +1,14 @@
+keysafe 0.20161107 released with [[!toggle text="these changes"]]
+[[!toggleable text="""
+ * The third keysafe server is now available, provided by Purism.
+ * Purism's keysafe server has been vetted to Recommended level!
+ * Change default for --port to 4242.
+ * Fix --check-server to not fail when the server has not had anything
+ stored on it yet.
+ * --upload-queued: Exit nonzero if unable to upload all queued objects.
+ * --autostart: If unable to upload all queued objects initially,
+ delay between 1 and 2 hours and try again.
+ * Better suggestion when user is having difficulty thinking of a strong
+ enough password.
+ * Defer requesting secret key from gpg until just before backup, so the
+ user knows why gpg is asking for this secret key to be backed up."""]] \ No newline at end of file
diff --git a/doc/screenshots.mdwn b/doc/screenshots.mdwn
new file mode 100644
index 0000000..3e35cf2
--- /dev/null
+++ b/doc/screenshots.mdwn
@@ -0,0 +1,14 @@
+
+[[screenshots/1.png]]
+
+[[screenshots/2.png]]
+
+[[screenshots/3.png]]
+
+(Entered password was "makesad spindle stick")
+
+[[screenshots/4.png]]
+
+[[screenshots/5.png]]
+
+[[screenshots/6.png]]
diff --git a/doc/screenshots/0.png b/doc/screenshots/0.png
new file mode 100644
index 0000000..7cfe206
--- /dev/null
+++ b/doc/screenshots/0.png
Binary files differ
diff --git a/doc/screenshots/1.png b/doc/screenshots/1.png
new file mode 100644
index 0000000..7759d6a
--- /dev/null
+++ b/doc/screenshots/1.png
Binary files differ
diff --git a/doc/screenshots/2.png b/doc/screenshots/2.png
new file mode 100644
index 0000000..becd319
--- /dev/null
+++ b/doc/screenshots/2.png
Binary files differ
diff --git a/doc/screenshots/3.png b/doc/screenshots/3.png
new file mode 100644
index 0000000..58d7523
--- /dev/null
+++ b/doc/screenshots/3.png
Binary files differ
diff --git a/doc/screenshots/4.png b/doc/screenshots/4.png
new file mode 100644
index 0000000..418844a
--- /dev/null
+++ b/doc/screenshots/4.png
Binary files differ
diff --git a/doc/screenshots/5.png b/doc/screenshots/5.png
new file mode 100644
index 0000000..89e1a22
--- /dev/null
+++ b/doc/screenshots/5.png
Binary files differ
diff --git a/doc/screenshots/6.png b/doc/screenshots/6.png
new file mode 100644
index 0000000..d750141
--- /dev/null
+++ b/doc/screenshots/6.png
Binary files differ
diff --git a/doc/screenshots/restore/1.png b/doc/screenshots/restore/1.png
new file mode 100644
index 0000000..8fd1f43
--- /dev/null
+++ b/doc/screenshots/restore/1.png
Binary files differ
diff --git a/doc/screenshots/restore/2.png b/doc/screenshots/restore/2.png
new file mode 100644
index 0000000..e682486
--- /dev/null
+++ b/doc/screenshots/restore/2.png
Binary files differ
diff --git a/doc/screenshots/restore/3.png b/doc/screenshots/restore/3.png
new file mode 100644
index 0000000..7c7e5dc
--- /dev/null
+++ b/doc/screenshots/restore/3.png
Binary files differ
diff --git a/doc/screenshots/restore/4.png b/doc/screenshots/restore/4.png
new file mode 100644
index 0000000..4d07070
--- /dev/null
+++ b/doc/screenshots/restore/4.png
Binary files differ
diff --git a/doc/servers.mdwn b/doc/servers.mdwn
new file mode 100644
index 0000000..3e82c7e
--- /dev/null
+++ b/doc/servers.mdwn
@@ -0,0 +1,194 @@
+There are currently not enough keysafe servers. We need at least 3 for
+keysafe to work. Please contact <id@joeyh.name> if you would like to run a
+keysafe server.
+
+## Server categories
+
+Keysafe's server list puts servers in three categories:
+
+1. **Recommended**: Servers that meet all best practices for security and
+ are run by a well-known, trusted entity.
+
+ Keysafe prefers to store data only on Recommended servers when possible.
+
+2. **Alternate**: Servers that are not secured well enough to be
+ Recommended.
+
+ Keysafe will store data on Alternate servers if it has to, but will
+ avoid storing enough data to allow the key to be recovered using only
+ the data stored on Alternate servers.
+
+ For example, with 2 of 3 shares needed to restore a key, keysafe can
+ store 1 share on an Alternate server, and the other 2 shares on two
+ Recommended servers.
+
+3. **Untrusted**: Servers that are not secured well or are run by an untrusted
+ entity.
+
+ Keysafe will never store data on Untrusted servers.
+
+ If a server becomes untrusted and keysafe stored data on it in the past,
+ keysafe will warn the user about this problem.
+
+ The only time keysafe will use untrusted servers is if it's restoring a
+ key, and cannot find enough shares on Recommended/Alternate
+ servers, and has to fall back to downloading from an Untrusted server.
+
+## Server list
+
+### Recommended
+
+#### hlmjmeth356s5ekm.onion
+
+ -----BEGIN PGP SIGNED MESSAGE-----
+ Hash: SHA1
+
+ The keysafe server hlmjmeth356s5ekm.onion is provided and administered by
+ Purism. It is located in the EU (Cyprus).
+
+ We intend to run this server for at least 10 years (through 2027),
+ or failing that, to transition any data stored on it to another
+ server that is of similar or higher security.
+
+ Our warrant canary is <https://puri.sm/warrant-canary/>,
+ and is updated quarterly.
+ -----BEGIN PGP SIGNATURE-----
+ Version: GnuPG v1
+
+ iQIcBAEBAgAGBQJYF8U4AAoJECPPLj0lRRT30CkP/Rn2TAeriNWO9wZcr0OHyX7B
+ TJcgLy3pZXbGn6T6qmJqg3K22fTKJ7CX0dfIM+WLI9FfBtnT95q1rnzywhBGPXzj
+ eD3g7r3QinIfMLBQTKyc9Ik5132uenD5h72ggVl3D+kuWv622IhaAaiVkuHc5KoR
+ 3/S+ImkcS/gz83UNTXnWdMs0V8+eqAjpWeYQS8Ih28AECI9f+xUUH//V9Ii/4Usv
+ E3Y0hbqj8kSi4/Q6IwmFiJTKZ1FpccKhl6GIYUSLwJMJDHoI46M/AaZy0Xx9pLcU
+ niSELai/7/0fY4N0TY2CbZUgH7FEhi0k8cCsGF7yTA6dqya8deKQKdUdDllcHayv
+ +GOAqijiSTPrRox4TPMMdurPXTsJxeJuxVdS75Lw2cFk+JaaIVS/3XEyeuGpaVKW
+ wSTltyFkMx9ur5cCPT2rxoRN78HuqgiHda/Jd4c2pny7GwpUEYAznQQaBYEl2jlQ
+ /Go3ZudpnWfBRRe7znazhA6mIatPY61GrNIebVlET6/NCw9sZFRjHXY3pMw1u/TY
+ 4eP0UQpBUed4/sot5vsZVwbn8e6eFh0S4HTdl5x1G8jN8nUZVdJJjOtACrONW+TG
+ CLSNDkMgQ5slBmtZm+MzL2VYkFHCMmPerNXY1DhHjMyfLpQEIN+bho+mIyc5h/W/
+ Br5jFZujcQ0u7GzqvaDB
+ =RmK4
+ -----END PGP SIGNATURE-----
+
+### Alternate
+
+#### keysafe.joeyh.name
+
+ -----BEGIN PGP SIGNED MESSAGE-----
+ Hash: SHA256
+
+ keysafe.joeyh.name is provided by me, Joey Hess.
+
+ I intend to run this server for at least 10 years (through 2027),
+ or failing that, to transition any data stored on it to another
+ server that is of similar or higher security.
+
+ It is a Digital Ocean VPS, located in Indonesia. I can't tell if the
+ hosting provider is accessing the contents of the server, and so
+ this server is not securely hosted enough to be Recommended.
+ -----BEGIN PGP SIGNATURE-----
+
+ iQIcBAEBCAAGBQJXx0qFAAoJEMkQ2SIlEuPHyGMQALSLL7LZEpTi+zf2kPYGoBMQ
+ 3z3FDB9B6SaF4uN3r+XlAw2Vzas2KVLCbNkO+np7tLzC0qdY5dBLDI7+ZJXiKi2v
+ iqxKICl0E8+ih8JOe0JWfoysO974I1DesEI7X6VUewwNpd35OgCuIL5RmknKrX4I
+ x7gUfsONiojUKgOT0yMErUfw3VNYB0Kbzw4Xic66eIkFl5z6APMknjqvOC1196v9
+ BW0rSM+OsthB9xkj7ULKQv+1LrxmwNu0+FL62qNKGObbXHayfLBGm8TT9Y7etQYD
+ 3zRDiUfa0m2aYu7ZRx5HSIgExVVd3YosDUFA4xsIb6N4wBbP1zS2TG2Zo5o/+3gt
+ BerkQL/xkMWhIMVCYp1hWc47MenHk1MJU5EhS+duL/fnlqW2HcFanM+fOv+/ZWt6
+ da2mdjSR95Ekq22BXN9eHO54AFJKLWYNdT9E5W2rlwqUoC4dqsqYGT3XWnAaKHC/
+ he9+B/wdEf7165Qy+MKo/36Ib7pfhPQv4hip2cuMP9w0E6JoKZusBV5AdxRvGAGf
+ GvUhvNog6v9/t+cqUp6dSTT2WVllkXJ/5deGJYLzZMJjZS3cZ75ZKr8OD5oQxr+m
+ 7oL6BDvxha7Q4qHo/RZgxyd/qZ7zWHTT6Tn6qNCBGUi4b6Etb0kEd5Os66WoLCSK
+ lhmhvShr0WRqB8fWYPkc
+ =SNGN
+ -----END PGP SIGNATURE-----
+</pre>
+
+#### thirdserver
+
+ Provided by Marek Isalski at [Faelix](http://www.faelix.net/).
+ Currently located in UK, but planned move to CH.
+ Vetting to Recommended level in progress.
+
+## Detailed requirements
+
+### Alternate
+
+* Keysafe port only exposed via tor hidden service.
+* Dedicated to only running keysafe, no other services. (Other than tor and
+ ssh for admin)
+* The set of people who administer the server, and procedures for giving
+ others access is well-defined.
+* Noone who has access to the server also has access to any Recommended
+ server.
+* Commitment to either keep the server running long-term (ie, 10+ years),
+ or transition the data to a replacement server that meets these
+ requirements and that must not contain any related shards.
+* No other open ports (other than ssh).
+* Ssh authentication only by ssh key, not password.
+* Either off-server backup, or replication of shards to additional disks.
+ (rsync to additional local disks would work perfectly well and avoids
+ the complications of RAID)
+* Any off-server backup is strongly encrypted.
+ (There's a trade-off here; any backup widens the attack surface.
+ It may be better to run some servers without backups and adjust the
+ number of shards needed to recover keys; a server losing its data
+ need not be catastrophic.)
+* Any backup should take care to not leak information about what objects
+ were present on the server at multiple times in the past. That would
+ let an attacker who can access the backups make guesses about shares
+ belong with other shares stored on other servers in the same time period.
+ See [[details]] for how that makes it somewhat easier for an attacker.
+
+ keysafe --backup-server can be used to generate encrypted files to back up,
+ in a way that is designed to avoid these problems.
+
+* Similarly, the filesystem and storage system should not allow rolling back
+ to old snapshots.
+
+### Recommended
+
+* Everything in Alternate, to start with.
+* Run by a well known and trustworthy entity.
+* Noone who has access to the server also has access to any other
+ Recommended or Alternate server.
+* Warrant canary.
+* Hardware is hosted in-house. A VM at a cloud provider is right out
+ because the provider could be made to give access to it without the
+ server operator knowing about it. Which would bypass the warrant canary.
+* The keysafe data store and any swap partitions are encrypted,
+ and have to be manually unlocked when the server is booted.
+
+## Server scaling
+
+Each key takes a minimum of 64 KiB to store, perhaps more for gpg keys
+with lots of signatures. So 10 GiB of disk is sufficient for 160 thousand
+users, which is enough for a small keysafe server.
+
+The keysafe server uses very little memory and CPU. It does rate limiting
+with client-side proof-of-work to prevent it being abused for
+general-purpose data storage.
+
+There is some disk IO overhead, because keysafe updates the mtime and ctime
+of all shards stored on the server, as frequently as every 30 minutes.
+Once a large number of shards are stored, this could become a significant
+source of disk IO.
+
+## Server setup
+
+It's early days still, but keysafe's server code works well enough.
+
+* `git clone git://keysafe.branchable.com/ keysafe`
+* Be sure to verify the gpg signature of the git repository!
+* You will need to install keysafe from source; see its INSTALL file.
+ Use `make install` to install it, including a systemd service file.
+* `systemctl enable keysafe.service`
+* Install tor and set up a tor hidden service. Keysafe listens on port 4242
+ by default, so use that port.
+* Configure the server to meet all the requirements for Alternate or
+ Required.
+* Once ready, email id@joeyh.name to get added to keysafe's server list.
+
+Here's a the [[code/propellor]] config for my own keysafe server:
+<http://source.propellor.branchable.com/?p=source.git;a=blob;f=joeyconfig.hs;h=15a00f7c2dffa15ed275fdd44e84e2edcc226559;hb=b9f87f0c08d94c5d43224a2c6bbacb332ebfc1b6#l460>
+--[[Joey]]
diff --git a/doc/todo.mdwn b/doc/todo.mdwn
new file mode 100644
index 0000000..6fa6e18
--- /dev/null
+++ b/doc/todo.mdwn
@@ -0,0 +1,4 @@
+This is keysafe's todo list. Link items to [[todo/done]] when done.
+
+[[!inline pages="./todo/* and !./todo/done and !link(done)
+and !*/Discussion" actions=yes postform=yes show=0 archive=yes]]
diff --git a/keysafe.1 b/keysafe.1
index 6b75c8a..7d0ee2b 100644
--- a/keysafe.1
+++ b/keysafe.1
@@ -161,6 +161,6 @@ The server's Message Of The Day.
Avoid using expensive cryptographic operations to secure data.
Use for testing only, not with real secret keys.
.SH SEE ALSO
-<https://joeyh.name/code/keysafe/>
+<https://keysafe.branchable.com/>
.SH AUTHOR
Joey Hess <id@joeyh.name>
diff --git a/keysafe.cabal b/keysafe.cabal
index 6c12124..ca261c4 100644
--- a/keysafe.cabal
+++ b/keysafe.cabal
@@ -6,7 +6,7 @@ Author: Joey Hess
Stability: Experimental
Copyright: 2016 Joey Hess
License: AGPL-3
-Homepage: https://joeyh.name/code/keysafe/
+Homepage: https://keysafe.branchable.com/
Category: Utility
Build-Type: Custom
Synopsis: back up a secret key securely to the cloud
@@ -125,4 +125,4 @@ Executable keysafe
source-repository head
type: git
- location: git://git.joeyh.name/keysafe.git
+ location: git://keysafe.branchable.com/
diff --git a/keysafe.service b/keysafe.service
index 24eaad2..1ae5f4a 100644
--- a/keysafe.service
+++ b/keysafe.service
@@ -1,6 +1,6 @@
[Unit]
Description=keysafe server
-Documentation=https://joeyh.name/code/keysafe/
+Documentation=https://keysafe.branchable.com/
[Service]
Environment='DAEMON_PARAMS=--port 4242 --store-directory=/var/lib/keysafe/'