Recent changes to this wiki:

add news item for github-backup 1.20160922
diff --git a/code/github-backup/news/version_1.20150807.mdwn b/code/github-backup/news/version_1.20150807.mdwn
deleted file mode 100644
index 13d0ccd..0000000
--- a/code/github-backup/news/version_1.20150807.mdwn
+++ /dev/null
@@ -1,8 +0,0 @@
-github-backup 1.20150807 released with [[!toggle text="these changes"]]
-[[!toggleable text="""
-   * Added bash completion.
-   * Add --no-forks flag that turns off backing up forks.
-     Thanks, Phil Ruffwind.
-   * Avoid nonzero exit due to temporary failures that can be retried next
-     time github-backup runs, so that it can be used in a cron job with eg,
-     chronic."""]]
\ No newline at end of file
diff --git a/code/github-backup/news/version_1.20160922.mdwn b/code/github-backup/news/version_1.20160922.mdwn
new file mode 100644
index 0000000..b9e1464
--- /dev/null
+++ b/code/github-backup/news/version_1.20160922.mdwn
@@ -0,0 +1,11 @@
+github-backup 1.20160922 released with [[!toggle text="these changes"]]
+[[!toggleable text="""
+   * Increase base bounds to 4.8 to get mapM\_ etc that works on Vector.
+   * Recommended build method is now to use stack, for more reliable builds.
+   * Explicitly list modules and other files in github-backup.cabal.
+   * The hackage .tar.gz now omits the debian directory and may omit other
+     source files in the future; the purpose of that tarball is to make
+     stack/cabal install work, not to be a complete source distribution.
+     Use git repository to get complete source.
+   * Various updates to internal git and utility libraries shared
+     with git-annex."""]]
\ No newline at end of file

correction
diff --git a/code/keysafe/faq.mdwn b/code/keysafe/faq.mdwn
index 03005fd..21387eb 100644
--- a/code/keysafe/faq.mdwn
+++ b/code/keysafe/faq.mdwn
@@ -10,7 +10,7 @@ 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 amoung three banks. While the banks know the
+evenly distribute the shreds amoung 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).

expand
diff --git a/code/keysafe/faq.mdwn b/code/keysafe/faq.mdwn
index 2d0b91a..03005fd 100644
--- a/code/keysafe/faq.mdwn
+++ b/code/keysafe/faq.mdwn
@@ -1,5 +1,20 @@
 [[!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 amoung three 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.
@@ -34,13 +49,6 @@ 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.
 
-### 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.
-
 ### Is keysafe suitable for backing up bitcoin wallets?
 
 Not recommended. Use a brain wallet.

POW
diff --git a/code/keysafe/details.mdwn b/code/keysafe/details.mdwn
index 6d7d28e..4fd7fea 100644
--- a/code/keysafe/details.mdwn
+++ b/code/keysafe/details.mdwn
@@ -176,19 +176,45 @@ 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. If keysafe needs
-to store a larger key, it can chunk it up, and include a count of the
-number of chunks in the first encrypted object.
+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.
 
-When a client connects to a server, it sends a request. The server
-replies with a
-[proof of work puzzle](https://en.wikipedia.org/wiki/Client_Puzzle_Protocol)
-that the client must solve to make that request.
-This can be used by servers to avoid DOS attacks.
+## Client puzzles
+
+Assuming that the client communicates with the server over http:
+
+	PUT /keysafe/objects/N?S
+	GET /keysafe/objects/N?S
+
+Then, the S can be required to be a string such that argon2(N,S)
+starts with a given number of 0's. This allows the server to verify the
+client's proof of work without maintaining any state.
+
+The required number of 0's can be queried:
+
+	GET /keysafe/proofofwork/
+
+With a response like "zeros=4 iterations=1".
+
+(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 itself.)
+
+Note that this scheme lets a client do work once for a given N and then
+request that N from multiple servers, as long as they have similar zeros=
+parameters (and the same iterations= parameters). This is probably a good
+thing; it means that keysafe doesn't need to do extra work when checking
+servers to get a shard.
+
+Servers can change their proof of work parameters as needed, but that can
+cause a client that was connected to the server to generate a bad POW.
+The server can respond with 402 Payment Required in that case, so the
+client knows to retry.
 
 ## Avoiding correlations
 

add
diff --git a/code.mdwn b/code.mdwn
index ba9ad89..2bd4dc0 100644
--- a/code.mdwn
+++ b/code.mdwn
@@ -27,6 +27,7 @@ In maintenance mode mostly, but I still have my hands in it somewhat.
 [[filters]]
 [[electrum-mnemonic]]
 [[brainfuck-monad]]
+[[zxcvbn-c]]
 [[scroll]]
 
 ## Past projects
diff --git a/code/zxcvbn-c.mdwn b/code/zxcvbn-c.mdwn
new file mode 100644
index 0000000..a73cf29
--- /dev/null
+++ b/code/zxcvbn-c.mdwn
@@ -0,0 +1,6 @@
+A quick haskell interface to the zxcvbn-c password strength estimation
+library.
+
+<http://hackage.haskell.org/package/zxcvbn-c>
+
+At some point, it would be good to implement this in pure haskell.

faq
diff --git a/code/keysafe.mdwn b/code/keysafe.mdwn
index 0047cba..7e8bfd1 100644
--- a/code/keysafe.mdwn
+++ b/code/keysafe.mdwn
@@ -38,6 +38,7 @@ 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
 
@@ -71,74 +72,6 @@ Email <id@joeyh.name>
 
 Keysafe is licensed under the terms of the AGPL 3+
 
-## Comparisons with other approaches
-
-### 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.
-
-### storing secring.gpg in the cloud
-
-Some people copy secring.gpg to dropbox or similar to back it up,
-and rely on the gpg passphrase for security.
-
-Gpg uses between 1024 (the default) and 65011712 rounds of SHA-1 hashing of
-the passphrase. 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 
-
-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.
-
-### non-sharded variant of keysafe
-
-Worth comparing the sharding approach with the most secure and simple
-non-sharded approach I can think of:
-
-* 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.
-* upload to diverse locations using the gpg keyid as a unique ID
-  (with some complication to handle objects maliciously uploaded using
-  the same ID)
-
-The key encryption is the same as keysafe in this approach, so the
-difficulty in brute forcing an encrypted key is the same as described
-in [[details]]. Brute-forcing is only feasible for weak passwords.
-
-But brute forcing can start right away, and be performed by anyone,
-unlike with sharding where only two colluding servers can start brute
-forcing right away.
-
-So, this isn't too bad, but for all the users who use weak passwords
-(you know who you are (yes, you)), it's not as good a choice as keysafe.
-At worst, keysafe degrades to being as secure as this approach.
-
 ## Thanks
 
 Thanks to Anthony Towns for his help with keysafe's design.
diff --git a/code/keysafe/faq.mdwn b/code/keysafe/faq.mdwn
new file mode 100644
index 0000000..2d0b91a
--- /dev/null
+++ b/code/keysafe/faq.mdwn
@@ -0,0 +1,51 @@
+[[!toc]]
+
+### 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 (the default) and 65011712 rounds of SHA-1 hashing of
+the passphrase. 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 
+
+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.
+
+### 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.
+
+### 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 amoung their papers. Using keysafe avoids such
+scenarios.

patreon
diff --git a/blog/entry/keysafe_alpha_release.mdwn b/blog/entry/keysafe_alpha_release.mdwn
index 30aa358..c9787ee 100644
--- a/blog/entry/keysafe_alpha_release.mdwn
+++ b/blog/entry/keysafe_alpha_release.mdwn
@@ -29,3 +29,5 @@ that's less than a year old, send me a benchmark:
 Bonus announcement: <http://hackage.haskell.org/package/zxcvbn-c/> is my
 quick Haskell interface to the C version of the zxcvbn password strength
 estimation library.
+
+PS: Past 50% of my goal on [Patreon](https://www.patreon.com/joeyh)!

typo
diff --git a/blog/entry/keysafe_alpha_release.mdwn b/blog/entry/keysafe_alpha_release.mdwn
index 86843a5..30aa358 100644
--- a/blog/entry/keysafe_alpha_release.mdwn
+++ b/blog/entry/keysafe_alpha_release.mdwn
@@ -22,7 +22,7 @@ to `~/.keysafe/objects/local/`
 
 I still need to tune the argon2 hash difficulty, and I need benchmark data
 to do so. If you have a top of the line laptop or server class machine
-that's less than a year old, send me a bechmark:
+that's less than a year old, send me a benchmark:
 
 	~/.local/bin/keysafe --benchmark | mail keysafe@joeyh.name -s benchmark
 

blog update
diff --git a/blog/entry/keysafe_alpha_release.mdwn b/blog/entry/keysafe_alpha_release.mdwn
new file mode 100644
index 0000000..86843a5
--- /dev/null
+++ b/blog/entry/keysafe_alpha_release.mdwn
@@ -0,0 +1,31 @@
+[[code/Keysafe]] securely backs up a gpg secret key or other short secret
+to the cloud. But not yet. Today's alpha release only supports storing the
+data locally, and I still need to finish tuning the argon2 hash
+difficulties with modern hardware. Other than that, I'm fairly happy with
+how it's turned out.
+
+Keysafe is written in Haskell, and many of the data types in it keep track
+of the estimated CPU time needed to create, decrypt, and brute-force them.
+Running that through a AWS SPOT pricing cost model lets keysafe estimate
+how much an attacker would need to spend to crack your password.
+
+[[code/keysafe/screenshots/4.png]]  
+(Above is for the password "makesad spindle stick")
+
+If you'd like to be an early adopter, install it like this:
+
+	sudo apt-get install haskell-stack libreadline-dev libargon2-0-dev zenity
+	stack install keysafe
+
+Run `~/.local/bin/keysafe --backup --store-local` to back up a gpg key
+to `~/.keysafe/objects/local/`
+
+I still need to tune the argon2 hash difficulty, and I need benchmark data
+to do so. If you have a top of the line laptop or server class machine
+that's less than a year old, send me a bechmark:
+
+	~/.local/bin/keysafe --benchmark | mail keysafe@joeyh.name -s benchmark
+
+Bonus announcement: <http://hackage.haskell.org/package/zxcvbn-c/> is my
+quick Haskell interface to the C version of the zxcvbn password strength
+estimation library.

de-hide
diff --git a/code/keysafe/news/version_0.20160819.mdwn b/code/keysafe/news/version_0.20160819.mdwn
index 38d9b31..1fe832a 100644
--- a/code/keysafe/news/version_0.20160819.mdwn
+++ b/code/keysafe/news/version_0.20160819.mdwn
@@ -1,5 +1,5 @@
-keysafe 0.20160819 released with [[!toggle text="these changes"]]
-[[!toggleable text="""
+keysafe 0.20160819 released
+
    * First release of keysafe. This is not yet ready for production use.
    * Network support is not yet implemented, but --store-local works for
      testing with local data storage.
@@ -8,4 +8,4 @@ keysafe 0.20160819 released with [[!toggle text="these changes"]]
      1 data will be supported by every later version.
    * Argon2 hashes are not yet tuned for modern hardware, but only for my
      laptop. So, cracking cost estimates may be low. To help with this
-     tuning, run `keysafe --bechmark` and send the output to me."""]]
\ No newline at end of file
+     tuning, run `keysafe --bechmark` and send the output to me.

add news item for keysafe 0.20160819
diff --git a/code/keysafe/news/version_0.20160819.mdwn b/code/keysafe/news/version_0.20160819.mdwn
new file mode 100644
index 0000000..38d9b31
--- /dev/null
+++ b/code/keysafe/news/version_0.20160819.mdwn
@@ -0,0 +1,11 @@
+keysafe 0.20160819 released with [[!toggle text="these changes"]]
+[[!toggleable text="""
+   * First release of keysafe. This is not yet ready for production use.
+   * Network support is not yet implemented, but --store-local works for
+     testing with local data storage.
+   * Data backed up with keysafe version 0.* will not be able to be restored
+     by any later version! Once the data format stabalizes, keysafe version
+     1 data will be supported by every later version.
+   * Argon2 hashes are not yet tuned for modern hardware, but only for my
+     laptop. So, cracking cost estimates may be low. To help with this
+     tuning, run `keysafe --bechmark` and send the output to me."""]]
\ No newline at end of file

update
diff --git a/code/keysafe.mdwn b/code/keysafe.mdwn
index 84131fa..0047cba 100644
--- a/code/keysafe.mdwn
+++ b/code/keysafe.mdwn
@@ -129,7 +129,7 @@ non-sharded approach I can think of:
 
 The key encryption is the same as keysafe in this approach, so the
 difficulty in brute forcing an encrypted key is the same as described
-above. Brute-forcing is only feasible for weak passwords.
+in [[details]]. Brute-forcing is only feasible for weak passwords.
 
 But brute forcing can start right away, and be performed by anyone,
 unlike with sharding where only two colluding servers can start brute

updates
diff --git a/code/keysafe.mdwn b/code/keysafe.mdwn
index fdae453..84131fa 100644
--- a/code/keysafe.mdwn
+++ b/code/keysafe.mdwn
@@ -73,6 +73,13 @@ Keysafe is licensed under the terms of the AGPL 3+
 
 ## Comparisons with other approaches
 
+### 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.
+
 ### storing secring.gpg in the cloud
 
 Some people copy secring.gpg to dropbox or similar to back it up,
@@ -86,14 +93,27 @@ 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 password (50 entropy): 21421231 GPU-years
-* Weak password (30 entropy): 10 GPU-years
-* Super-weak password (19 entropy): 2 GPU-days
+* 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 
 
-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.
+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.
 
 ### non-sharded variant of keysafe
 

crop
diff --git a/code/keysafe/screenshots/4.png b/code/keysafe/screenshots/4.png
index 3c137a2..418844a 100644
Binary files a/code/keysafe/screenshots/4.png and b/code/keysafe/screenshots/4.png differ

typog
diff --git a/code/keysafe.mdwn b/code/keysafe.mdwn
index bfb5f44..fdae453 100644
--- a/code/keysafe.mdwn
+++ b/code/keysafe.mdwn
@@ -29,7 +29,7 @@ before backing up the key.
 
 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)).
+[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.
 

reduce size
diff --git a/code/keysafe/screenshots/4.png b/code/keysafe/screenshots/4.png
index 31e0517..3c137a2 100644
Binary files a/code/keysafe/screenshots/4.png and b/code/keysafe/screenshots/4.png differ

foo
diff --git a/code/keysafe.mdwn b/code/keysafe.mdwn
index 9946f01..bfb5f44 100644
--- a/code/keysafe.mdwn
+++ b/code/keysafe.mdwn
@@ -5,7 +5,8 @@ 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.
 
-Needs security review! May run over your dog! Not suitable for bitcoin keys!
+Not yet ready for production use! Needs security review!
+May run over your dog! Not suitable for bitcoin keys!
 
 ## Screenshots
 

rss
diff --git a/code/keysafe.mdwn b/code/keysafe.mdwn
index 36b31a4..9946f01 100644
--- a/code/keysafe.mdwn
+++ b/code/keysafe.mdwn
@@ -38,6 +38,10 @@ 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]].
 
+## News
+
+[[!inline pages="code/keysafe/news/* and !*/Discussion" show="3"]]
+
 ## Git repository
 
 `git clone git://git.joeyh.name/keysafe.git`

update
diff --git a/code/keysafe.mdwn b/code/keysafe.mdwn
index 534123d..36b31a4 100644
--- a/code/keysafe.mdwn
+++ b/code/keysafe.mdwn
@@ -62,6 +62,10 @@ Note that there is a manpage, but stack doesn't install it yet.
 
 Email <id@joeyh.name>
 
+## License
+
+Keysafe is licensed under the terms of the AGPL 3+
+
 ## Comparisons with other approaches
 
 ### storing secring.gpg in the cloud

update
diff --git a/code/keysafe.mdwn b/code/keysafe.mdwn
index 380f660..534123d 100644
--- a/code/keysafe.mdwn
+++ b/code/keysafe.mdwn
@@ -23,8 +23,8 @@ Keysafe checks your password strength (using the excellent but not perfect
 and shows an estimate of the cost to crack your password,
 before backing up the key. 
 
-[[screenshots/3.png]] [[screenshots/4.png]]
-(Entered password was "makesad spindle stick")
+[[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

reorg
diff --git a/code/keysafe.mdwn b/code/keysafe.mdwn
index 2e198c7..380f660 100644
--- a/code/keysafe.mdwn
+++ b/code/keysafe.mdwn
@@ -9,11 +9,7 @@ Needs security review! May run over your dog! Not suitable for bitcoin keys!
 
 ## Screenshots
 
-[[screenshots/1.png]] [[screenshots/2.png]]
-
-[[screenshots/3.png]] [[screenshots/4.png]] (Entered password was "makesad spindle stick")
-
-[[screenshots/5.png]] [[screenshots/6.png]]
+See [[screenshots]]. (Keysafe can also run in text mode in a terminal.)
 
 ## How it works, basically
 
@@ -27,6 +23,9 @@ Keysafe checks your password strength (using the excellent but not perfect
 and shows an estimate of the cost to crack your password,
 before backing up the key. 
 
+[[screenshots/3.png]] [[screenshots/4.png]]
+(Entered password was "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)).
@@ -41,7 +40,8 @@ vectors (and how keysafe thwarts them), see [[details]].
 
 ## Git repository
 
-Keysafe's git repository is <git://git.joeyh.name/keysafe.git>.
+`git clone git://git.joeyh.name/keysafe.git`
+
 All tags and commits in this repository are gpg signed, and you should
 verify the signature before using it.
 
diff --git a/code/keysafe/screenshots.mdwn b/code/keysafe/screenshots.mdwn
new file mode 100644
index 0000000..3e35cf2
--- /dev/null
+++ b/code/keysafe/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]]

wording
diff --git a/code/keysafe.mdwn b/code/keysafe.mdwn
index 7679176..2e198c7 100644
--- a/code/keysafe.mdwn
+++ b/code/keysafe.mdwn
@@ -112,5 +112,4 @@ At worst, keysafe degrades to being as secure as this approach.
 
 ## Thanks
 
-Thanks to Anthony Towns for his help reviewing the security properties of
-keysafe.
+Thanks to Anthony Towns for his help with keysafe's design.

update
diff --git a/code/keysafe.mdwn b/code/keysafe.mdwn
index d3a7d78..7679176 100644
--- a/code/keysafe.mdwn
+++ b/code/keysafe.mdwn
@@ -5,345 +5,62 @@ 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 implemented! Needs security review! May run over your dog!
-Not suitable for bitcoin keys!
+Needs security review! May run over your dog! Not suitable for bitcoin keys!
 
-## Example
+## Screenshots
 
-	> keysafe --backup --name="email@example.com" --type=gpg
-	Password:
-	Verify password:
-	Please wait...
-	Key backed up to 3 servers, hosted by:
-		eff.org
-		riseup.net
-		joeyh.name
+[[screenshots/1.png]] [[screenshots/2.png]]
 
-	> keysafe --restore --name="email@example.com" --type=gpg
-	Password:
-	Please wait...
-	Key successfully restored.
+[[screenshots/3.png]] [[screenshots/4.png]] (Entered password was "makesad spindle stick")
 
-	[also, imagine a GUI here]
+[[screenshots/5.png]] [[screenshots/6.png]]
 
 ## How it works, basically
 
-The secret key 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.
-
-A password is used to encrypt the key. Using a strong password is highly
-recommended, especially for well-known keys. Brute forcing a strong
-password is infeasible with keysafe. Keysafe is designed so that
-even a well-chosen 8 letter long password protects a key for years. Basing
-passwords on dictionary words of course makes them much easier to crack.
-
-If your gpg key ID is not published to keyservers or elsewhere,
-it's very unlikely any attacker will find the encrypted key that keysafe
-stores, let alone devote years of work to cracking this unknown key.
-
-All you need to recover the key is the --name you used when backing it up,
-and the password.
-
-## 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 client puzzle 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 work the servers impose to solve their client puzzle.
-
-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. 

(Diff truncated)
obscure name
diff --git a/code/keysafe.mdwn b/code/keysafe.mdwn
index bcb7a26..d3a7d78 100644
--- a/code/keysafe.mdwn
+++ b/code/keysafe.mdwn
@@ -48,7 +48,9 @@ and the password.
 
 ## Storing a key
 
-* Input password and name from user.
+* 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
@@ -112,8 +114,11 @@ 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 also
-helps.
+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 work the servers impose to solve their client puzzle.
 
 The sharding prevents a single malicious server from blindly 
 guessing weak passwords across its entire collection of objects.

comparison
diff --git a/code/keysafe.mdwn b/code/keysafe.mdwn
index 52f926d..bcb7a26 100644
--- a/code/keysafe.mdwn
+++ b/code/keysafe.mdwn
@@ -342,6 +342,30 @@ Reading the key from gpg into locked memory is the other challenge.
 
 ## Comparisons with other approaches
 
+### storing secring.gpg in the cloud
+
+Some people copy secring.gpg to dropbox or similar to back it up,
+and rely on the gpg passphrase for security.
+
+Gpg uses between 1024 (the default) and 65011712 rounds of SHA-1 hashing of
+the passphrase. 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:
+
+* Strong password (50 entropy): 21421231 GPU-years
+* Weak password (30 entropy): 10 GPU-years
+* Super-weak password (19 entropy): 2 GPU-days
+
+Indeed, the design of gpg prevents an 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.
+
+### non-sharded variant of keysafe
+
 Worth comparing the sharding approach with the most secure and simple
 non-sharded approach I can think of:
 

minor tweaks to attack methods
and recalculated some attack costs
diff --git a/code/keysafe.mdwn b/code/keysafe.mdwn
index dbc8e4e..52f926d 100644
--- a/code/keysafe.mdwn
+++ b/code/keysafe.mdwn
@@ -50,7 +50,9 @@ and the password.
 
 * Input password and name from user.
 * Get the keyid of the key. (This can be any a public value
-  unique to the private key, eg a gpg keyid.)
+  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.
@@ -84,56 +86,60 @@ average of 35 minutes.
 
 ## Difficulty of brute forcing a single encrypted key
 
-* Assume we know the name.
+* 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
-  argon2(password, salt=name+P), and check if checksum verifies.
-* Repeat for next password
+  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 years of work
-is: 2^(N-1)*50/60/24/365 (Not adjusted for moore's law.)
+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
-* Weak password (30 entropy): 51072
-* Super-weak password (19 entropy): 25
+* Strong password (50 entropy): 53553077761 CPU-years
+* Weak password (30 entropy): 51072 CPU-years
+* Super-weak password (19 entropy): 25 CPU-years
 
-## Attack methods
-
-(Assuming rainbow tables won't be of use due to the salting.)
+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.
 
-An attacker who wants to target a particular person with a known keyid can
-guess their N1-N3, download two of S1-S3 and start brute forcing the
-password soon after the object is stored.
+## Attack methods
 
-If a gpg key is not published to keyservers, the attacker is unlikely to
-know its keyid, and so this method skips over such keys. And if the name
-used to store the key is different than the name on the keyservers, this
-method will skip over it too.
+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 also
+helps.
 
 The sharding prevents a single malicious server from blindly 
 guessing weak passwords across its entire collection of objects.
-
-Two servers can collude to recombine shards. If recombining two shards
-yielded data which can 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, even if all users have super-weak passwords,
-this attack takes 2621440 years of CPU work to crack one.
+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 the right one. Multiply by 5 years for cracking only super-weak
-passwords.
+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 with a known keyid
+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
@@ -147,9 +153,9 @@ 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 (562 trillion CPU years). So, a state-level entity
-will probably only find it feasible to target particular people with known
-keyids. Since such an attack can be performed by anyone as discussed above,
+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

Added a comment: Great!!
diff --git a/blog/entry/git-annex_v6/comment_2_4ab849a23713470fb99e4bd688056d8b._comment b/blog/entry/git-annex_v6/comment_2_4ab849a23713470fb99e4bd688056d8b._comment
new file mode 100644
index 0000000..9732dbb
--- /dev/null
+++ b/blog/entry/git-annex_v6/comment_2_4ab849a23713470fb99e4bd688056d8b._comment
@@ -0,0 +1,10 @@
+[[!comment format=mdwn
+ username="Oliver@5ecb9875ed5bbd2b3e48407518c07a27d754571c"
+ nickname="Oliver"
+ subject="Great!!"
+ date="2016-08-15T10:22:08Z"
+ content="""
+Wow, I've been folowing git-annex from the beginning. First I thought it is way to complicated. Thus I tried to find a different way to solve my needs. After thinking about it really hard I came to the concolusion that a system that solve all my needs has to be as complicated as git annex. Now I just discovered version 6 and largefiles with mimetype support (https://git-annex.branchable.com/tips/largefiles/). This solution still fullfills all my needs and now it is easy to use, too. Just great! Thank you very much! You really superseeded git lfs.
+Best regards
+Oliver
+"""]]

add news item for moreutils 0.60
diff --git a/code/moreutils/news/version_0.55.mdwn b/code/moreutils/news/version_0.55.mdwn
deleted file mode 100644
index dfe7d60..0000000
--- a/code/moreutils/news/version_0.55.mdwn
+++ /dev/null
@@ -1,6 +0,0 @@
-moreutils 0.55 released with [[!toggle text="these changes"]]
-[[!toggleable text="""
-   * parallel: serialise output through internal pipe. Closes: #[704125](http://bugs.debian.org/704125)
-     Thanks, Nicolas Schier.
-   * sponge: add append option '-a'. Closes: #[623197](http://bugs.debian.org/623197)
-     Thanks, Nicolas Schier."""]]
\ No newline at end of file
diff --git a/code/moreutils/news/version_0.60.mdwn b/code/moreutils/news/version_0.60.mdwn
new file mode 100644
index 0000000..51cfb60
--- /dev/null
+++ b/code/moreutils/news/version_0.60.mdwn
@@ -0,0 +1,16 @@
+moreutils 0.60 released with [[!toggle text="these changes"]]
+[[!toggleable text="""
+   * New implementation of isutf8 by Julien Palard.
+     - Noncharacters (ending with 0xFFFF and 0xFFFE) were considered
+       invalid when encoded in utf8, according to the unicode standard
+       they are valid: "However, they are not illegal in interchange, nor
+       does their presence cause Unicode text to be ill-formed."
+     - \xf4\xbf\xbf\xbf was considered valid UTF8, which is not: after
+       0xF4 the following byte should be between 80 and 8F.
+     - This implementation does not try to decode the stream, so it checks
+       it faster.
+     - Add --list option. Closes: #[691330](http://bugs.debian.org/691330)
+   * Support bullding in Cygwin.
+     Thanks, StalkR
+   * OSX build fix.
+     Thanks, Tony Kelman."""]]
\ No newline at end of file

put P in the salt
name is pretty low entropy, so putting P there will make rainbow
tables 256 times as expensive.
diff --git a/code/keysafe.mdwn b/code/keysafe.mdwn
index 0cf1782..dbc8e4e 100644
--- a/code/keysafe.mdwn
+++ b/code/keysafe.mdwn
@@ -54,7 +54,7 @@ and the password.
 * 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+P, salt=name), tuned to take 0.195 minutes.
+* 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
@@ -74,7 +74,7 @@ So, storing a key takes 10 minutes.
 * Request N1-N3 from servers until two objects are available.
 * Shamir recombine the objects.
 * Guess a value for P.
-* Generate K by argon2(password+P, salt=name)
+* Generate K by argon2(password, salt=name+P)
 * AES decrypt
 * Repeat with new P until checksum verifies.
 
@@ -87,7 +87,7 @@ average of 35 minutes.
 * Assume we know the name.
 * Guess a password.
 * For each possible value of P, AES decrypt with
-  argon2(password+P, salt=name), and check if checksum verifies.
+  argon2(password, salt=name+P), and check if checksum verifies.
 * Repeat for next password
 
 So, for a password with N entropy, the number of years of work
@@ -340,7 +340,7 @@ Worth comparing the sharding approach with the most secure and simple
 non-sharded approach I can think of:
 
 * Generate decryption puzzle P, a byte chosen at random.
-* Generate K by argon2(password+P, salt=name), tuned to take 0.195 minutes.
+* Generate K by argon2(password, salt=name+P), tuned to take 0.195 minutes.
 * AES encrypt (data + checksum) with K as the key.
 * upload to diverse locations using the gpg keyid as a unique ID
   (with some complication to handle objects maliciously uploaded using

improved decryption puzzle approach
diff --git a/code.mdwn b/code.mdwn
index ee38075..ba9ad89 100644
--- a/code.mdwn
+++ b/code.mdwn
@@ -7,6 +7,7 @@ The stuff that's swapped into my local cache at the moment.
 
 [[git-annex]]
 [[propellor]]
+[[keysafe]]
 [[concurrent-output]]
 [[myrepos|mr]]
 [[etckeeper]]
diff --git a/code/keysafe.mdwn b/code/keysafe.mdwn
index adbe504..0cf1782 100644
--- a/code/keysafe.mdwn
+++ b/code/keysafe.mdwn
@@ -51,11 +51,11 @@ and the password.
 * Input password and name from user.
 * Get the keyid of the key. (This can be any a public value
   unique to the private key, eg a gpg keyid.)
-* Generate K by argon2(password, salt=name), tuned to take 10 minutes.
 * Generate N by argon2(name, salt=keyid), tuned to take 10 minutes.
 * Generate N1-N3 by sha256 of N+1,2,3
-* Generate random R
-* AES encrypt (data + checksum) with (K|R) as the key.
+* Generate decryption puzzle P, a byte chosen at random.
+* Generate K by argon2(password+P, salt=name), 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.
@@ -65,37 +65,37 @@ and the password.
   If any of the uploads is rejected as name already in use, 
   ask user to enter a different name or password.
 
-R needs to be in a range tuned so that AES needs to decrypt data for
-at least 1 minute on a GPU. Hopefully on a CPU the decrypt time
-will be less than an hour.
-
-(Alternatively, use a tunable client puzzle to encode R.
-Store the puzzle alongside the encrypted data.
-Use Argon2, which is GPU and ASIC resistent.
-Probably more on the order of 10 minutes per CPU core for this approach.)
+So, storing a key takes 10 minutes.
 
 ## Recovering a key
 
 * Input password and name from user.
-* Generate K, N1-N3 as above.
+* Calculate N and N1-N2
 * Request N1-N3 from servers until two objects are available.
 * Shamir recombine the objects.
-* Guess R and AES decrypt, repeating until checksum verifies.
+* Guess a value for P.
+* Generate K by argon2(password+P, salt=name)
+* 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.
 * Guess a password.
-* K = argon2(password, salt=name) -- 10 minutes CPU work
-* AES decrypt with (K+R) forall R -- 1 minute GPU work
-* Repeat for next password.
+* For each possible value of P, AES decrypt with
+  argon2(password+P, salt=name), and check if checksum verifies.
+* Repeat for next password
 
-So, for password with N entropy, the number of years of work
-is: 2^(N-1)*11/60/24/365 (Not adjusted for moore's law.)
+So, for a password with N entropy, the number of years of work
+is: 2^(N-1)*50/60/24/365 (Not adjusted for moore's law.)
 
-* Strong password (50 entropy): 11781677107
-* Weak password (30 entropy): 11235
-* Super-weak password (19 entropy): 5 years
+* Strong password (50 entropy): 53553077761
+* Weak password (30 entropy): 51072
+* Super-weak password (19 entropy): 25
 
 ## Attack methods
 
@@ -306,86 +306,6 @@ 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.
 
-## maybe use tunable work puzzles (instead of more expensive AES decryption)
-
-I stumbled upon this interesting paper on tunable proof of work puzzles
-that can expose information when solved:
-<https://www1.ericsson.com/res/docs/2015/random-access-procedure.pdf>  
-(With a low probabiliy of finding a bad solution.)
-
-That's effectively a way to encrypt data such that decryption takes a
-tunable amount of work.
-
-The puzzle is basically generated by:
-
-	F(k || d || r)
-
-Where F is a cryptographic function, k is a secret value, d is a difficutly
-bit string, and r is the result exposed by solving the puzzle.
-
-This could be used to encrypt shards. The decrypted 
-shard is r, and for k, use part of the password's entropy pool.
-
-The same k can be reused to encrypt *all* shards. So, the entropy pool
-is not split up between the shards.
-
-To decrypt a shard, keysafe would only need to solve the puzzle once,
-because it knows k. In the rare case when it finds a bad solution, it would
-notice when checking the validity of the combined shards, and it would
-then need to resume looking for a solution.
-
-A brute force shard decryption attack (that has not cracked the
-namesecret) would have to guess values for k (or guess passwords and
-derive k) and solve the puzzle repeatedly. The puzzle can be tuned so
-that this takes infeasibly long.
-
-An attacker who has already brute forced the namesecret can make
-educated guesses about the entropy pool, and k, so this
-won't slow them down as much.
-
-## more expensive AES decryption
-
-Idea from Anthony Towns
-
-> Hmm, interesting. Can you do this a bit more simply though? I'm
-> thinking:
-> 
->  * secret key is 16kB
->  * user decides "i'm willing to spend 1 hour of CPU on decryption"
->  * AES speed is ~110MB/second, so 360GB/hour which gives about 2**24
->    secret key decryptions
-
-(Really AES can be much faster, 3-7 GB/s on CPUs and there is GPU
-accelleration, so this needs tuning..)
-
->  * choose a random number 24 bit number, R, stored in a 64 bit unsigned
->    int
-> 
->  * set secret key,
->       S = sha256( R || slowhash( "ajt@debian.org" A B C X "gpg" ))
->  * encrypt the gpg secret key data as:
->       E_S( SHA256( data ); data )
->  * shard the encrypted gpg secret key data, etc
-> 
-> Then after reassembling the shards, and knowing A,B and X, but
-> bruteforcing each possible C, you not only have to run the slowhash, but
-> you have to do 360GB's of trial decryption as well.
-> 
-> The above has the drawback that if one of the shards is corrupted, you'll
-> have to do three hours of trial decryption to work out which one it was
-> though. You could mitigate that by adding a per-shard checksum:
-> 
->     ID_n = sha256( "name" CHK_n )
->     CHK_n = slowhash( "chk" A X "ajt@debian.org" "gpg" )
-> 
->     object_n = SHARD + HMAC( CHK_n, SHARD )
-> 
-> That avoids any increase in the setup time, means that you can only fake
-> the checksum by discovering A and X (and performing a slowhash on them)
-> or breaking sha256, and doesn't provide any easier ways to brute force
-> things than figuring out a preimage for the object id. So yeah, I think
-> that works.
-
 ## maybe use blind signatures
 
 > I think you could use [blind signatures](https://en.wikipedia.org/wiki/Blind_signature) 
@@ -419,24 +339,24 @@ Reading the key from gpg into locked memory is the other challenge.
 Worth comparing the sharding approach with the most secure and simple
 non-sharded approach I can think of:
 
-* Generate K by argon2(password, salt=name)
-* Generate random R (same method as in the sharded approach).
-* AES encrypt (data + checksum) with (K|R) as the key.
+* Generate decryption puzzle P, a byte chosen at random.
+* Generate K by argon2(password+P, salt=name), tuned to take 0.195 minutes.
+* AES encrypt (data + checksum) with K as the key.
 * upload to diverse locations using the gpg keyid as a unique ID
   (with some complication to handle objects maliciously uploaded using
   the same ID)
 
-The key encryption is the same in this approach, so the difficulty in brute
-forcing an encrypted key is the same as described above. Brute-forcing
-is only feasible for weak passwords.
+The key encryption is the same as keysafe in this approach, so the
+difficulty in brute forcing an encrypted key is the same as described
+above. Brute-forcing is only feasible for weak passwords.
 
-Brute forcing can start right away, and be performed by anyone,
+But brute forcing can start right away, and be performed by anyone,
 unlike with sharding where only two colluding servers can start brute
 forcing right away.
 

(Diff truncated)
Revert "puzzle IV"
This reverts commit aa44bcfc1a339ee904995e3e3a3ed2a7a567be63.
Not a good idea to use IV, because all the parts of the IV that are 0
will not obscure the data in the first block at all.
diff --git a/code/keysafe.mdwn b/code/keysafe.mdwn
index c0e4026..adbe504 100644
--- a/code/keysafe.mdwn
+++ b/code/keysafe.mdwn
@@ -54,11 +54,8 @@ and the password.
 * Generate K by argon2(password, salt=name), tuned to take 10 minutes.
 * Generate N by argon2(name, salt=keyid), tuned to take 10 minutes.
 * Generate N1-N3 by sha256 of N+1,2,3
-* Generate IV, which is an AES IV consisting of some number of random
-  bytes followed by NULLs. This should be tuned so that AES
-  needs to decrypt data for at least 1 minute on a GPU to guess it.
-  Hopefully on a CPU the decrypt time will be less than an hour.
-* AES encrypt (data + checksum) with K as the key.
+* Generate random R
+* AES encrypt (data + checksum) with (K|R) 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.
@@ -68,10 +65,14 @@ and the password.
   If any of the uploads is rejected as name already in use, 
   ask user to enter a different name or password.
 
-(Alternatively, instead of a random IV, use a tunable client puzzle to
-encode K. Store the puzzle alongside the encrypted data. Use Argon2, which
-is GPU and ASIC resistent. Probably more on the order of 10 minutes per CPU
-core for this approach.)
+R needs to be in a range tuned so that AES needs to decrypt data for
+at least 1 minute on a GPU. Hopefully on a CPU the decrypt time
+will be less than an hour.
+
+(Alternatively, use a tunable client puzzle to encode R.
+Store the puzzle alongside the encrypted data.
+Use Argon2, which is GPU and ASIC resistent.
+Probably more on the order of 10 minutes per CPU core for this approach.)
 
 ## Recovering a key
 
@@ -385,11 +386,6 @@ accelleration, so this needs tuning..)
 > things than figuring out a preimage for the object id. So yeah, I think
 > that works.
 
-Now keysafe is using a simpler approach to the same idea: The IV used in AES
-encryption is not stored, and so must be guessed to decrypt data.
-The initial several bytes of the IV are random and the rest NULL,
-which allows tuning the amount of work that must be done.
-
 ## maybe use blind signatures
 
 > I think you could use [blind signatures](https://en.wikipedia.org/wiki/Blind_signature) 

puzzle IV
diff --git a/code/keysafe.mdwn b/code/keysafe.mdwn
index adbe504..c0e4026 100644
--- a/code/keysafe.mdwn
+++ b/code/keysafe.mdwn
@@ -54,8 +54,11 @@ and the password.
 * Generate K by argon2(password, salt=name), tuned to take 10 minutes.
 * Generate N by argon2(name, salt=keyid), tuned to take 10 minutes.
 * Generate N1-N3 by sha256 of N+1,2,3
-* Generate random R
-* AES encrypt (data + checksum) with (K|R) as the key.
+* Generate IV, which is an AES IV consisting of some number of random
+  bytes followed by NULLs. This should be tuned so that AES
+  needs to decrypt data for at least 1 minute on a GPU to guess it.
+  Hopefully on a CPU the decrypt time will be less than an hour.
+* 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.
@@ -65,14 +68,10 @@ and the password.
   If any of the uploads is rejected as name already in use, 
   ask user to enter a different name or password.
 
-R needs to be in a range tuned so that AES needs to decrypt data for
-at least 1 minute on a GPU. Hopefully on a CPU the decrypt time
-will be less than an hour.
-
-(Alternatively, use a tunable client puzzle to encode R.
-Store the puzzle alongside the encrypted data.
-Use Argon2, which is GPU and ASIC resistent.
-Probably more on the order of 10 minutes per CPU core for this approach.)
+(Alternatively, instead of a random IV, use a tunable client puzzle to
+encode K. Store the puzzle alongside the encrypted data. Use Argon2, which
+is GPU and ASIC resistent. Probably more on the order of 10 minutes per CPU
+core for this approach.)
 
 ## Recovering a key
 
@@ -386,6 +385,11 @@ accelleration, so this needs tuning..)
 > things than figuring out a preimage for the object id. So yeah, I think
 > that works.
 
+Now keysafe is using a simpler approach to the same idea: The IV used in AES
+encryption is not stored, and so must be guessed to decrypt data.
+The initial several bytes of the IV are random and the rest NULL,
+which allows tuning the amount of work that must be done.
+
 ## maybe use blind signatures
 
 > I think you could use [blind signatures](https://en.wikipedia.org/wiki/Blind_signature) 

typo
diff --git a/blog/entry/keysafe/comment_5_5ea418b81e02998683f51da2bae91c08._comment b/blog/entry/keysafe/comment_5_5ea418b81e02998683f51da2bae91c08._comment
index 40bd9e3..395222b 100644
--- a/blog/entry/keysafe/comment_5_5ea418b81e02998683f51da2bae91c08._comment
+++ b/blog/entry/keysafe/comment_5_5ea418b81e02998683f51da2bae91c08._comment
@@ -10,7 +10,7 @@ I can only increment that number here by overwriting my original
 
 "mom123" was being used internally as an rough example of a 19 bit entropy
 password, calculated per Shannon, so without using a dictionary. It should
-not have leaked out into the user-visible part of the ocumentation.
+not have leaked out into the user-visible part of the documentation.
 
 And of course it's referring to the time needed to crack the password
 in the context of keysafe, not time to crack it in the context of having a

reword
diff --git a/blog/entry/keysafe/comment_5_5ea418b81e02998683f51da2bae91c08._comment b/blog/entry/keysafe/comment_5_5ea418b81e02998683f51da2bae91c08._comment
index 937722f..40bd9e3 100644
--- a/blog/entry/keysafe/comment_5_5ea418b81e02998683f51da2bae91c08._comment
+++ b/blog/entry/keysafe/comment_5_5ea418b81e02998683f51da2bae91c08._comment
@@ -4,14 +4,13 @@
  date="2016-08-11T23:11:07Z"
  content="""
 @alkadim, I wonder what number of all the conversations that have
-included accusations have gone on to be constructive? I can only increment
-that number here by overwriting my original (predictively defensive)
-response.
+included accusations of snakeoil have gone on to be constructive?
+I can only increment that number here by overwriting my original
+(predictively defensive) response.
 
-"mom123" was being used internally as an example of a 19 bit entropy
-password, calculated per Shannon, so without using a dictionary.
-It should not have leaked out into the user-visible part of the
-ocumentation. Of course the document is a draft anyway.
+"mom123" was being used internally as an rough example of a 19 bit entropy
+password, calculated per Shannon, so without using a dictionary. It should
+not have leaked out into the user-visible part of the ocumentation.
 
 And of course it's referring to the time needed to crack the password
 in the context of keysafe, not time to crack it in the context of having a

improve password strengh descriptions
diff --git a/code/keysafe.mdwn b/code/keysafe.mdwn
index 1d75fe3..adbe504 100644
--- a/code/keysafe.mdwn
+++ b/code/keysafe.mdwn
@@ -35,12 +35,13 @@ the key.
 
 A password is used to encrypt the key. Using a strong password is highly
 recommended, especially for well-known keys. Brute forcing a strong
-password is infeasible with keysafe. Weaker passwords still take years
-to brute force.
+password is infeasible with keysafe. Keysafe is designed so that
+even a well-chosen 8 letter long password protects a key for years. Basing
+passwords on dictionary words of course makes them much easier to crack.
 
 If your gpg key ID is not published to keyservers or elsewhere,
 it's very unlikely any attacker will find the encrypted key that keysafe
-stores, let alone devote years of work to crack this unknown key.
+stores, let alone devote years of work to cracking this unknown key.
 
 All you need to recover the key is the --name you used when backing it up,
 and the password.
@@ -92,8 +93,8 @@ Probably more on the order of 10 minutes per CPU core for this approach.)
 So, for password with N entropy, the number of years of work
 is: 2^(N-1)*11/60/24/365 (Not adjusted for moore's law.)
 
-* Strong password (50 entropy): 11781677107 years
-* Weak password (30 entropy): 11235 years
+* Strong password (50 entropy): 11781677107
+* Weak password (30 entropy): 11235
 * Super-weak password (19 entropy): 5 years
 
 ## Attack methods

tune down
diff --git a/blog/entry/keysafe/comment_5_5ea418b81e02998683f51da2bae91c08._comment b/blog/entry/keysafe/comment_5_5ea418b81e02998683f51da2bae91c08._comment
index eb5197a..937722f 100644
--- a/blog/entry/keysafe/comment_5_5ea418b81e02998683f51da2bae91c08._comment
+++ b/blog/entry/keysafe/comment_5_5ea418b81e02998683f51da2bae91c08._comment
@@ -3,17 +3,18 @@
  subject="""comment 5"""
  date="2016-08-11T23:11:07Z"
  content="""
-@alkadim, of course it's referring to the time needed to crack the password
-in the context of keysafe. Ie, each try involves the expensive process of
-deriving an AES key (say 10 CPU-minutes), and once the key is derived it's
-also made expensive to use the key (say 1 GPU-minute).
+@alkadim, I wonder what number of all the conversations that have
+included accusations have gone on to be constructive? I can only increment
+that number here by overwriting my original (predictively defensive)
+response.
 
-Password entropy calculation is not a very exact science, so of
-course an example like "mom123" assumes "mom" and "123" are not in the
-dictionary. In which case I think its entropy would be somewhere around 19
-bits. Of course they are in the dictionary in real life. "9ibz02" would be
-a better example of a password that really probably has an entropy of ~15-19.
+"mom123" was being used internally as an example of a 19 bit entropy
+password, calculated per Shannon, so without using a dictionary.
+It should not have leaked out into the user-visible part of the
+ocumentation. Of course the document is a draft anyway.
 
-(Assusing in-progress design drafts of being snake oil is probably not the
-most constructuve look.)
+And of course it's referring to the time needed to crack the password
+in the context of keysafe, not time to crack it in the context of having a
+password file or something. The document explains why each password
+guess involves a 10 CPU-minute calculation and a 1 GPU-minute calculation.
 """]]

remove the mom123 example because it was too confusing
diff --git a/blog/entry/keysafe/comment_5_5ea418b81e02998683f51da2bae91c08._comment b/blog/entry/keysafe/comment_5_5ea418b81e02998683f51da2bae91c08._comment
new file mode 100644
index 0000000..eb5197a
--- /dev/null
+++ b/blog/entry/keysafe/comment_5_5ea418b81e02998683f51da2bae91c08._comment
@@ -0,0 +1,19 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 5"""
+ date="2016-08-11T23:11:07Z"
+ content="""
+@alkadim, of course it's referring to the time needed to crack the password
+in the context of keysafe. Ie, each try involves the expensive process of
+deriving an AES key (say 10 CPU-minutes), and once the key is derived it's
+also made expensive to use the key (say 1 GPU-minute).
+
+Password entropy calculation is not a very exact science, so of
+course an example like "mom123" assumes "mom" and "123" are not in the
+dictionary. In which case I think its entropy would be somewhere around 19
+bits. Of course they are in the dictionary in real life. "9ibz02" would be
+a better example of a password that really probably has an entropy of ~15-19.
+
+(Assusing in-progress design drafts of being snake oil is probably not the
+most constructuve look.)
+"""]]
diff --git a/code/keysafe.mdwn b/code/keysafe.mdwn
index a6bee3c..1d75fe3 100644
--- a/code/keysafe.mdwn
+++ b/code/keysafe.mdwn
@@ -35,8 +35,8 @@ the key.
 
 A password is used to encrypt the key. Using a strong password is highly
 recommended, especially for well-known keys. Brute forcing a strong
-password is infeasible with keysafe. Even a weak password like
-"mom123" takes 1 year of GPU time to brute force.
+password is infeasible with keysafe. Weaker passwords still take years
+to brute force.
 
 If your gpg key ID is not published to keyservers or elsewhere,
 it's very unlikely any attacker will find the encrypted key that keysafe
@@ -94,7 +94,7 @@ is: 2^(N-1)*11/60/24/365 (Not adjusted for moore's law.)
 
 * Strong password (50 entropy): 11781677107 years
 * Weak password (30 entropy): 11235 years
-* Super-weak password (19 entropy) (eg "mom123"): 5 years
+* Super-weak password (19 entropy): 5 years
 
 ## Attack methods
 

more on attacks
diff --git a/code/keysafe.mdwn b/code/keysafe.mdwn
index 36150cb..a6bee3c 100644
--- a/code/keysafe.mdwn
+++ b/code/keysafe.mdwn
@@ -102,10 +102,7 @@ is: 2^(N-1)*11/60/24/365 (Not adjusted for moore's law.)
 
 An attacker who wants to target a particular person with a known keyid can
 guess their N1-N3, download two of S1-S3 and start brute forcing the
-encryption soon after the object is stored. However, it's hard for an
-attacker to discover all objects stored on a server. This protects
-uninteresting users who used weak passwords, because they are unlikely to
-become a target for cracking.
+password soon after the object is stored.
 
 If a gpg key is not published to keyservers, the attacker is unlikely to
 know its keyid, and so this method skips over such keys. And if the name
@@ -116,23 +113,51 @@ The sharding prevents a single malicious server from blindly
 guessing weak passwords across its entire collection of objects.
 
 Two servers can collude to recombine shards. If recombining two shards
-yields data which can be checked to see if it's valid, then
-it becomes fairly inexpensive to try all combinations of shards, and
+yielded data which can 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
+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.)
-
-Or colluding servers can try to likely correlate related objects and
-recombine pairs of those. The more users use keysafe, the harder
-this becomes.
-
-(Note that it's easy to determine an object's shard number,
-which reduces the difficulty of a recombination attack by 2^3.)
+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, even if all users have super-weak passwords,
+this attack takes 2621440 years of CPU work to crack one.
+
+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 the right one. Multiply by 5 years for cracking only super-weak
+passwords.
+
+Colluding servers who want to target a particular person with a known keyid
+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 (562 trillion CPU years). So, a state-level entity
+will probably only find it feasible to target particular people with known
+keyids. 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.
+deny them access to it. Or, to entirely take down storage servers.
 
 ### Malicious data attack
 
@@ -218,8 +243,9 @@ Ways the server could draw correlations include:
   (Avoid by waiting some period of time between retrieving shards.
   Although, this makes key recovery take longer, which could be
   frustrating..)
-* Any user ID associated with the data.  
-  (Avoid by allowing anyone to store data and don't associate data with any user ID.)
+* 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.)
 

Added a comment: Brute-forcing-related claims
diff --git a/blog/entry/keysafe/comment_4_3cc9b708e48c3cb660037478cb738990._comment b/blog/entry/keysafe/comment_4_3cc9b708e48c3cb660037478cb738990._comment
new file mode 100644
index 0000000..701eeba
--- /dev/null
+++ b/blog/entry/keysafe/comment_4_3cc9b708e48c3cb660037478cb738990._comment
@@ -0,0 +1,18 @@
+[[!comment format=mdwn
+ username="alkadim@16dbdbfdb5d7aee5bbfeaa6d1a393f900cd6b341"
+ nickname="alkadim"
+ subject="Brute-forcing-related claims"
+ date="2016-08-11T19:07:37Z"
+ content="""
+I was surprised to read the following snake-oily statement:
+
+> Even a weak password like \"mom123\" takes 1 year of GPU time to brute force.
+
+Upon reading that I thought that maybe you were referring not to the weak password, but to the derived key itself (though, that didn't make that much sense either).
+
+But then I saw this:
+
+> Super-weak password (19 entropy) (eg \"mom123\"): 5 years
+
+Excuse me, but \"19 entropy\"? 19 bogons of entropy perhaps. Because \"mom123\" sure as hell does not have anywhere near 19 bits of entropy. In particular, for the case in question, that of password-cracking, it's much closer to 0. Also, things like that are in every dictionary and dictionary generator out there. So making claims about brute-force-resistance based on some foobar entropy count make no sense in my opinion.
+"""]]

update
diff --git a/code/keysafe.mdwn b/code/keysafe.mdwn
index c7b59d7..36150cb 100644
--- a/code/keysafe.mdwn
+++ b/code/keysafe.mdwn
@@ -49,10 +49,10 @@ and the password.
 
 * Input password and name from user.
 * Get the keyid of the key. (This can be any a public value
-  unique to the private key.)
+  unique to the private key, eg a gpg keyid.)
 * Generate K by argon2(password, salt=name), tuned to take 10 minutes.
-* Generate N1-N3 by argon2(name, salt=I+keyid), tuned to take 10 minutes.
-  (Where I is 1,2,3)
+* Generate N by argon2(name, salt=keyid), tuned to take 10 minutes.
+* Generate N1-N3 by sha256 of N+1,2,3
 * Generate random R
 * AES encrypt (data + checksum) with (K|R) as the key.
 * Shamir the encrypted key with N=2, M=3, yeilding S1-S3.
@@ -410,3 +410,8 @@ forcing right away.
 So, this isn't too bad, but for all the users who use weak passwords
 (you know who you are (yes, you)), it's not as good a choice as sharding.
 At worst, sharding degrades to being as secure as this approach.
+
+## Thanks
+
+Thanks to Anthony Towns for his help reviewing the security properties of
+keysafe.

will probably I ++ keyid, not OR
diff --git a/code/keysafe.mdwn b/code/keysafe.mdwn
index 31ecb86..c7b59d7 100644
--- a/code/keysafe.mdwn
+++ b/code/keysafe.mdwn
@@ -51,7 +51,7 @@ and the password.
 * Get the keyid of the key. (This can be any a public value
   unique to the private key.)
 * Generate K by argon2(password, salt=name), tuned to take 10 minutes.
-* Generate N1-N3 by argon2(name, salt=I|keyid), tuned to take 10 minutes.
+* Generate N1-N3 by argon2(name, salt=I+keyid), tuned to take 10 minutes.
   (Where I is 1,2,3)
 * Generate random R
 * AES encrypt (data + checksum) with (K|R) as the key.

update
diff --git a/code/keysafe.mdwn b/code/keysafe.mdwn
index 06e1ef1..31ecb86 100644
--- a/code/keysafe.mdwn
+++ b/code/keysafe.mdwn
@@ -48,11 +48,11 @@ and the password.
 ## Storing a key
 
 * Input password and name from user.
-* Get the keyident of the key. (This can be any a public value
+* Get the keyid of the key. (This can be any a public value
   unique to the private key.)
 * Generate K by argon2(password, salt=name), tuned to take 10 minutes.
-* Generate N by argon2(name, salt=keyid), tuned to take 10 minutes.
-* Generate N1-N2 by sha256("N keyident")
+* Generate N1-N3 by argon2(name, salt=I|keyid), tuned to take 10 minutes.
+  (Where I is 1,2,3)
 * Generate random R
 * AES encrypt (data + checksum) with (K|R) as the key.
 * Shamir the encrypted key with N=2, M=3, yeilding S1-S3.

fix some typos and clarify a few things
diff --git a/code/keysafe.mdwn b/code/keysafe.mdwn
index 054166b..06e1ef1 100644
--- a/code/keysafe.mdwn
+++ b/code/keysafe.mdwn
@@ -48,10 +48,13 @@ and the password.
 ## Storing a key
 
 * Input password and name from user.
+* Get the keyident of the key. (This can be any a public value
+  unique to the private key.)
 * Generate K by argon2(password, salt=name), tuned to take 10 minutes.
-* Generate N1-N3 by argon2(keyid, salt=I|name), tuned to take 10 minutes.
+* Generate N by argon2(name, salt=keyid), tuned to take 10 minutes.
+* Generate N1-N2 by sha256("N keyident")
 * Generate random R
-* AES encrypt (data + checksum) with (K+R) as the key.
+* AES encrypt (data + checksum) with (K|R) 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.
@@ -95,7 +98,7 @@ is: 2^(N-1)*11/60/24/365 (Not adjusted for moore's law.)
 
 ## Attack methods
 
-(Assuming rainbow tables won't be of use due to the name salting.)
+(Assuming rainbow tables won't be of use due to the salting.)
 
 An attacker who wants to target a particular person with a known keyid can
 guess their N1-N3, download two of S1-S3 and start brute forcing the

atime
diff --git a/code/keysafe.mdwn b/code/keysafe.mdwn
index a5f9033..054166b 100644
--- a/code/keysafe.mdwn
+++ b/code/keysafe.mdwn
@@ -168,7 +168,8 @@ 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.)
+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

safe versioning scheme via varying argon2 parameters
diff --git a/code/keysafe.mdwn b/code/keysafe.mdwn
index a030d75..a5f9033 100644
--- a/code/keysafe.mdwn
+++ b/code/keysafe.mdwn
@@ -131,6 +131,23 @@ 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.
 
+### 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
@@ -150,6 +167,9 @@ 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.)
+
 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.
@@ -175,7 +195,7 @@ replies with a
 that the client must solve to make that request.
 This can be used by servers to avoid DOS attacks.
 
-### Avoiding correlations
+## Avoiding correlations
 
 As noted above, the more objects that are stored, the more secure
 keysafe becomes, because it becomes harder to correlate objects
@@ -199,7 +219,7 @@ Ways the server could draw correlations include:
 * Same sized objects may be related shares.  
   (Avoid by making all objects stored be a standard size.)
 
-### Detecting corrupt data
+## 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
@@ -217,24 +237,45 @@ 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.
 
-### 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.
-
-### maybe use tunable work puzzles (instead of more expensive AES decryption)
+## 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.
+
+## maybe use tunable work puzzles (instead of more expensive AES decryption)
 
 I stumbled upon this interesting paper on tunable proof of work puzzles
 that can expose information when solved:
@@ -271,7 +312,7 @@ An attacker who has already brute forced the namesecret can make
 educated guesses about the entropy pool, and k, so this
 won't slow them down as much.
 
-### more expensive AES decryption
+## more expensive AES decryption
 
 Idea from Anthony Towns
 
@@ -314,7 +355,7 @@ accelleration, so this needs tuning..)
 > things than figuring out a preimage for the object id. So yeah, I think
 > that works.
 
-### maybe use blind signatures
+## maybe use blind signatures
 
 > I think you could use [blind signatures](https://en.wikipedia.org/wiki/Blind_signature) 
 > to allow paying for

note that encrypted data must be undistinguishable from random data
diff --git a/code/keysafe.mdwn b/code/keysafe.mdwn
index 0fe677c..a030d75 100644
--- a/code/keysafe.mdwn
+++ b/code/keysafe.mdwn
@@ -104,24 +104,28 @@ attacker to discover all objects stored on a server. This protects
 uninteresting users who used weak passwords, because they are unlikely to
 become a target for cracking.
 
+If a gpg key is not published to keyservers, the attacker is unlikely to
+know its keyid, and so this method skips over such keys. And if the name
+used to store the key is different than the name on the keyservers, this
+method will skip over it too.
+
 The sharding prevents a single malicious server from blindly 
 guessing weak passwords across its entire collection of objects.
 
-Two servers can collude to recombine shards, but to determine which shards
-belong together, have to use argon2 with a keyid and name, which takes 10
-minutes per attempt. This slows down blindly guessing weak passwords some,
-because it will take the attacker some time to generate a collection of
-recombined objects to check. More importantly if a gpg key is not published
-to keyservers, the attacker is unlikely to know its keyid, and so this
-method skips over such keys. And if the name used to store the key is
-different than the name on the keyservers, this method will skip over it
-too.
+Two servers can collude to recombine shards. If recombining two shards
+yields data which can be checked to see if it's valid, then
+it becomes 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.)
 
 Or colluding servers can try to likely correlate related objects and
 recombine pairs of those. The more users use keysafe, the harder
-this becomes. Note that it's easy to determine an object's shard number
-(combining it with an unrelated shard with the name number will
-yeild all 0's), which reduces the difficulty of a correlation attack by 2^3.
+this becomes.
+
+(Note that it's easy to determine an object's shard number,
+which reduces the difficulty of a recombination attack by 2^3.)
 
 A different kind of attack: Legal/extralegal action to get a 
 particular person's key removed from storage servers to try to

shard number can be determined
diff --git a/code/keysafe.mdwn b/code/keysafe.mdwn
index 80aa866..0fe677c 100644
--- a/code/keysafe.mdwn
+++ b/code/keysafe.mdwn
@@ -62,8 +62,8 @@ and the password.
   ask user to enter a different name or password.
 
 R needs to be in a range tuned so that AES needs to decrypt data for
-at least 1 minute with some large number of GPUs. Hopefully on a CPU
-the decrypt time will be less than an hour.
+at least 1 minute on a GPU. Hopefully on a CPU the decrypt time
+will be less than an hour.
 
 (Alternatively, use a tunable client puzzle to encode R.
 Store the puzzle alongside the encrypted data.
@@ -119,7 +119,9 @@ too.
 
 Or colluding servers can try to likely correlate related objects and
 recombine pairs of those. The more users use keysafe, the harder
-this becomes.
+this becomes. Note that it's easy to determine an object's shard number
+(combining it with an unrelated shard with the name number will
+yeild all 0's), which reduces the difficulty of a correlation attack by 2^3.
 
 A different kind of attack: Legal/extralegal action to get a 
 particular person's key removed from storage servers to try to

update
diff --git a/code/keysafe.mdwn b/code/keysafe.mdwn
index 7a5c697..80aa866 100644
--- a/code/keysafe.mdwn
+++ b/code/keysafe.mdwn
@@ -48,7 +48,7 @@ and the password.
 ## Storing a key
 
 * Input password and name from user.
-* Generate K by argon2(password, salt=name)
+* Generate K by argon2(password, salt=name), tuned to take 10 minutes.
 * Generate N1-N3 by argon2(keyid, salt=I|name), tuned to take 10 minutes.
 * Generate random R
 * AES encrypt (data + checksum) with (K+R) as the key.
@@ -82,16 +82,16 @@ Probably more on the order of 10 minutes per CPU core for this approach.)
 
 * Assume we know the name.
 * Guess a password.
-* K = argon2(password, salt=name) -- 5 minutes CPU work
+* K = argon2(password, salt=name) -- 10 minutes CPU work
 * AES decrypt with (K+R) forall R -- 1 minute GPU work
 * Repeat for next password.
 
 So, for password with N entropy, the number of years of work
-is: 2^(N-1)*6/60/24/365 (Not adjusted for moore's law.)
+is: 2^(N-1)*11/60/24/365 (Not adjusted for moore's law.)
 
-* Strong password (50 entropy): 6426369331 years
-* Weak password (30 entropy): 6128 years
-* Super-weak password (19 entropy) (eg "mom123"): 2.5 years
+* Strong password (50 entropy): 11781677107 years
+* Weak password (30 entropy): 11235 years
+* Super-weak password (19 entropy) (eg "mom123"): 5 years
 
 ## Attack methods
 
@@ -324,6 +324,18 @@ accelleration, so this needs tuning..)
 
 -- Anthony Towns:
 
+## keep gpg keys locked in memory
+
+gpg secret keys should only exist in locked memory. So, keysafe
+should make sure that's always the case when encrypting and decrypting
+them. 
+
+Raaz supports AES of data that is in locked memory
+<http://cse.iitk.ac.in/users/ppk/posts/2016-08-02-Handling-Secure-Memory-in-Raaz.html>
+
+Reading the key from gpg into locked memory is the other challenge.
+<https://github.com/raaz-crypto/raaz/issues/263>
+
 ## Comparisons with other approaches
 
 Worth comparing the sharding approach with the most secure and simple

show work
diff --git a/code/keysafe.mdwn b/code/keysafe.mdwn
index 774fda9..7a5c697 100644
--- a/code/keysafe.mdwn
+++ b/code/keysafe.mdwn
@@ -6,6 +6,7 @@ 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 implemented! Needs security review! May run over your dog!
+Not suitable for bitcoin keys!
 
 ## Example
 
@@ -32,13 +33,14 @@ 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.
 
-A password is used to encrypt the key. For the servers to access your
-key, two of them need to collude together, and they then have to brute
-force the password. The design of keysafe makes brute forcing
-extra difficult by making it hard to know which shards belong to you.
+A password is used to encrypt the key. Using a strong password is highly
+recommended, especially for well-known keys. Brute forcing a strong
+password is infeasible with keysafe. Even a weak password like
+"mom123" takes 1 year of GPU time to brute force.
 
-Indeed the more people that use keysafe, the harder it becomes to
-brute-force anyone's key!
+If your gpg key ID is not published to keyservers or elsewhere,
+it's very unlikely any attacker will find the encrypted key that keysafe
+stores, let alone devote years of work to crack this unknown key.
 
 All you need to recover the key is the --name you used when backing it up,
 and the password.
@@ -49,7 +51,7 @@ and the password.
 * Generate K by argon2(password, salt=name)
 * Generate N1-N3 by argon2(keyid, salt=I|name), tuned to take 10 minutes.
 * Generate random R
-* AES encrypt (data + checksum) with (K|R) as the key.
+* AES encrypt (data + checksum) with (K+R) 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.
@@ -78,14 +80,18 @@ Probably more on the order of 10 minutes per CPU core for this approach.)
 
 ## Difficulty of brute forcing a single encrypted key
 
-With a strong password, brute forcing requires 2^50 argon2.
-And, aeons of GPU time for the AES decrypts. Infeasible.
+* Assume we know the name.
+* Guess a password.
+* K = argon2(password, salt=name) -- 5 minutes CPU work
+* AES decrypt with (K+R) forall R -- 1 minute GPU work
+* Repeat for next password.
 
-With a weak password, say 2^30 argon2, cost for those is $460K,
-plus 2042 years of GPU time. 
+So, for password with N entropy, the number of years of work
+is: 2^(N-1)*6/60/24/365 (Not adjusted for moore's law.)
 
-Even a super-weak 19 entropy password (eg "mom123") would need
-1 year of GPU time to crack.
+* Strong password (50 entropy): 6426369331 years
+* Weak password (30 entropy): 6128 years
+* Super-weak password (19 entropy) (eg "mom123"): 2.5 years
 
 ## Attack methods
 

new approach
diff --git a/code/keysafe.mdwn b/code/keysafe.mdwn
index 03bb613..774fda9 100644
--- a/code/keysafe.mdwn
+++ b/code/keysafe.mdwn
@@ -7,7 +7,7 @@ up and restore their key as they reinstall their laptop.
 
 Not yet implemented! Needs security review! May run over your dog!
 
-## example
+## Example
 
 	> keysafe --backup --name="email@example.com" --type=gpg
 	Password:
@@ -25,7 +25,7 @@ Not yet implemented! Needs security review! May run over your dog!
 
 	[also, imagine a GUI here]
 
-## how it works, basically
+## How it works, basically
 
 The secret key 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
@@ -43,161 +43,127 @@ brute-force anyone's key!
 All you need to recover the key is the --name you used when backing it up,
 and the password.
 
-## design
+## Storing a key
 
-### sharding
+* Input password and name from user.
+* Generate K by argon2(password, salt=name)
+* Generate N1-N3 by argon2(keyid, salt=I|name), tuned to take 10 minutes.
+* Generate random R
+* AES encrypt (data + checksum) with (K|R) 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 client puzzle 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.
 
-Shamir secret sharing is used to generate the shards of the key.
-By default three shards are made, and any two of them can recreate the key.
-(These numbers can be adjusted as desired.)
+R needs to be in a range tuned so that AES needs to decrypt data for
+at least 1 minute with some large number of GPUs. Hopefully on a CPU
+the decrypt time will be less than an hour.
 
-### server list
+(Alternatively, use a tunable client puzzle to encode R.
+Store the puzzle alongside the encrypted data.
+Use Argon2, which is GPU and ASIC resistent.
+Probably more on the order of 10 minutes per CPU core for this approach.)
 
-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 designated default servers.
-Shards are stored on these unless overridden by other configuration.
-
-When recovering a key, the client tries the default 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 default servers when necessary.
-
-### servers
-
-The server stores fixed size objects indexed by a name.
-
-The object size should be larger than most private keys, but not much
-larger. This prevents abusing the object storage for non-keys, and avoids
-leaking information about the type of object in its size. 16kb seems a
-reasonable size for objects.
-
-Servers can rate limit requests. It's fine for requests to take several
-minutes to complete.
-
-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.
-
-### storing a shard
-
-Shards are encrypted with AES before being stored on a server.
-
-A server should only allow a given object name to be stored once, after that
-it should reject it. This is to prevent probems if object names happen
-to collide. If there is a collision, backup will fail, and the user can be
-prompted to pick a different --name.
-
-### retrieving a shard
+## Recovering a key
 
-Anyone who knows an objects name can retrieve it from the server.
+* Input password and name from user.
+* Generate K, N1-N3 as above.
+* Request N1-N3 from servers until two objects are available.
+* Shamir recombine the objects.
+* Guess R and AES decrypt, repeating until checksum verifies.
 
-Servers can return a dummy object that is indistinguishable from a real
-object when asked for an object that they don't have. This makes brute
-force attacks harder. One way to do this would be to generate and store a
-random object, so that the same value is always returned.
+## Difficulty of brute forcing a single encrypted key
 
-### object names
+With a strong password, brute forcing requires 2^50 argon2.
+And, aeons of GPU time for the AES decrypts. Infeasible.
 
-The client should choose object names that cannot be matched up with a
-particular user. It should also be hard to correlate object names of related
-shards.
+With a weak password, say 2^30 argon2, cost for those is $460K,
+plus 2042 years of GPU time. 
 
-To accomplish that:
+Even a super-weak 19 entropy password (eg "mom123") would need
+1 year of GPU time to crack.
 
-	hash(namesecret + name + type + shardnum)
+## Attack methods
 
-Where namesecret is derived from the password (see below), name is
-what was specified with --name, type is what was specified with --type, and
-shardnum is eg 1.
+(Assuming rainbow tables won't be of use due to the name salting.)
 
-### encryption secrets
+An attacker who wants to target a particular person with a known keyid can
+guess their N1-N3, download two of S1-S3 and start brute forcing the
+encryption soon after the object is stored. However, it's hard for an
+attacker to discover all objects stored on a server. This protects
+uninteresting users who used weak passwords, because they are unlikely to
+become a target for cracking.
 
-From the password, multiple encryption secrets need to be generated.
-A total of 4 distinct encryption secrets are needed: The namesecret
-and one encryption key for each shard.
+The sharding prevents a single malicious server from blindly 
+guessing weak passwords across its entire collection of objects.
 
-The entropy from the password is divided up between those 4 secrets.
-Part of it is shared beteen them, and part is uniquely allocated to each of
-the 4 secrets. This needs to be carefully balanced to make each brute
-force cracking scenario maximally hard. TODO
+Two servers can collude to recombine shards, but to determine which shards
+belong together, have to use argon2 with a keyid and name, which takes 10
+minutes per attempt. This slows down blindly guessing weak passwords some,
+because it will take the attacker some time to generate a collection of
+recombined objects to check. More importantly if a gpg key is not published
+to keyservers, the attacker is unlikely to know its keyid, and so this
+method skips over such keys. And if the name used to store the key is
+different than the name on the keyservers, this method will skip over it
+too.
 
-This is a key derivation problem, so there are lots of
-[key derivation functions](https://en.wikipedia.org/wiki/Key_derivation_function)
-that could be used, including ones designed to make brute-forcing
-difficult.
+Or colluding servers can try to likely correlate related objects and
+recombine pairs of those. The more users use keysafe, the harder
+this becomes.
 
-It's fine if keysafe makes it very expensive to generate the encryption
-secrets that are used client side. It only has to do it once when a secret
-key is stored, and once when it's recovered. Spending on the order of 10
-minutes CPU time and many megabytes of memory would be acceptable, to make
-brute forcing extremely hard. Keysafe can also make this tunable -- storing
-a more valuable gpg key? Bump the cost up another order of magnitude.
-  
-Key derivation needs a salt to protect against rainbow tables. Use
---name as the salt.
+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.
 
-* script: Computationally intensive key generation from password,
-  tunable difficulty, tunable derived key length, 
-  somewhat ASIC resistent (but cryptocurrency use has caused ASICS to be
-  developed), not GPU resistent
+## Server list
 
-  <http://hackage.haskell.org/package/scrypt>
-
-* Argon2: Tunable time and memory costs, tunable parallelism requirement,
-  GPU resistent, ASIC resistent.
-
-  Result of the [Password hashing competition](https://password-hashing.net/)
-
-  <http://hackage.haskell.org/package/argon2>
-
-### brute force attack analysis
-
-There are two targets to brute force attack: the namesecret and the
-encrypted shards. 
-

(Diff truncated)
Added a comment
diff --git a/blog/entry/keysafe/comment_3_1e8ae9c0cdfbd02431b0c8aac4124fff._comment b/blog/entry/keysafe/comment_3_1e8ae9c0cdfbd02431b0c8aac4124fff._comment
new file mode 100644
index 0000000..48ce358
--- /dev/null
+++ b/blog/entry/keysafe/comment_3_1e8ae9c0cdfbd02431b0c8aac4124fff._comment
@@ -0,0 +1,9 @@
+[[!comment format=mdwn
+ username="Ben"
+ subject="comment 3"
+ date="2016-08-06T14:04:03Z"
+ content="""
+I relate to this usecase.
+
+An approach for a backend: https://ripacrypt.download/
+"""]]

todo
diff --git a/code/keysafe.mdwn b/code/keysafe.mdwn
index 768d178..03bb613 100644
--- a/code/keysafe.mdwn
+++ b/code/keysafe.mdwn
@@ -162,23 +162,23 @@ colluding malicious servers, and a third party.
 
 #### brute force decrypting shards
 
+This attack can only be performed by colluding malicious servers, because
+they need to have access to two sets of shards.
+
 Decrypting a shard using the wrong encryption secret generates
 random garbage. This makes brute-forcing quite difficult because each shard
 is itself an unstructured, high-entropy piece of data. Makes it hard to
 know when the right encryption secret has been guessed.
 
-An attacker would have to brute-force all necessary shards together,
-combine them, and check if the result is a valid gpg keyring. 
-This requires some method of correlating related shards.
+An attacker has to try all combinations of shards from the two sets,
+and for each combination, guess the encryption secrets used to encrypt
+both. It will know it found the right combination of shards when the
+result is a valid gpg keyring.
 
 The more people that are using keysafe, the harder it becomes for this
-attack, because there are increasingly many shards and it's harder to
-correlate related ones.
+attack. The number of combinations of shards is 2\*\*numusers.
 
-This attack can only be performed by colluding malicious servers,
-because they need to have access to both shards. A single malicious server
-would have to download the other shard from the other server, but has no
-way to detemine its name.
+An attacker's best hope is to find a way to correlate related shards.
 
 #### brute forcing the namesecret
 
@@ -267,3 +267,40 @@ 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.
+
+## TODO
+
+I stumbled upon this interesting paper on tunable proof of work puzzles
+that can expose information when solved:
+<https://www1.ericsson.com/res/docs/2015/random-access-procedure.pdf>  
+(With a low probabiliy of finding a bad solution.)
+
+That's effectively a way to encrypt data such that decryption takes a
+tunable amount of work.
+
+The puzzle is basically generated by:
+
+	F(k || d || r)
+
+Where F is a cryptographic function, k is a secret value, d is a difficutly
+bit string, and r is the result exposed by solving the puzzle.
+
+This could be used to encrypt shards. The decrypted 
+shard is r, and for k, use part of the password's entropy pool.
+
+The same k can be reused to encrypt *all* shards. So, the entropy pool
+is not split up between the shards.
+
+To decrypt a shard, keysafe would only need to solve the puzzle once,
+because it knows k. In the rare case when it finds a bad solution, it would
+notice when checking the validity of the combined shards, and it would
+then need to resume looking for a solution.
+
+A brute force shard decryption attack (that has not cracked the
+namesecret) would have to guess values for k (or guess passwords and
+derive k) and solve the puzzle repeatedly. The puzzle can be tuned so
+that this takes infeasibly long.
+
+An attacker who has already brute forced the namesecret can make
+educated guesses about the entropy pool, and k, so this
+won't slow them down as much.

clarify
diff --git a/code/keysafe.mdwn b/code/keysafe.mdwn
index 146db9e..768d178 100644
--- a/code/keysafe.mdwn
+++ b/code/keysafe.mdwn
@@ -183,7 +183,7 @@ way to detemine its name.
 #### brute forcing the namesecret
 
 This can only be performed by an attacker who has access to a server,
-because they need to be able to check passwords by checking if a
+because they need to be able to check passwords, by checking if a
 corresponding shard exists. A third party is prevented from performing
 this attack because servers pretend all object names exist.
 
@@ -192,8 +192,8 @@ work done by the password hash function. The amount of work should be
 picked such that this attack takes over a decade.
 
 Once the namesecret is brute forced, the attacker may not know
-the password yet, but they have figured out a good deal of the entropy
-pool, and can reuse that to decrypt the shards. And, they know the names
+the password yet, but they have learned much of the contents of the entropy
+pool, and can use that to decrypt the shards faster. And, they know the names
 of all the shards, so can easily retrive a second shard from another
 server.
 

simpl
diff --git a/code/keysafe.mdwn b/code/keysafe.mdwn
index 9f49769..146db9e 100644
--- a/code/keysafe.mdwn
+++ b/code/keysafe.mdwn
@@ -158,8 +158,7 @@ There are two targets to brute force attack: the namesecret and the
 encrypted shards. 
 
 There are three classes of potential attackers: A malicious server,
-colluding malicious servers, and a third party trying to find data on a
-non-malicious server.
+colluding malicious servers, and a third party.
 
 #### brute force decrypting shards
 

reord
diff --git a/code/keysafe.mdwn b/code/keysafe.mdwn
index 7266e93..9f49769 100644
--- a/code/keysafe.mdwn
+++ b/code/keysafe.mdwn
@@ -73,6 +73,9 @@ larger. This prevents abusing the object storage for non-keys, and avoids
 leaking information about the type of object in its size. 16kb seems a
 reasonable size for objects.
 
+Servers can rate limit requests. It's fine for requests to take several
+minutes to complete.
+
 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.
@@ -90,10 +93,6 @@ prompted to pick a different --name.
 
 Anyone who knows an objects name can retrieve it from the server.
 
-Servers should limit the rate of retrival requests, to avoid attackers
-trying to find object names by brute force. It's ok for a retrieval to take
-several minutes to complete.
-
 Servers can return a dummy object that is indistinguishable from a real
 object when asked for an object that they don't have. This makes brute
 force attacks harder. One way to do this would be to generate and store a

object size
diff --git a/code/keysafe.mdwn b/code/keysafe.mdwn
index a5a5b75..7266e93 100644
--- a/code/keysafe.mdwn
+++ b/code/keysafe.mdwn
@@ -66,7 +66,12 @@ stored on, and can change the default servers when necessary.
 
 ### servers
 
-The server stores small objects indexed by a name.
+The server stores fixed size objects indexed by a name.
+
+The object size should be larger than most private keys, but not much
+larger. This prevents abusing the object storage for non-keys, and avoids
+leaking information about the type of object in its size. 16kb seems a
+reasonable size for objects.
 
 Servers run exclusively as tor hidden services. This prevents them from
 finding out the IP addresses of clients, as well as providing transport

update
diff --git a/code/keysafe.mdwn b/code/keysafe.mdwn
index a2f1af2..a5a5b75 100644
--- a/code/keysafe.mdwn
+++ b/code/keysafe.mdwn
@@ -89,10 +89,10 @@ Servers should limit the rate of retrival requests, to avoid attackers
 trying to find object names by brute force. It's ok for a retrieval to take
 several minutes to complete.
 
-Servers can return random junk when asked for an object that they don't
-have. This makes brute force attacks harder. One way to do this would be to
-generate and store a random object, so that the same value is always
-returned.
+Servers can return a dummy object that is indistinguishable from a real
+object when asked for an object that they don't have. This makes brute
+force attacks harder. One way to do this would be to generate and store a
+random object, so that the same value is always returned.
 
 ### object names
 
@@ -114,6 +114,11 @@ From the password, multiple encryption secrets need to be generated.
 A total of 4 distinct encryption secrets are needed: The namesecret
 and one encryption key for each shard.
 
+The entropy from the password is divided up between those 4 secrets.
+Part of it is shared beteen them, and part is uniquely allocated to each of
+the 4 secrets. This needs to be carefully balanced to make each brute
+force cracking scenario maximally hard. TODO
+
 This is a key derivation problem, so there are lots of
 [key derivation functions](https://en.wikipedia.org/wiki/Key_derivation_function)
 that could be used, including ones designed to make brute-forcing
@@ -152,23 +157,6 @@ There are three classes of potential attackers: A malicious server,
 colluding malicious servers, and a third party trying to find data on a
 non-malicious server.
 
-#### brute forcing the namesecret
-
-Brute force attacking the namesecret is essentially a matter of cracking
-the password.
-
-This can only be performed by an attacker who has access to a server,
-because they need to be able to check passwords by checking if a
-corresponding shard exists. A third party is prevented from performing
-this attack because servers pretend all object names exist.
-
-The difficulty depends on the entropy of the password, and the amount of
-work done by the password hash function. The amount of work should be
-picked such that this attack takes over a decade.
-
-Once the namesecret is brute forced, the password is probably known,
-and the attacker can then trivially retrieve and decrypt the all shards.
-
 #### brute force decrypting shards
 
 Decrypting a shard using the wrong encryption secret generates
@@ -179,11 +167,32 @@ know when the right encryption secret has been guessed.
 An attacker would have to brute-force all necessary shards together,
 combine them, and check if the result is a valid gpg keyring. 
 This requires some method of correlating related shards.
+
 The more people that are using keysafe, the harder it becomes for this
 attack, because there are increasingly many shards and it's harder to
 correlate related ones.
 
-This attack can only be performed by colluding malicious servers.
+This attack can only be performed by colluding malicious servers,
+because they need to have access to both shards. A single malicious server
+would have to download the other shard from the other server, but has no
+way to detemine its name.
+
+#### brute forcing the namesecret
+
+This can only be performed by an attacker who has access to a server,
+because they need to be able to check passwords by checking if a
+corresponding shard exists. A third party is prevented from performing
+this attack because servers pretend all object names exist.
+
+The difficulty depends on the entropy of the namesecret, and the amount of
+work done by the password hash function. The amount of work should be
+picked such that this attack takes over a decade.
+
+Once the namesecret is brute forced, the attacker may not know
+the password yet, but they have figured out a good deal of the entropy
+pool, and can reuse that to decrypt the shards. And, they know the names
+of all the shards, so can easily retrive a second shard from another
+server.
 
 ### avoiding correlations
 
@@ -228,7 +237,7 @@ alive and is storing the data.
 	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 random response.
+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

claridy
diff --git a/code/keysafe.mdwn b/code/keysafe.mdwn
index 71b6ebf..a2f1af2 100644
--- a/code/keysafe.mdwn
+++ b/code/keysafe.mdwn
@@ -59,10 +59,10 @@ and the organization providing the server.
 Three of the servers in the list are designated default servers.
 Shards are stored on these unless overridden by other configuration.
 
-When recovering a key, the client tries the default servers first.
-But, if it doesn't recover enough shards from them, it tries other servers
-on the list. This way we don't need to remember which servers the shards
-were stored on, and can change the default servers when necessary.
+When recovering a key, the client tries the default 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 default servers when necessary.
 
 ### servers
 

substantially simplified
Eliminated the shard splitting, because treating the halves differently
was confusing, and didn't actually buy us much.
diff --git a/code/keysafe.mdwn b/code/keysafe.mdwn
index f466fff..71b6ebf 100644
--- a/code/keysafe.mdwn
+++ b/code/keysafe.mdwn
@@ -50,7 +50,6 @@ and the password.
 Shamir secret sharing is used to generate the shards of the key.
 By default three shards are made, and any two of them can recreate the key.
 (These numbers can be adjusted as desired.)
-Call these shard1..shard3. Each shard is stored on a separate server.
 
 ### server list
 
@@ -67,104 +66,53 @@ were stored on, and can change the default servers when necessary.
 
 ### servers
 
-The server stores objects indexed by a name, and with an associated
-encryption method.
+The server stores small objects indexed by a name.
 
 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.
 
-The server never exposes an encrypted object to a client. To retrieve an
-object, a client must provide the encryption secret. The object is then
-decrypted on the server, and the result returned. 
-
-TODO: If the wrong secret is given, the server should return garbage
-data. It's important that whatever is returned in this case
-be deterministic, and that it not leak information which an attacker
-could use to recover the encrypted object. In particular, if
-the encryption method works such that `encrypt(secret, decrypt(secret, data)) == data`
-then the attacker could use any secret and recover the original
-encrypted object. (Thanks, Anthony Towns)
-
-### encryption methods
-
-The encryption method should be such that decrypting with the wrong
-encryption secret generates random garbage. This makes brute-forcing quite
-difficult because each shard is itself an unstructured, high-entropy piece
-of data. Makes it hard to know when the right encryption secret has been
-guessed. An attacker would have to brute-force all necessary shards
-together, combine them, and check if the result is a valid gpg keyring.
-
-Also, there's a null encryption method that passes the object through
-unchanged.
-
 ### storing a shard
 
-To store a shard on a server, it is broken into two halves. Call these
-`shard1A`, `shard1B` etc. Each half is encrypted with its own encryption
-secret (discussed below).
-
-`shard*A` is always stored on the server with the null encryption method,
-while `shard*B` is always stored using a real encryption method. This is done
-to make various different types of attacks harder, as detailed below.
+Shards are encrypted with AES before being stored on a server.
 
-A server should only allow a given object to be stored once, after that
+A server should only allow a given object name to be stored once, after that
 it should reject it. This is to prevent probems if object names happen
 to collide. If there is a collision, backup will fail, and the user can be
 prompted to pick a different --name.
 
 ### retrieving a shard
 
-It follows that retrieving a shard involves asking the server for each half
-and providing the encryption secret for `shard*B` to the server so it can 
-decrypt it. Note that the encryption secret for `shard*A` is never sent to
-any server.
+Anyone who knows an objects name can retrieve it from the server.
+
+Servers should limit the rate of retrival requests, to avoid attackers
+trying to find object names by brute force. It's ok for a retrieval to take
+several minutes to complete.
+
+Servers can return random junk when asked for an object that they don't
+have. This makes brute force attacks harder. One way to do this would be to
+generate and store a random object, so that the same value is always
+returned.
 
 ### object names
 
 The client should choose object names that cannot be matched up with a
 particular user. It should also be hard to correlate object names of related
-shards (or shard halves).
+shards.
 
 To accomplish that:
 
-	hash(namesecret + name + type + shardname)
+	hash(namesecret + name + type + shardnum)
 
-Where namesecret is derived from the password (see below) name is
+Where namesecret is derived from the password (see below), name is
 what was specified with --name, type is what was specified with --type, and
-shardname is eg shard1A.
-
-This can be attacked: The server can try to brute-force the namesecret
-of a user (after guessing the --name they'll use), 
-and if they manage to generate a hash that they've seen, 
-they now know that a shard belongs to that user and can proceed to 
-brute forcing that shard.
-
-A third party can also try to brute-force attack the namesecret by making
-requests to the server. Servers can prevent this attack with rate limiting
-and/or by returning randon junk when asked for an object that does not exist.
-
-Picking the right hash here will make brute forcing much harder.
-Eg, scrypt or argon2.
+shardnum is eg 1.
 
 ### encryption secrets
 
 From the password, multiple encryption secrets need to be generated.
-A total of 7 distinct encryption secrets are needed.
-Call these namesecret and es1A-es3B.
-
-It's crucial that knowing namesecret not make it easier to brute force
-the rest of the encryption secrets. This is necessary because the brute
-force attack on object names is the easiest one to perform.
-
-TODO: That's really important. How to make sure it's the case?
-
-Knowing es1B should not make it easier to brute force es1A. This is necessary
-because es1B is sent to the server to retrieve an object.
-
-Ideally, knowing es1B should not make it easier to brute force es2B and
-es2C. But this may not be practical. Only so much password entropy to go
-around.
+A total of 4 distinct encryption secrets are needed: The namesecret
+and one encryption key for each shard.
 
 This is a key derivation problem, so there are lots of
 [key derivation functions](https://en.wikipedia.org/wiki/Key_derivation_function)
@@ -195,30 +143,47 @@ Key derivation needs a salt to protect against rainbow tables. Use
 
   <http://hackage.haskell.org/package/argon2>
 
-### brute force attacks
+### brute force attack analysis
+
+There are two targets to brute force attack: the namesecret and the
+encrypted shards. 
+
+There are three classes of potential attackers: A malicious server,
+colluding malicious servers, and a third party trying to find data on a
+non-malicious server.
+
+#### brute forcing the namesecret
+
+Brute force attacking the namesecret is essentially a matter of cracking
+the password.
+
+This can only be performed by an attacker who has access to a server,
+because they need to be able to check passwords by checking if a
+corresponding shard exists. A third party is prevented from performing
+this attack because servers pretend all object names exist.
+
+The difficulty depends on the entropy of the password, and the amount of
+work done by the password hash function. The amount of work should be
+picked such that this attack takes over a decade.
 
-The A half of a shard can be retrieved by anyone, and anyone can try to
-brute-force its encryption secret. But that's useless without the B half, and
-that half cannot be retrieved correctly without knowing its encryption secret.
-Servers should throttle retrieval attempts of the same object, to prevent
-attackers from brute force attacks.
+Once the namesecret is brute forced, the password is probably known,
+and the attacker can then trivially retrieve and decrypt the all shards.
 
-Of course, the server can brute force attack both halves whenever it
-likes.
+#### brute force decrypting shards
 
-Worse, when shardNB is retrieved, the encryption secret is provided to the
-server. So, the server then knows half without brute-forcing. It still has
-to brute-force shardNA though.
+Decrypting a shard using the wrong encryption secret generates
+random garbage. This makes brute-forcing quite difficult because each shard
+is itself an unstructured, high-entropy piece of data. Makes it hard to
+know when the right encryption secret has been guessed.
 
-But the more people that are using keysafe, the harder it becomes for
-the server to brute-force attack anyone! This is because with more and more
-objects stored, the server has an increasingly hard time matching up the
-two halves of a shard.
+An attacker would have to brute-force all necessary shards together,
+combine them, and check if the result is a valid gpg keyring. 
+This requires some method of correlating related shards.
+The more people that are using keysafe, the harder it becomes for this
+attack, because there are increasingly many shards and it's harder to
+correlate related ones.
 
-Even if a server manages to correctly decrypt the shard that was stored on
-it, it still needs to collude with one other server in order to recover the
-user's secret key. And again the more people that are using keysafe,
-the more difficulty there is in matching up a user's shards.
+This attack can only be performed by colluding malicious servers.

(Diff truncated)
aj review
diff --git a/code/keysafe.mdwn b/code/keysafe.mdwn
index 4f20d92..f466fff 100644
--- a/code/keysafe.mdwn
+++ b/code/keysafe.mdwn
@@ -76,8 +76,15 @@ level encryption.
 
 The server never exposes an encrypted object to a client. To retrieve an
 object, a client must provide the encryption secret. The object is then
-decrypted on the server, and the result returned. If the wrong secret is
-given, the server returns garbage.
+decrypted on the server, and the result returned. 
+
+TODO: If the wrong secret is given, the server should return garbage
+data. It's important that whatever is returned in this case
+be deterministic, and that it not leak information which an attacker
+could use to recover the encrypted object. In particular, if
+the encryption method works such that `encrypt(secret, decrypt(secret, data)) == data`
+then the attacker could use any secret and recover the original
+encrypted object. (Thanks, Anthony Towns)
 
 ### encryption methods
 
@@ -137,6 +144,9 @@ A third party can also try to brute-force attack the namesecret by making
 requests to the server. Servers can prevent this attack with rate limiting
 and/or by returning randon junk when asked for an object that does not exist.
 
+Picking the right hash here will make brute forcing much harder.
+Eg, scrypt or argon2.
+
 ### encryption secrets
 
 From the password, multiple encryption secrets need to be generated.
@@ -147,6 +157,8 @@ It's crucial that knowing namesecret not make it easier to brute force
 the rest of the encryption secrets. This is necessary because the brute
 force attack on object names is the easiest one to perform.
 
+TODO: That's really important. How to make sure it's the case?
+
 Knowing es1B should not make it easier to brute force es1A. This is necessary
 because es1B is sent to the server to retrieve an object.
 
@@ -160,11 +172,11 @@ that could be used, including ones designed to make brute-forcing
 difficult.
 
 It's fine if keysafe makes it very expensive to generate the encryption
-secrets. It only has to do it once when a secret key is stored, and once
-when it's recovered. Spending on the order of 10 minutes CPU time and many
-megabytes of memory would be acceptable, to make brute forcing extremely
-hard. Keysafe can also make this tunable -- storing a more valuable gpg
-key? Bump the cost up another order of magnitude.
+secrets that are used client side. It only has to do it once when a secret
+key is stored, and once when it's recovered. Spending on the order of 10
+minutes CPU time and many megabytes of memory would be acceptable, to make
+brute forcing extremely hard. Keysafe can also make this tunable -- storing
+a more valuable gpg key? Bump the cost up another order of magnitude.
   
 Key derivation needs a salt to protect against rainbow tables. Use
 --name as the salt.
@@ -239,6 +251,11 @@ servers to collect encryption secrets.
 A side benefit to chaffing is it also verifies that the server is still
 alive and is storing the data.
 
+>  - As far as chaffing goes, maybe it would be interesting to make use of
+>    cron's "thundering herd" problem; eg, if clients deliberately make
+>    queries on the hour, it'll be harder to do traffic analysis...
+-- Anthony Towns
+
 ### object size
 
 To avoid abuse, servers will limit the size of objects stored in them,

more
diff --git a/code/keysafe.mdwn b/code/keysafe.mdwn
index e1197c0..4f20d92 100644
--- a/code/keysafe.mdwn
+++ b/code/keysafe.mdwn
@@ -158,6 +158,13 @@ This is a key derivation problem, so there are lots of
 [key derivation functions](https://en.wikipedia.org/wiki/Key_derivation_function)
 that could be used, including ones designed to make brute-forcing
 difficult.
+
+It's fine if keysafe makes it very expensive to generate the encryption
+secrets. It only has to do it once when a secret key is stored, and once
+when it's recovered. Spending on the order of 10 minutes CPU time and many
+megabytes of memory would be acceptable, to make brute forcing extremely
+hard. Keysafe can also make this tunable -- storing a more valuable gpg
+key? Bump the cost up another order of magnitude.
   
 Key derivation needs a salt to protect against rainbow tables. Use
 --name as the salt.

comment
diff --git a/blog/entry/keysafe/comment_2_99ff2eabbf0a338991e3a1fc1bd2c927._comment b/blog/entry/keysafe/comment_2_99ff2eabbf0a338991e3a1fc1bd2c927._comment
new file mode 100644
index 0000000..68e2515
--- /dev/null
+++ b/blog/entry/keysafe/comment_2_99ff2eabbf0a338991e3a1fc1bd2c927._comment
@@ -0,0 +1,11 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 2"""
+ date="2016-08-05T14:17:49Z"
+ content="""
+I already use gfshare to shard my gpg key for backup, in a less
+secure way than keysafe.
+
+But, if I implement keysafe in haskell, there's a nice pure haskell
+shamir library, <http://hackage.haskell.org/package/secret-sharing>
+"""]]

simplify
diff --git a/code/keysafe.mdwn b/code/keysafe.mdwn
index 70df830..e1197c0 100644
--- a/code/keysafe.mdwn
+++ b/code/keysafe.mdwn
@@ -150,11 +150,9 @@ force attack on object names is the easiest one to perform.
 Knowing es1B should not make it easier to brute force es1A. This is necessary
 because es1B is sent to the server to retrieve an object.
 
-However, knowing es1B may make it easier to brute force es2B. This tradeoff
-may be necessary because passwords only have so much entropy to go around.
-It will make it somewhat easier for colluding servers to combine to
-brute-force the user's secret key, but there's a combinatorial explosion
-involved, so this is probably acceptable.
+Ideally, knowing es1B should not make it easier to brute force es2B and
+es2C. But this may not be practical. Only so much password entropy to go
+around.
 
 This is a key derivation problem, so there are lots of
 [key derivation functions](https://en.wikipedia.org/wiki/Key_derivation_function)

key derivation functions
diff --git a/code/keysafe.mdwn b/code/keysafe.mdwn
index 3646419..70df830 100644
--- a/code/keysafe.mdwn
+++ b/code/keysafe.mdwn
@@ -68,7 +68,7 @@ were stored on, and can change the default servers when necessary.
 ### servers
 
 The server stores objects indexed by a name, and with an associated
-encryption method. 
+encryption method.
 
 Servers run exclusively as tor hidden services. This prevents them from
 finding out the IP addresses of clients, as well as providing transport
@@ -88,11 +88,6 @@ of data. Makes it hard to know when the right encryption secret has been
 guessed. An attacker would have to brute-force all necessary shards
 together, combine them, and check if the result is a valid gpg keyring.
 
-It would be good for the encryption to be CPU-expensive and GPU attack
-resistent.
-
-TODO: What encryption to use?
-
 Also, there's a null encryption method that passes the object through
 unchanged.
 
@@ -155,13 +150,33 @@ force attack on object names is the easiest one to perform.
 Knowing es1B should not make it easier to brute force es1A. This is necessary
 because es1B is sent to the server to retrieve an object.
 
-However, knowing es1B may make it easier to brute force es2B. This may be
-necessary because passwords only have so much entropy to go around. It will
-make it somewhat easier for colluding servers to combine to brute-force the
-user's secret key, but there's a combinatorial explosion involved, so
-this is probably acceptable.
+However, knowing es1B may make it easier to brute force es2B. This tradeoff
+may be necessary because passwords only have so much entropy to go around.
+It will make it somewhat easier for colluding servers to combine to
+brute-force the user's secret key, but there's a combinatorial explosion
+involved, so this is probably acceptable.
+
+This is a key derivation problem, so there are lots of
+[key derivation functions](https://en.wikipedia.org/wiki/Key_derivation_function)
+that could be used, including ones designed to make brute-forcing
+difficult.
+  
+Key derivation needs a salt to protect against rainbow tables. Use
+--name as the salt.
+
+* script: Computationally intensive key generation from password,
+  tunable difficulty, tunable derived key length, 
+  somewhat ASIC resistent (but cryptocurrency use has caused ASICS to be
+  developed), not GPU resistent
+
+  <http://hackage.haskell.org/package/scrypt>
+
+* Argon2: Tunable time and memory costs, tunable parallelism requirement,
+  GPU resistent, ASIC resistent.
+
+  Result of the [Password hashing competition](https://password-hashing.net/)
 
-TODO: How to generate these?
+  <http://hackage.haskell.org/package/argon2>
 
 ### brute force attacks
 

Added a comment: libgfshare
diff --git a/blog/entry/keysafe/comment_1_bd198207ffaab69db5801a00d1a934c2._comment b/blog/entry/keysafe/comment_1_bd198207ffaab69db5801a00d1a934c2._comment
new file mode 100644
index 0000000..a462db4
--- /dev/null
+++ b/blog/entry/keysafe/comment_1_bd198207ffaab69db5801a00d1a934c2._comment
@@ -0,0 +1,10 @@
+[[!comment format=mdwn
+ username="mepper@fb792a0b90551ff034a87a360ecd6e2c3ca7365b"
+ nickname="mepper"
+ subject="libgfshare"
+ date="2016-08-05T11:50:09Z"
+ content="""
+You might want to check out libgfshare which already implements Shamir's method.
+
+http://www.digital-scurf.org/software/libgfshare 
+"""]]

fix numbers
diff --git a/code/keysafe.mdwn b/code/keysafe.mdwn
index 31a3e66..3646419 100644
--- a/code/keysafe.mdwn
+++ b/code/keysafe.mdwn
@@ -242,8 +242,8 @@ So 64k should be a generous enough standard object size.
 
 A $10 VPS server could store around 16 million such objects on a 32 GB
 disk. Even if 99% of stored objects are chaff (probably not), that's still
-enough room to store 80 thousand users' keys. Upgrade to a 4 TB disk to
-store ten million users' keys.
+enough room to store 160 thousand users' keys. Upgrade to a 4 TB disk to
+store 20 million users' keys.
 
 ### detecting corrupt data
 

more key size thoughts
diff --git a/code/keysafe.mdwn b/code/keysafe.mdwn
index 1c7db37..31a3e66 100644
--- a/code/keysafe.mdwn
+++ b/code/keysafe.mdwn
@@ -1,4 +1,4 @@
-Securely backs up a gpg secret key or other short secret to the cloud.
+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
@@ -23,6 +23,8 @@ Not yet implemented! Needs security review! May run over your dog!
 	Please wait...
 	Key successfully restored.
 
+	[also, imagine a GUI here]
+
 ## how it works, basically
 
 The secret key is split into three shards, and each is uploaded to a server
@@ -228,10 +230,20 @@ whitespace to some standard size. If the input secret key is larger than
 that size, it can be broken into chunks and each chunk individually sharded
 and stored.
 
-An ascii armored gpg secret key of size 4096, exported without signatures,
-is ~6705 bytes. A key with lots of signatures tends to export larger,
-but `paperkey` is good at cutting that down, to ~2724 bytes.
-So 64k might be a good standard object size.
+An ascii armored gpg secret key of length 4096, exported without
+signatures, is ~6705 bytes. A key with lots of signatures tends to export
+larger, but `paperkey` is good at cutting that down, to ~2724 byteas.
+Non-gpg private keys will probably not be much larger (ssh private keys are
+max at ~1700 bytes; bind DNSSEC private keys are ~3320 bytes; SSL certs
+~3300 bytes).
+
+So 64k should be a generous enough standard object size.  
+(And it was good enough for billg.. *rimshot*)  
+
+A $10 VPS server could store around 16 million such objects on a 32 GB
+disk. Even if 99% of stored objects are chaff (probably not), that's still
+enough room to store 80 thousand users' keys. Upgrade to a 4 TB disk to
+store ten million users' keys.
 
 ### detecting corrupt data
 

blog update
diff --git a/blog/entry/keysafe.mdwn b/blog/entry/keysafe.mdwn
new file mode 100644
index 0000000..c37de2a
--- /dev/null
+++ b/blog/entry/keysafe.mdwn
@@ -0,0 +1,47 @@
+Have you ever thought about using a gpg key to encrypt something, but
+didn't due to worries that you'd eventually lose the secret key? Or maybe
+you did use a gpg key to encrypt something and lost the key. There are
+nice tools like [paperkey](http://www.jabberwocky.com/software/paperkey/)
+to back up gpg keys, but they require things like printers, and a secure
+place to store the backups.
+
+I feel that simple backup and restore of gpg keys (and encryption keys
+generally) is keeping some users from using gpg. If there was a nice
+automated solution for that, distributions could come preconfigured to
+generate encryption keys and use them for backups etc. I know this is
+a missing peice in the git-annex assistant, which makes it easy to
+generate a gpg key to encrypt your data, but can't help you back up the
+secret key.
+
+So, I'm thinking about storing secret keys in the cloud. Which seems
+scary to me, since when I was a Debian Developer, my gpg key could have
+been used to compromise millions of systems. But this is not about
+developers, it's about users, and so trading off some security for some
+ease of use may be appropriate. Especially since the alternative is no
+security. I know that some folks back up their gpg keys in the
+cloud using DropBox.. We can do better.
+
+I've thought up a design for this, called [[code/keysafe]].
+The synopsis of how it works is:
+
+> The secret key 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.
+> 
+> A password is used to encrypt the key. For the servers to access your
+> key, two of them need to collude together, and they then have to brute
+> force the password. The design of keysafe makes brute forcing
+> extra difficult by making it hard to know which shards belong to you.
+> 
+> Indeed the more people that use keysafe, the harder it becomes to 
+> brute-force anyone's key!
+
+I could really use some additional reviews and feedback on
+[[the design|code/keysafe]] by experts.
+
+----
+
+This project is being sponsored by [Purism](https://puri.sm/)
+and by my [Patreon supporters](https://www.patreon.com/joeyh).
+By the way, I'm 15% of the way to my Patreon goal after one day!
diff --git a/code/keysafe.mdwn b/code/keysafe.mdwn
index 71dec05..1c7db37 100644
--- a/code/keysafe.mdwn
+++ b/code/keysafe.mdwn
@@ -35,6 +35,9 @@ key, two of them need to collude together, and they then have to brute
 force the password. The design of keysafe makes brute forcing
 extra difficult by making it hard to know which shards belong to you.
 
+Indeed the more people that use keysafe, the harder it becomes to
+brute-force anyone's key!
+
 All you need to recover the key is the --name you used when backing it up,
 and the password.
 

encryption
diff --git a/code/keysafe.mdwn b/code/keysafe.mdwn
index 7e48efb..71dec05 100644
--- a/code/keysafe.mdwn
+++ b/code/keysafe.mdwn
@@ -83,6 +83,11 @@ of data. Makes it hard to know when the right encryption secret has been
 guessed. An attacker would have to brute-force all necessary shards
 together, combine them, and check if the result is a valid gpg keyring.
 
+It would be good for the encryption to be CPU-expensive and GPU attack
+resistent.
+
+TODO: What encryption to use?
+
 Also, there's a null encryption method that passes the object through
 unchanged.
 

fm
diff --git a/code/keysafe.mdwn b/code/keysafe.mdwn
index a5dc4d8..7e48efb 100644
--- a/code/keysafe.mdwn
+++ b/code/keysafe.mdwn
@@ -132,7 +132,7 @@ A third party can also try to brute-force attack the namesecret by making
 requests to the server. Servers can prevent this attack with rate limiting
 and/or by returning randon junk when asked for an object that does not exist.
 
-## encryption secrets
+### encryption secrets
 
 From the password, multiple encryption secrets need to be generated.
 A total of 7 distinct encryption secrets are needed.

corrupt and malicious data
diff --git a/code/keysafe.mdwn b/code/keysafe.mdwn
index 73e16b2..a5dc4d8 100644
--- a/code/keysafe.mdwn
+++ b/code/keysafe.mdwn
@@ -224,3 +224,37 @@ An ascii armored gpg secret key of size 4096, exported without signatures,
 is ~6705 bytes. A key with lots of signatures tends to export larger,
 but `paperkey` is good at cutting that down, to ~2724 bytes.
 So 64k might be a good standard object 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.
+
+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.
+
+### 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.

typo
diff --git a/code/keysafe.mdwn b/code/keysafe.mdwn
index 7407893..73e16b2 100644
--- a/code/keysafe.mdwn
+++ b/code/keysafe.mdwn
@@ -204,7 +204,7 @@ The client can also do chaffing, by storing additional junk objects,
 and by keeping a list of objects it's uploaded and occasionally retriving
 a random object from each server. Note that a random encryption secret
 should be used with such retrievals, which also makes it harder for 
-servers to collect enctyptions secrets.
+servers to collect encryption secrets.
 
 A side benefit to chaffing is it also verifies that the server is still
 alive and is storing the data.

improve
diff --git a/code/keysafe.mdwn b/code/keysafe.mdwn
index 6fc3be5..7407893 100644
--- a/code/keysafe.mdwn
+++ b/code/keysafe.mdwn
@@ -191,13 +191,23 @@ Ways the server could draw correlations include:
   various objects, probably on the order of days.)
 * IP address used to store the data.  
   (Using tor avoids this.)
-* When the data was retrieved.
+* 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..)
 * Any 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.)
 
-The client can also do chaffing, by storing additional junk objects.
+The client can also do chaffing, by storing additional junk objects,
+and by keeping a list of objects it's uploaded and occasionally retriving
+a random object from each server. Note that a random encryption secret
+should be used with such retrievals, which also makes it harder for 
+servers to collect enctyptions secrets.
+
+A side benefit to chaffing is it also verifies that the server is still
+alive and is storing the data.
 
 ### object size
 

updates
diff --git a/code/keysafe.mdwn b/code/keysafe.mdwn
index cdea9c8..6fc3be5 100644
--- a/code/keysafe.mdwn
+++ b/code/keysafe.mdwn
@@ -96,6 +96,11 @@ secret (discussed below).
 while `shard*B` is always stored using a real encryption method. This is done
 to make various different types of attacks harder, as detailed below.
 
+A server should only allow a given object to be stored once, after that
+it should reject it. This is to prevent probems if object names happen
+to collide. If there is a collision, backup will fail, and the user can be
+prompted to pick a different --name.
+
 ### retrieving a shard
 
 It follows that retrieving a shard involves asking the server for each half
@@ -111,13 +116,22 @@ shards (or shard halves).
 
 To accomplish that:
 
-	hash(namesecret + username + shardname)
+	hash(namesecret + name + type + shardname)
+
+Where namesecret is derived from the password (see below) name is
+what was specified with --name, type is what was specified with --type, and
+shardname is eg shard1A.
 
 This can be attacked: The server can try to brute-force the namesecret
-of a user, and if they manage to generate a hash that they've seen,
-they now know that a shard belongs to that user and can proceed to
+of a user (after guessing the --name they'll use), 
+and if they manage to generate a hash that they've seen, 
+they now know that a shard belongs to that user and can proceed to 
 brute forcing that shard.
 
+A third party can also try to brute-force attack the namesecret by making
+requests to the server. Servers can prevent this attack with rate limiting
+and/or by returning randon junk when asked for an object that does not exist.
+
 ## encryption secrets
 
 From the password, multiple encryption secrets need to be generated.

typo
diff --git a/code/keysafe.mdwn b/code/keysafe.mdwn
index 2fa015a..cdea9c8 100644
--- a/code/keysafe.mdwn
+++ b/code/keysafe.mdwn
@@ -128,10 +128,10 @@ It's crucial that knowing namesecret not make it easier to brute force
 the rest of the encryption secrets. This is necessary because the brute
 force attack on object names is the easiest one to perform.
 
-Knowing es1A should not make it easier to brute force es1B. This is necessary
-because es1A is sent to the server to retrieve an object.
+Knowing es1B should not make it easier to brute force es1A. This is necessary
+because es1B is sent to the server to retrieve an object.
 
-However, knowing es1A may make it easier to brute force es2A. This may be
+However, knowing es1B may make it easier to brute force es2B. This may be
 necessary because passwords only have so much entropy to go around. It will
 make it somewhat easier for colluding servers to combine to brute-force the
 user's secret key, but there's a combinatorial explosion involved, so

typog
diff --git a/code/keysafe.mdwn b/code/keysafe.mdwn
index b3114b0..2fa015a 100644
--- a/code/keysafe.mdwn
+++ b/code/keysafe.mdwn
@@ -89,18 +89,18 @@ unchanged.
 ### storing a shard
 
 To store a shard on a server, it is broken into two halves. Call these
-shard1A, shard1B etc. Each half is encrypted with its own encryption
+`shard1A`, `shard1B` etc. Each half is encrypted with its own encryption
 secret (discussed below).
 
-shard*A is always stored on the server with the null encryption method,
-while shard*B is always stored using a real encryption method. This is done
+`shard*A` is always stored on the server with the null encryption method,
+while `shard*B` is always stored using a real encryption method. This is done
 to make various different types of attacks harder, as detailed below.
 
 ### retrieving a shard
 
 It follows that retrieving a shard involves asking the server for each half
-and providing the encryption secret for shard*B to the server so it can 
-decrypt it. Note that the encryption secret for shard*A is never sent to
+and providing the encryption secret for `shard*B` to the server so it can 
+decrypt it. Note that the encryption secret for `shard*A` is never sent to
 any server.
 
 ### object names

add
diff --git a/code/keysafe.mdwn b/code/keysafe.mdwn
new file mode 100644
index 0000000..b3114b0
--- /dev/null
+++ b/code/keysafe.mdwn
@@ -0,0 +1,202 @@
+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 implemented! Needs security review! May run over your dog!
+
+## example
+
+	> keysafe --backup --name="email@example.com" --type=gpg
+	Password:
+	Verify password:
+	Please wait...
+	Key backed up to 3 servers, hosted by:
+		eff.org
+		riseup.net
+		joeyh.name
+
+	> keysafe --restore --name="email@example.com" --type=gpg
+	Password:
+	Please wait...
+	Key successfully restored.
+
+## how it works, basically
+
+The secret key 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.
+
+A password is used to encrypt the key. For the servers to access your
+key, two of them need to collude together, and they then have to brute
+force the password. The design of keysafe makes brute forcing
+extra difficult by making it hard to know which shards belong to you.
+
+All you need to recover the key is the --name you used when backing it up,
+and the password.
+
+## design
+
+### sharding
+
+Shamir secret sharing is used to generate the shards of the key.
+By default three shards are made, and any two of them can recreate the key.
+(These numbers can be adjusted as desired.)
+Call these shard1..shard3. Each shard is stored on a separate server.
+
+### 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 designated default servers.
+Shards are stored on these unless overridden by other configuration.
+
+When recovering a key, the client tries the default servers first.
+But, if it doesn't recover enough shards from them, it tries other servers
+on the list. This way we don't need to remember which servers the shards
+were stored on, and can change the default servers when necessary.
+
+### servers
+
+The server stores objects indexed by a name, and with an associated
+encryption method. 
+
+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.
+
+The server never exposes an encrypted object to a client. To retrieve an
+object, a client must provide the encryption secret. The object is then
+decrypted on the server, and the result returned. If the wrong secret is
+given, the server returns garbage.
+
+### encryption methods
+
+The encryption method should be such that decrypting with the wrong
+encryption secret generates random garbage. This makes brute-forcing quite
+difficult because each shard is itself an unstructured, high-entropy piece
+of data. Makes it hard to know when the right encryption secret has been
+guessed. An attacker would have to brute-force all necessary shards
+together, combine them, and check if the result is a valid gpg keyring.
+
+Also, there's a null encryption method that passes the object through
+unchanged.
+
+### storing a shard
+
+To store a shard on a server, it is broken into two halves. Call these
+shard1A, shard1B etc. Each half is encrypted with its own encryption
+secret (discussed below).
+
+shard*A is always stored on the server with the null encryption method,
+while shard*B is always stored using a real encryption method. This is done
+to make various different types of attacks harder, as detailed below.
+
+### retrieving a shard
+
+It follows that retrieving a shard involves asking the server for each half
+and providing the encryption secret for shard*B to the server so it can 
+decrypt it. Note that the encryption secret for shard*A is never sent to
+any server.
+
+### object names
+
+The client should choose object names that cannot be matched up with a
+particular user. It should also be hard to correlate object names of related
+shards (or shard halves).
+
+To accomplish that:
+
+	hash(namesecret + username + shardname)
+
+This can be attacked: The server can try to brute-force the namesecret
+of a user, and if they manage to generate a hash that they've seen,
+they now know that a shard belongs to that user and can proceed to
+brute forcing that shard.
+
+## encryption secrets
+
+From the password, multiple encryption secrets need to be generated.
+A total of 7 distinct encryption secrets are needed.
+Call these namesecret and es1A-es3B.
+
+It's crucial that knowing namesecret not make it easier to brute force
+the rest of the encryption secrets. This is necessary because the brute
+force attack on object names is the easiest one to perform.
+
+Knowing es1A should not make it easier to brute force es1B. This is necessary
+because es1A is sent to the server to retrieve an object.
+
+However, knowing es1A may make it easier to brute force es2A. This may be
+necessary because passwords only have so much entropy to go around. It will
+make it somewhat easier for colluding servers to combine to brute-force the
+user's secret key, but there's a combinatorial explosion involved, so
+this is probably acceptable.
+
+TODO: How to generate these?
+
+### brute force attacks
+
+The A half of a shard can be retrieved by anyone, and anyone can try to
+brute-force its encryption secret. But that's useless without the B half, and
+that half cannot be retrieved correctly without knowing its encryption secret.
+Servers should throttle retrieval attempts of the same object, to prevent
+attackers from brute force attacks.
+
+Of course, the server can brute force attack both halves whenever it
+likes.
+
+Worse, when shardNB is retrieved, the encryption secret is provided to the
+server. So, the server then knows half without brute-forcing. It still has
+to brute-force shardNA though.
+
+But the more people that are using keysafe, the harder it becomes for
+the server to brute-force attack anyone! This is because with more and more
+objects stored, the server has an increasingly hard time matching up the
+two halves of a shard.
+
+Even if a server manages to correctly decrypt the shard that was stored on
+it, it still needs to collude with one other server in order to recover the
+user's secret key. And again the more people that are using keysafe,
+the more difficulty there is in matching up a user's shards.
+
+### 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.)
+* IP address used to store the data.  
+  (Using tor avoids this.)
+* When the data was retrieved.
+* Any 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.)
+
+The client can also do chaffing, by storing additional junk objects.
+
+### object size
+
+To avoid abuse, servers will limit the size of objects stored in them,
+and will probably rate limit accesses too.
+
+Picking a single size and making all objects that size helps avoid
+correlations. For this reason, clients should pad the input secret key with

(Diff truncated)
watch-my-terminal supports multiple simultaneous viewers well.
diff --git a/code/debug-me/discussion.mdwn b/code/debug-me/discussion.mdwn
index b29f681..8027f1a 100644
--- a/code/debug-me/discussion.mdwn
+++ b/code/debug-me/discussion.mdwn
@@ -9,7 +9,7 @@ Some similar projects you may be interested in looking at, if only for "how not
 * [Iodine][] - IP over DNS tunnel, when even Tor fails
 * [Mosh][] - the mobile shell, interesting concepts of local terminal emulation and predictive capabilities
 * [Monkeysphere][] - OpenPGP web of trust applied to SSH and HTTP servers and clients
-* [watch-my-terminal][] - Allows a remote user to watch your terminal session via any modern browser (script+node on the broadcaster side, javascript on the watchers' side). Terminal emulation is quite good; it correctly renders vim, less and aptitude.
+* [watch-my-terminal][] - Allows a remote users to watch your terminal session via any modern browser (script+node on the broadcaster side, javascript on the watchers' side). Terminal emulation is quite good; it correctly renders vim, less and aptitude.
 
 [Gitso]: https://code.google.com/archive/p/gitso/
 [more recent fork]: https://github.com/AustP/Gitso

diff --git a/code/debug-me/discussion.mdwn b/code/debug-me/discussion.mdwn
index 30bfab7..b29f681 100644
--- a/code/debug-me/discussion.mdwn
+++ b/code/debug-me/discussion.mdwn
@@ -9,7 +9,7 @@ Some similar projects you may be interested in looking at, if only for "how not
 * [Iodine][] - IP over DNS tunnel, when even Tor fails
 * [Mosh][] - the mobile shell, interesting concepts of local terminal emulation and predictive capabilities
 * [Monkeysphere][] - OpenPGP web of trust applied to SSH and HTTP servers and clients
-* [watch-my-terminal][] - Allows a remote user to watch your terminal session via any modern browser (script+node on the broadcaster side, javascript on the watchers' side). Terminal emulation quite good; it correctly renders vim, less and aptitude.
+* [watch-my-terminal][] - Allows a remote user to watch your terminal session via any modern browser (script+node on the broadcaster side, javascript on the watchers' side). Terminal emulation is quite good; it correctly renders vim, less and aptitude.
 
 [Gitso]: https://code.google.com/archive/p/gitso/
 [more recent fork]: https://github.com/AustP/Gitso

add note about javascript terminal emulator
diff --git a/code/debug-me/discussion.mdwn b/code/debug-me/discussion.mdwn
index b7a85a7..30bfab7 100644
--- a/code/debug-me/discussion.mdwn
+++ b/code/debug-me/discussion.mdwn
@@ -9,6 +9,7 @@ Some similar projects you may be interested in looking at, if only for "how not
 * [Iodine][] - IP over DNS tunnel, when even Tor fails
 * [Mosh][] - the mobile shell, interesting concepts of local terminal emulation and predictive capabilities
 * [Monkeysphere][] - OpenPGP web of trust applied to SSH and HTTP servers and clients
+* [watch-my-terminal][] - Allows a remote user to watch your terminal session via any modern browser (script+node on the broadcaster side, javascript on the watchers' side). Terminal emulation quite good; it correctly renders vim, less and aptitude.
 
 [Gitso]: https://code.google.com/archive/p/gitso/
 [more recent fork]: https://github.com/AustP/Gitso
@@ -17,5 +18,6 @@ Some similar projects you may be interested in looking at, if only for "how not
 [Iodine]: http://code.kryo.se/iodine/
 [Mosh]: https://mosh.mit.edu/
 [Monkeysphere]: http://web.monkeysphere.info
+[watch-my-terminal]: https://jasonwoof.com/gitweb/?p=watch-my-terminal.git;a=tree
 
 It would seem to me preferable to reuse existing components (SSH, especially) instead of reinventing the wheel too much here. So much trouble with terminal emulation and so on, as I am sure you know...

comment
diff --git a/blog/entry/Patreon/comment_2_1b260c0748b78fd1182dadade97e4b34._comment b/blog/entry/Patreon/comment_2_1b260c0748b78fd1182dadade97e4b34._comment
new file mode 100644
index 0000000..bb1c9a0
--- /dev/null
+++ b/blog/entry/Patreon/comment_2_1b260c0748b78fd1182dadade97e4b34._comment
@@ -0,0 +1,20 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 2"""
+ date="2016-08-03T22:46:52Z"
+ content="""
+@anarcat, <https://snowdrift.coop/p/snowdrift/w/othercrowdfunding>
+is the canonical comparison of pretty much every crowdfunding site 
+from a FLOSS perspective.
+
+I'm using Patreon because they have monthly payments automated and are a
+well known name in the space that is probably not going away anytimee soon.
+Also ESR has a semi-successful Patreon account. Although I'm no ESR (thank
+goodness).
+
+The only perhaps better option from a FLOSS POV would be Gratipay (which
+used to be called Gittip), but when I looked at it some time ago I didn't
+get the feeling it would work as well. I'd prefer to use Snowdrift (and
+have supported them both financially and with code) but it's not live yet.
+Self-hosting is unfortunately probably not feasible.
+"""]]

Added a comment: why patreon?
diff --git a/blog/entry/Patreon/comment_1_00a4334a27d9645b79d402a823530937._comment b/blog/entry/Patreon/comment_1_00a4334a27d9645b79d402a823530937._comment
new file mode 100644
index 0000000..9d9df56
--- /dev/null
+++ b/blog/entry/Patreon/comment_1_00a4334a27d9645b79d402a823530937._comment
@@ -0,0 +1,13 @@
+[[!comment format=mdwn
+ username="https://id.koumbit.net/anarcat"
+ subject="why patreon?"
+ date="2016-08-03T21:59:38Z"
+ content="""
+Hi!
+
+First of all, best of luck in your next funding project. I hope everything goes according to your wishes, and it seems Patreon has the potential of accomplishing that in the long term, which is great.
+
+I am curious, however, to hear your opinion on the different crowdfunding models. I know you have experimented with Kickstarter, your own site, Flattr, and now Patreon... and probably more I do not know about. Your opinion on those various tools and platforms would be very valuable for other developers looking at similar experiments...
+
+Thanks!
+"""]]

some ideas of simillar projects
diff --git a/code/debug-me/discussion.mdwn b/code/debug-me/discussion.mdwn
new file mode 100644
index 0000000..b7a85a7
--- /dev/null
+++ b/code/debug-me/discussion.mdwn
@@ -0,0 +1,21 @@
+Prior art
+=========
+
+Some similar projects you may be interested in looking at, if only for "how not to do things" ideas:
+
+* [Gitso][] ([more recent fork][]) - reverse VNC connector: lacks strong authentication and the web of trust, delegates firewall issues to the developer, gives full access to the developer, cross-platform
+* [Corkscrew][] - SSH over HTTP tunnel, allows you to run whatever on top of even the most restrictive firewalls
+* [Tor][] - useful to bypass fascist firewalls, NAT and all sort of restrictive technologies, even if both ends are behind NAT, keeps both ends geolocation more private
+* [Iodine][] - IP over DNS tunnel, when even Tor fails
+* [Mosh][] - the mobile shell, interesting concepts of local terminal emulation and predictive capabilities
+* [Monkeysphere][] - OpenPGP web of trust applied to SSH and HTTP servers and clients
+
+[Gitso]: https://code.google.com/archive/p/gitso/
+[more recent fork]: https://github.com/AustP/Gitso
+[Corkscrew]: https://en.wikipedia.org/wiki/Corkscrew_(program)
+[Tor]: https://www.torproject.org/
+[Iodine]: http://code.kryo.se/iodine/
+[Mosh]: https://mosh.mit.edu/
+[Monkeysphere]: http://web.monkeysphere.info
+
+It would seem to me preferable to reuse existing components (SSH, especially) instead of reinventing the wheel too much here. So much trouble with terminal emulation and so on, as I am sure you know...

remove flattr buttons, add patreaon in one place
diff --git a/blog.mdwn b/blog.mdwn
index ed4c232..89195b3 100644
--- a/blog.mdwn
+++ b/blog.mdwn
@@ -7,9 +7,6 @@ show="10"
 actions=yes]]
 
 [[!sidebar content="""
-<a href="http://flattr.com/thing/39887/Joey-Hesss-blog" target="_blank">
-<img src="https://api.flattr.com/button/flattr-badge-large.png" alt="Flattr this" title="Flattr this" border="0" /></a>
-
 [[!calendar pages="blog/entry/* and !blog/entry/*/* and !*/Discussion"]]
 
 [[!calendar pages="blog/entry/* and !blog/entry/*/* and !*/Discussion" year=-1]]
diff --git a/code/alien.mdwn b/code/alien.mdwn
index 88c59c0..de043f5 100644
--- a/code/alien.mdwn
+++ b/code/alien.mdwn
@@ -52,9 +52,3 @@ I've blogged a few times about alien.
 examines who I think is using alien now, and 
 [[this_post|blog/entry/ten_years_of_free_software_--_part_4_alien]] gives
 some historical background.
-
-[[!sidebar content="""
-<a href="http://flattr.com/thing/39936/Alien" target="_blank">
-<img src="http://api.flattr.com/button/button-static-50x60.png" alt="Flattr
-this" title="Flattr this" border="0" /></a>
-"""]]
diff --git a/code/debhelper.mdwn b/code/debhelper.mdwn
index b0dabf3..a662fcd 100644
--- a/code/debhelper.mdwn
+++ b/code/debhelper.mdwn
@@ -30,8 +30,3 @@ maintaining support for said obscure thing.
 My first rule of thumb is that at least ten packages need to be obvious
 benefactors of a feature or command before it's added to debhelper. That's
 an easy bar; after that I have to do some thinking and make the hard call.
-
-[[!sidebar content="""
-<a href="http://flattr.com/thing/39941/Debhelper" target="_blank">
-<img src="http://api.flattr.com/button/button-static-50x60.png" alt="Flattr this" title="Flattr this" border="0" /></a>
-"""]]
diff --git a/code/dpkg-repack.mdwn b/code/dpkg-repack.mdwn
index 92d9ebb..cc646c6 100644
--- a/code/dpkg-repack.mdwn
+++ b/code/dpkg-repack.mdwn
@@ -10,9 +10,3 @@ upgrade it.
 
 `dpkg-repack` is available in git (`git://git.joeyh.name/dpkg-repack`),
 or of course, as a Debian package.
-
-[[!sidebar content="""
-<a href="http://flattr.com/thing/40412/dpkg-repack" target="_blank">
-<img src="http://api.flattr.com/button/button-static-50x60.png" alt="Flattr
-this" title="Flattr this" border="0" /></a>
-"""]]
diff --git a/code/etckeeper.mdwn b/code/etckeeper.mdwn
index f9a7f2b..053c693 100644
--- a/code/etckeeper.mdwn
+++ b/code/etckeeper.mdwn
@@ -12,8 +12,3 @@ of working with revision control.
 ## News
 
 [[!inline pages="code/etckeeper/news/* and !*/Discussion" show="3"]]
-
-[[!sidebar content="""
-<a href="http://flattr.com/thing/39940/etckeeper" target="_blank">
-<img src="http://api.flattr.com/button/button-static-50x60.png" alt="Flattr this" title="Flattr this" border="0" /></a>
-"""]]
diff --git a/code/github-backup.mdwn b/code/github-backup.mdwn
index 88c91c4..19531f8 100644
--- a/code/github-backup.mdwn
+++ b/code/github-backup.mdwn
@@ -5,8 +5,3 @@ Available in Debian, or <https://github.com/joeyh/github-backup>
 ## News
 
 [[!inline pages="code/github-backup/news/* and !*/Discussion" show="3"]]
-
-[[!sidebar content="""
-<a href="http://flattr.com/thing/572797/github-backup" target="_blank">
-<img src="http://api.flattr.com/button/button-static-50x60.png" alt="Flattr this" title="Flattr this" border="0" /></a>
-"""]]
diff --git a/code/moreutils.mdwn b/code/moreutils.mdwn
index 2d86904..f9db7a8 100644
--- a/code/moreutils.mdwn
+++ b/code/moreutils.mdwn
@@ -214,8 +214,3 @@ include.
 
   Applies a sed pattern to a list of files to rename them. Rejected because
   perl has a `rename` program that works nearly identically.
-
-[[!sidebar content="""
-<a href="http://flattr.com/thing/39933/moreutils" target="_blank">
-<img src="http://api.flattr.com/button/button-static-50x60.png" alt="Flattr this" title="Flattr this" border="0" /></a>
-"""]]
diff --git a/code/mpdtoys.mdwn b/code/mpdtoys.mdwn
index 9309466..5f1326f 100644
--- a/code/mpdtoys.mdwn
+++ b/code/mpdtoys.mdwn
@@ -15,8 +15,3 @@ The mpdtoys are available in git at `git://git.joeyh.name/mpdtoys`, or
 ## News
 
 [[!inline pages="code/mpdtoys/news/* and !*/Discussion" show="3"]]
-
-[[!sidebar content="""
-<a href="http://flattr.com/thing/39938/mpdtoys" target="_blank">
-<img src="http://api.flattr.com/button/button-static-50x60.png" alt="Flattr this" title="Flattr this" border="0" /></a>
-"""]]
diff --git a/thanks.mdwn b/thanks.mdwn
index 5c57890..0111ed0 100644
--- a/thanks.mdwn
+++ b/thanks.mdwn
@@ -3,8 +3,6 @@ I do, a note is always the best way to make me happy, but here are some
 more tangible options:
 
 * paypal joey@kitenet.net
-* <a href="http://flattr.com/thing/39887/Joey-Hesss-blog" target="_blank">
-  <img src="http://api.flattr.com/button/flattr-badge-large.png" alt="Flattr me" title="Flattr me" border="0" />
-  </a>
+* [support me on Patream](https://patreon.com/joeyh)
 * [My Amazon wishlist](http://www.amazon.com/gp/registry/registry.html/104-5960215-8415137?ie=UTF8&type=wishlist&id=H9MGKNPCYVS2)
 * bitcoin address: <a href="bitcoin:[[!inline raw=yes pages=bitcoin]]">[[!inline raw=yes pages=bitcoin]]</a>

blog update
diff --git a/blog/entry/Patreon.mdwn b/blog/entry/Patreon.mdwn
new file mode 100644
index 0000000..d7bc77a
--- /dev/null
+++ b/blog/entry/Patreon.mdwn
@@ -0,0 +1,24 @@
+I've been funded for two years by the [DataLad](https://datalad.org/)
+project to work on git-annex. This has been a super excellent gig; they provided
+funding and feedback on ways git-annex could be improved, and I had a large
+amount of flexability to decide what to work on in git-annex.
+Also plenty of spare time to work on new projects like
+[[code/propellor]], [[code/concurrent-output]], and [[code/scroll]].
+It was an awesome way to spend the last two years of my 
+[[twenty_years_of_free_software|twenty_years_of_free_software_--_part_1_ikiwiki]].
+
+That funding is running out. I'd like to continue this great streak of
+working on the free software projects that are important to me. I'd
+normally dip into my savings at this point and keep on going until
+some other source of funding turned up. But, my savings are about to be
+obliterated, since I'm [[buying_the_place|hackerholler]] where
+I've had so much success working distraction-free.
+
+So, I've started **[a Patreon page](https://www.patreon.com/joeyh)** 
+to fund my ongoing work. Please check it out and contribute if you want to.
+
+Some details about projects I want to work on this fall:
+
+* [make debugging easier by building debug-me](https://www.patreon.com/posts/debug-me-6145970)
+* [adding type level port conflict detection to Propellor](https://www.patreon.com/posts/adding-type-port-6145901)
+* [finishing up git-annex v6 repository mode](https://www.patreon.com/posts/git-annex-v6-6145825)

foo
diff --git a/blog/entry/PocketCHIP_quick_review.mdwn b/blog/entry/PocketCHIP_quick_review.mdwn
index d985fb4..a27d8e7 100644
--- a/blog/entry/PocketCHIP_quick_review.mdwn
+++ b/blog/entry/PocketCHIP_quick_review.mdwn
@@ -15,7 +15,8 @@ niche.
 
 Unless you're into hardware hacking and want to hook wires up to the GPIO
 pins, the best hardware feature is the complete keyboard, with even 
-Escape and Control and arrow keys. You can ssh around and run vi on it, etc.
+Escape and Control and arrow keys. You can ssh around and run vi on it,
+run your favorite REPL (I use ghci) to do quick programming, etc.
 The keyboard is small and a little strange, but you get used
 to it quickly; your QWERTY muscle memory is transferrable to it.
 I had fun installing nethack on it and handing it to my sister who

foo
diff --git a/blog/entry/PocketCHIP_quick_review.mdwn b/blog/entry/PocketCHIP_quick_review.mdwn
index 5414b32..d985fb4 100644
--- a/blog/entry/PocketCHIP_quick_review.mdwn
+++ b/blog/entry/PocketCHIP_quick_review.mdwn
@@ -47,7 +47,7 @@ network-manager in some way and I wasn't able to find the corresponding source.)
 
 The battery life is around 5 hours. Unfortunately the "sleep" mode only
 turns off the backlight and maybe wifi, and leaves the rest of the system
-running. This and the slightly awkard form factor too big to really
+running. This and the slightly awkward form factor too big to really
 comfortably fit in a pocket limit the use of PocketCHIP quite a bit.
 Perhaps the sleeping will get sorted out, and perhaps I'll delete the GPIO
 breakout board from the top of mine to make it more pocket sized.

foo
diff --git a/blog/entry/PocketCHIP_quick_review.mdwn b/blog/entry/PocketCHIP_quick_review.mdwn
index 90a9928..5414b32 100644
--- a/blog/entry/PocketCHIP_quick_review.mdwn
+++ b/blog/entry/PocketCHIP_quick_review.mdwn
@@ -15,8 +15,8 @@ niche.
 
 Unless you're into hardware hacking and want to hook wires up to the GPIO
 pins, the best hardware feature is the complete keyboard, with even 
-Escape and Control and arrow keys. You can play nethack on it, you can run
-vi on it, etc. The keyboard is small and a little strange, but you get used
+Escape and Control and arrow keys. You can ssh around and run vi on it, etc.
+The keyboard is small and a little strange, but you get used
 to it quickly; your QWERTY muscle memory is transferrable to it.
 I had fun installing nethack on it and handing it to my sister who
 had never played nethack before, to watch her learn to play.

blog update
diff --git a/blog/entry/PocketCHIP_quick_review.mdwn b/blog/entry/PocketCHIP_quick_review.mdwn
new file mode 100644
index 0000000..90a9928
--- /dev/null
+++ b/blog/entry/PocketCHIP_quick_review.mdwn
@@ -0,0 +1,53 @@
+[PocketCHIP](https://getchip.com/pages/pocketchip) is the pocket sized
+Linux terminal I always used to want. Which is to say, it runs (nearly)
+stock Debian, X, etc, it has a physical keyboard, and the hardware and
+software is (nearly) non-proprietary and very hackable. Best of all, it's
+fun and it encourages playful learning.
+
+It's also clunky and flawed and constructed out of cheap components.
+This keeps it from being something I'd actually carry around in my pocket
+and use regularly. The smart thing they've done though is embrace these
+limitations, targeting it at the hobbiest, and not trying to compete with
+smart phones. The PocketCHIP is its own little device in its own little
+niche.
+
+<img src="https://cdn.shopify.com/s/files/1/1065/9514/t/15/assets/pcoverview.jpg?8333739622326240485" alt="PocketCHIP front, side, and back views">
+
+Unless you're into hardware hacking and want to hook wires up to the GPIO
+pins, the best hardware feature is the complete keyboard, with even 
+Escape and Control and arrow keys. You can play nethack on it, you can run
+vi on it, etc. The keyboard is small and a little strange, but you get used
+to it quickly; your QWERTY muscle memory is transferrable to it.
+I had fun installing nethack on it and handing it to my sister who
+had never played nethack before, to watch her learn to play.
+
+The screen resolution is 480x272, which is pretty tiny. And, it's a cheap
+resistive touchscreen, with a bezil around it. This makes it very hard to
+use scroll bars and icons near the edge of the screen. The customized 
+interface that ships with it avoids these problems, and so I've been using
+that for now. When I have time, I plan to put a fullscreen window
+manager on it, and write a [[code/pdmenu]] menu configuration for it, so
+everything can be driven using the keyboard.
+
+I also have not installed Debian from scratch on it yet. This would be
+tricky because it uses a somewhat patched kernel (to support the display
+and wifi). The shipped distribution is sadly not entirely free software.
+There are some nonfree drivers and firmwares. And, they included a non-free
+gaming environment on it (a very nice one for part of the audience, that
+allows editing the games, but non-free nevertheless). They did do a good
+job of packaging up all the custom software they include on it, although
+they don't seem to have 
+[published source packages for everything](https://bbs.nextthing.co/t/dear-next-thing-suggest-adding-debian-source-packages/3968).
+
+(They might be infringing my GPL copyright of flash-kernel by distributing
+a modified version without source. I say "might" because flash-kernel is
+a pile of shell scripts, so you could probably extract the (probably
+trivial) modifications. Still.. Also, they seem to have patched
+network-manager in some way and I wasn't able to find the corresponding source.)
+
+The battery life is around 5 hours. Unfortunately the "sleep" mode only
+turns off the backlight and maybe wifi, and leaves the rest of the system
+running. This and the slightly awkard form factor too big to really
+comfortably fit in a pocket limit the use of PocketCHIP quite a bit.
+Perhaps the sleeping will get sorted out, and perhaps I'll delete the GPIO
+breakout board from the top of mine to make it more pocket sized.

update
diff --git a/blog/entry/hackerholler.mdwn b/blog/entry/hackerholler.mdwn
index 2b4063a..5f4c6ba 100644
--- a/blog/entry/hackerholler.mdwn
+++ b/blog/entry/hackerholler.mdwn
@@ -39,6 +39,4 @@ Update: That was too much to hope for as it turned out. But,
 this post did lead to some possibilities, which might let me afford
 the place. Stay tuned.
 
-<img src="https://hackerholler.branchable.com/woodstove.jpg">
-
 [[!meta author=Joey]]

update
diff --git a/blog/entry/hackerholler.mdwn b/blog/entry/hackerholler.mdwn
index 9e89a1c..2b4063a 100644
--- a/blog/entry/hackerholler.mdwn
+++ b/blog/entry/hackerholler.mdwn
@@ -35,11 +35,9 @@ a creek.
 Could we put all this together somehow? Might a handful of my friends
 be able to contribute somewhere in the range of $10 thousand to buy in?
 
-Interested? Want more details? Have ideas?  
-<b>Visit the <a href="https://hackerholler.branchable.com/">Hacker Holler website</a>
-and get in touch.</b>
-
-(Limited to folks I've met in person or spent a lot of time online with.)
+Update: That was too much to hope for as it turned out. But,
+this post did lead to some possibilities, which might let me afford
+the place. Stay tuned.
 
 <img src="https://hackerholler.branchable.com/woodstove.jpg">
 

scale
diff --git a/pics/brazil/2014/circle.jpg b/pics/brazil/2014/circle.jpg
index f95e45a..b966dec 100644
Binary files a/pics/brazil/2014/circle.jpg and b/pics/brazil/2014/circle.jpg differ

pic
diff --git a/pics/brazil/2014/circle.jpg b/pics/brazil/2014/circle.jpg
new file mode 100644
index 0000000..f95e45a
Binary files /dev/null and b/pics/brazil/2014/circle.jpg differ

wrinkle
diff --git a/code/debug-me.mdwn b/code/debug-me.mdwn
index 51340b0..c00b324 100644
--- a/code/debug-me.mdwn
+++ b/code/debug-me.mdwn
@@ -92,6 +92,13 @@ Asynchronous inputs are only used for sending signals, eg ctrl-c, not for
 sending keystrokes. This allows interruption of a running command at any
 time, without needing to catch up to its most recent output.
 
+It might seem like a good idea for a client to resend a rejected input,
+rebasing it on top of the new output. But, if a client did this, its user
+would have plausible deniability about what they intended that input to do.
+Perhaps they were not sending Y in response to "delete disk?", but to a
+previous question. So, inputs should not be resent. To prevent that,
+no message is sent to indicate when an input is rejected.
+
 Synchronous input interacts badly with terminal echo, because sending an
 input causes an echo output, and if that output has not been received by the
 time the next letter is input, the next input sent will be rejected. To

improved
diff --git a/code/debug-me.mdwn b/code/debug-me.mdwn
index 402018b..51340b0 100644
--- a/code/debug-me.mdwn
+++ b/code/debug-me.mdwn
@@ -32,29 +32,6 @@ being debugged.
 
 ### design
 
-#### interface
-
-Interface is as close to a ssh session as possible.
-
-It can be important to match terminal sizes, to make sure the developer
-is seeing same thing as the user. `debug-me` can assist with this by
-drawing a box and having the developer resize the terminal to enclose it,
-when the terminal sizes vary.
-
-It would be possible to have the user manually vet inputs and outputs,
-rather than generating a GPG signed proof of the developer's activity.
-But, this would significantly complicate things, by needing to display
-on the user's terminal what inputs and outputs remain to be vetted.
-The complication of implementing that does not seem worth it.
-Especially because manual vetting would introduce lag.
-
-The user can input stuff, just as well as the developer.
-
-It might be nice to have an integrated chat, but again this complicates
-the terminal handing significantly. User and developer can just as well
-chat on IRC anyway. Or run `screen` within `debug-me` and use one window
-to chat in.
-
 #### client-server
 
 This needs to be client-server, because a end user's machine is probably
@@ -69,40 +46,9 @@ gets an URL, which developers' clients can connect to in order to enter
 the session. Sharing that URL should be the only way for anyone to view
 the session (other than the person running the HTTP server).
 
-#### proof
-
-The developer activity proof takes the form of a chain of outputs and inputs.
-In other words, what the developer was shown, and what they did in response,
-and so on. Each input is GPG signed and includes SHA256 hashes of
-previous messages.
-
-A `debug-me` session starts by sending an initial output to the
-developer. Probably this is a shell prompt. (To prevent replay attacks
-of debug-me sessions it should also include a timestamp and/or a random token.)
-
-The developer enters a command, and their client hashes the previous output
-and includes that in a GPG signed message with the command. The ouput of
-the command then arrives, and is hashed and included in the next GPG signed
-input message, and so on.
-
-Note that an input is only accepted if it includes the hashes of
-the previous input (if any) and all outputs since the previous input.
-
-A race is possible, where the developer's client sends an input before
-receiving a new output, and so their input is rejected. Their client can
-deal with this by re-sending the input, including the hash of the new
-output. Problem: If new output is constantly arriving, an input of eg
-ctrl-c to interrupt it may never be accepted. Perhaps an input should
-instead be accepted as long as it includes a hash of any of a recent
-output? Would that be as secure? It may give a developer plausible
-deniability, that they did not mean to send "y" in response to "format
-disk?" but in response to the previous output. Even resending inputs
-on race can give some plausible deniability about what the developer
-saw when they made the input.
-
 Multiple clients can be connected, and all send inputs. The user's
-client will only accept inputs GPG signed with keys that the user has
-granted access.
+client will only accept inputs GPG signed with keys that the user
+has granted access.
 
 When a new client connects, the whole session is sent to it, so it
 gets caught up and can start adding inputs to the chain.
@@ -112,11 +58,80 @@ to run `debug-me` on another computer, to record the developer activity proof
 there. This way a very Evil developer can't delete the user's only copy of
 the proof of their Evil.
 
-The server can also record the session, but this doesn't help if the
+The server can also record the session. This doesn't help if the
 developer is running the server. But if there are multiple servers
 run by different people, the user's client could send the session to
 several of them to get it recorded.
 
+#### proof
+
+The developer activity proof takes the form of a chain of outputs and inputs.
+In other words, what the developer was shown, and what they did in response,
+and so on. Each input is GPG signed and includes the SHA256 hash of a
+previous output or input.
+
+A `debug-me` session starts by generating an initial output.
+Probably this is a shell prompt. (To prevent replay attacks
+of debug-me sessions it should also include a timestamp and/or a random token.)
+
+The developer enters a command, and their client hashes the last seen
+output and includes that in a GPG signed message with the command. The
+ouput of the command then arrives, and is hashed and included in the next
+GPG signed input message, and so on.
+
+There are two kinds of inputs: Synchronous and asynchronous.
+
+A synchronous input must include the hash of the output that it was made
+in response to, and will only be accepted by the user's client when that
+output is the last one that was sent. This way it's always clear what
+the state of the debug-me session was when the developer saw the output
+and entered a given input.
+
+An asynchronous input must include the hash of the previous input.
+Asynchronous inputs are only used for sending signals, eg ctrl-c, not for
+sending keystrokes. This allows interruption of a running command at any
+time, without needing to catch up to its most recent output.
+
+Synchronous input interacts badly with terminal echo, because sending an
+input causes an echo output, and if that output has not been received by the
+time the next letter is input, the next input sent will be rejected. To
+deal with this, an input can include an echo block. If the echo block has
+the same content as the sum of outputs sent since the output that the input
+is in response to, then the input will be accepted.
+
+For example:
+
+	1. output "prompt>"
+	2. input "t" (previous: 1)
+	3. output "t" (previous: 2)
+	4. input "o" (previous: 1, echo: "t") -- valid because "t" = 3
+	5. output "o" (previous: 4)
+	6. input "p" (1, echo: "to") -- valid because "to" = 3+5
+	7. output: "p" (previous: 6)
+
+#### interface
+
+Interface is as close to a ssh session as possible.
+
+The user can input stuff, just as well as the developer.
+
+It can be important to match terminal sizes, to make sure the developer
+is seeing same thing as the user. `debug-me` can assist with this by
+drawing a box and having the developer resize the terminal to enclose it,
+when the terminal sizes vary.
+
+It would be possible to have the user manually vet inputs and outputs,
+rather than generating a GPG signed proof of the developer's activity.
+But, this would significantly complicate things, by needing to display
+on the user's terminal what inputs and outputs remain to be vetted.
+The complication of implementing that does not seem worth it.
+Especially because manual vetting would introduce lag.
+
+It might be nice to have an integrated chat, but again this complicates
+the terminal handing significantly. User and developer can just as well
+chat on IRC anyway. Or run `screen` within `debug-me` and use one window
+to chat in.
+
 #### installation
 
 For `debug-me` to be most useful, it will need to be included in major

tweaks
diff --git a/code/debug-me.mdwn b/code/debug-me.mdwn
index 19a1c05..402018b 100644
--- a/code/debug-me.mdwn
+++ b/code/debug-me.mdwn
@@ -77,10 +77,13 @@ and so on. Each input is GPG signed and includes SHA256 hashes of
 previous messages.
 
 A `debug-me` session starts by sending an initial output to the
-developer. Probably this is a shell prompt. The developer enters a command,
-and their client hashes the previous output and includes that in a GPG signed
-message with the command. The ouput of the command then arrives, and is
-hashed and included in the next GPG signed input message, and so on.
+developer. Probably this is a shell prompt. (To prevent replay attacks
+of debug-me sessions it should also include a timestamp and/or a random token.)
+
+The developer enters a command, and their client hashes the previous output
+and includes that in a GPG signed message with the command. The ouput of
+the command then arrives, and is hashed and included in the next GPG signed
+input message, and so on.
 
 Note that an input is only accepted if it includes the hashes of
 the previous input (if any) and all outputs since the previous input.
@@ -88,7 +91,14 @@ the previous input (if any) and all outputs since the previous input.
 A race is possible, where the developer's client sends an input before
 receiving a new output, and so their input is rejected. Their client can
 deal with this by re-sending the input, including the hash of the new
-output.
+output. Problem: If new output is constantly arriving, an input of eg
+ctrl-c to interrupt it may never be accepted. Perhaps an input should
+instead be accepted as long as it includes a hash of any of a recent
+output? Would that be as secure? It may give a developer plausible
+deniability, that they did not mean to send "y" in response to "format
+disk?" but in response to the previous output. Even resending inputs
+on race can give some plausible deniability about what the developer
+saw when they made the input.
 
 Multiple clients can be connected, and all send inputs. The user's
 client will only accept inputs GPG signed with keys that the user has
@@ -99,8 +109,13 @@ gets caught up and can start adding inputs to the chain.
 
 Other clients can connect and only record the session. This allows a user
 to run `debug-me` on another computer, to record the developer activity proof
-there. This way a very Evil developer can't delete the user's
-only copy of the proof of their Evil.
+there. This way a very Evil developer can't delete the user's only copy of
+the proof of their Evil.
+
+The server can also record the session, but this doesn't help if the
+developer is running the server. But if there are multiple servers
+run by different people, the user's client could send the session to
+several of them to get it recorded.
 
 #### installation
 

clarif
diff --git a/code/debug-me.mdwn b/code/debug-me.mdwn
index 5789259..19a1c05 100644
--- a/code/debug-me.mdwn
+++ b/code/debug-me.mdwn
@@ -73,8 +73,8 @@ the session (other than the person running the HTTP server).
 
 The developer activity proof takes the form of a chain of outputs and inputs.
 In other words, what the developer was shown, and what they did in response,
-and so on. Each input is GPG signed and includes the SHA256 hashes of one or
-more outputs that came before it.
+and so on. Each input is GPG signed and includes SHA256 hashes of
+previous messages.
 
 A `debug-me` session starts by sending an initial output to the
 developer. Probably this is a shell prompt. The developer enters a command,