update for multi-target attacks

[Imported from Trac: page NewMutableEncodingDesign, version 15]
davidsarah 2010-01-08 03:35:39 +00:00
parent e2f06eda11
commit 84430c96f9

@ -11,6 +11,16 @@ page is about the backend layout that would make those features possible.
* [this tahoe-dev message](http://allmydata.org/pipermail/tahoe-dev/2009-July/002345.html) and its neighbors have some good discussion about cap design for mutable files * [this tahoe-dev message](http://allmydata.org/pipermail/tahoe-dev/2009-July/002345.html) and its neighbors have some good discussion about cap design for mutable files
* [The Elk Point design](http://allmydata.org/pipermail/tahoe-dev/2009-September/002848.html) is very interesting, and has not yet been transcribed into this wiki page. * [The Elk Point design](http://allmydata.org/pipermail/tahoe-dev/2009-September/002848.html) is very interesting, and has not yet been transcribed into this wiki page.
# Parameters K and T
Below, K is the security level needed for an attack against confidentiality:
such attacks will require p * 2^K^ work factor (product of machine size and time)
for a probability of success p. T is the additional number of bits needed to take
into account
[multi-target attacks](http://allmydata.org/trac/tahoe/ticket/882#comment:6) against
hash functions, so that attacks against integrity also require p * 2^K^ work factor
for 2^T^ target files.
# Yay ECDSA # Yay ECDSA
Once we have ECDSA (#331), we'll have a general-purpose signing primitive Once we have ECDSA (#331), we'll have a general-purpose signing primitive
@ -22,8 +32,9 @@ signatures use 1216-*byte* signing keys, 292-byte verifying keys, and
The RSA fields are so large that we clearly cannot put them in the filecaps, The RSA fields are so large that we clearly cannot put them in the filecaps,
so the encoding scheme requires them to be stored in the shares, encrypted so the encoding scheme requires them to be stored in the shares, encrypted
and hashed as necessary. The DSA keys are short enough (in most cases) to put and hashed as necessary. The ECDSA keys are short enough (in most cases) to put
directly in the filecap, simplifying the design considerably. directly in the filecap, although note that this still increases the cap length
relative to using a hash truncated to K+T bits.
# Desired Features # Desired Features
@ -46,8 +57,8 @@ directly in the filecap, simplifying the design considerably.
## Filecap Length ## Filecap Length
A likely security parameter K (=kappa) would be 96, 128, or 160 bits, and most of A likely security parameter K (=kappa) would be 96, 128, or 160 bits.
the filecaps will be some multiple of K. [96 bits is too short IMHO --David-Sarah] [96 bits is too short IMHO --David-Sarah]
Assuming a `tahoe:` prefix and no additional metadata, here's what Assuming a `tahoe:` prefix and no additional metadata, here's what
various lengths of base62-encoded filecaps would look like: various lengths of base62-encoded filecaps would look like:
@ -82,7 +93,8 @@ if we don't need to prevent collisions, then we can use a K-bit hash for
K-bit second-pre-image resistance. However, see K-bit second-pre-image resistance. However, see
[#882:c6](http://allmydata.org/trac/tahoe/ticket/882#comment:6) for a [#882:c6](http://allmydata.org/trac/tahoe/ticket/882#comment:6) for a
counterargument saying that 50 extra bits or so are needed to be secure counterargument saying that 50 extra bits or so are needed to be secure
against multi-target attacks. against multi-target attacks (i.e. T = 50). This page has now been updated
assuming the counterargument is correct.
# Design Proposals # Design Proposals
@ -122,7 +134,7 @@ nicely in the ["StorageSS08" paper](http://allmydata.org/~zooko/lafs.pdf)
* (1K) writecap = K-bit random string (perhaps derived from user-supplied * (1K) writecap = K-bit random string (perhaps derived from user-supplied
material) (remember, K=kappa, probably 128bits) material) (remember, K=kappa, probably 128bits)
* (minimum 2K) readcap = minimum 2*K-bit semiprivate key * (minimum 2K) readcap = minimum 2*K-bit semiprivate key
* verifycap = 2*K-bit public key * (minimum 2K) verifycap = public key
* storage-index = truncated verifycap * storage-index = truncated verifycap
On each publish, a random salt is generated and stored in the share. The data On each publish, a random salt is generated and stored in the share. The data
@ -141,7 +153,7 @@ Like above, but create two levels of semiprivate keys instead of just one:
* (1K) writecap = K-bit random string * (1K) writecap = K-bit random string
* (minimum 2K) readcap = minimum 2*K-bit first semiprivate key * (minimum 2K) readcap = minimum 2*K-bit first semiprivate key
* (minimum 2K) traversalcap = minimum 2*K-bit second semiprivate key * (minimum 2K) traversalcap = minimum 2*K-bit second semiprivate key
* verifycap = 2*K-bit public key * (minimum 2K) verifycap = public key
* storage-index = truncated verifycap * storage-index = truncated verifycap
The dirnode encoding would use H(writecap) to protect the child writecaps, The dirnode encoding would use H(writecap) to protect the child writecaps,
@ -157,44 +169,46 @@ is the pubkey, and that can't be used to protect the data because it's public
current (discrete-log DSA) mutable file structure, and merely move the current (discrete-log DSA) mutable file structure, and merely move the
private key out of the share and into the writecap: private key out of the share and into the writecap:
* (1K) writecap = K-bit random string = privkey * (K) writecap = K-bit random string = privkey
* (3K) readcap = H(writecap)[:K] + H(pubkey) * (2K + T) readcap = H(writecap)[:K] + H(pubkey)[:K+T]
* verifycap = H(pubkey) * (K + T) verifycap = H(pubkey)[:K+T]
* storage-index = truncated verifycap * storage-index = truncated verifycap
In this case, the readcap/verifycap holder is obligated to fetch the pubkey In this case, the readcap/verifycap holder is obligated to fetch the pubkey
from one of the shares, since they cannot derive it themselves. This from one of the shares, since they cannot derive it themselves. This
preserves offline attenuation and server-side validation. The readcap grows preserves offline attenuation and server-side validation. The readcap grows
to (1+2)*K : we can truncate the AES key since we only need K bits for K-bit to 2K + T : we only need K bits for K-bit confidentiality, but require K+T bits
confidentiality, but require 2*K bits on H(pubkey) to attain K-bit collision on H(pubkey) to attain K-bit second-preimage resistance for 2^T^ targets. (To
resistance. The verifycap is 2*K. obtain collision-resistance, set T = K, although that shouldn't be necessary
for mutable files.) The verifycap is K+T bits.
### include ECDSA pubkey in cap ### include ECDSA pubkey in cap
Or, if the pubkey is short enough, include it in the cap rather than Or, if the pubkey is short enough, include it in the cap rather than
requiring the client to fetch a copy: requiring the client to fetch a copy:
* (1K) writecap = K-bit random string = privkey * (K) writecap = K-bit random string = privkey
* (minimum 3K) readcap = H(writecap)[:K] + pubkey * (minimum 3K) readcap = H(writecap)[:K] + pubkey
* verifycap = pubkey * (minimum 2K) verifycap = pubkey
* storage-index = H(pubkey) * storage-index = H(pubkey)
I think ECDSA pubkeys are 2*K long, so this would not change the length of ECDSA pubkeys are slightly more than 2*K long, so this would increase the
the readcaps. It would just simplify/speed-up the download process. If we length of the readcaps whenever K > T. The advantage would be simplifying/speeding up
could use shorter pubkeys, this design might give us slightly shorter keys. the download process. It is highly unlikely that there is any public key algorithm
Alternately, if we could use shorter hashes, then the H(pubkey) design might with keys shorter than 2*K for a K-bit security level. Since we can use shorter
give us slightly shorter keys. hashes than public keys, the H(pubkey) design above gives us shorter read caps,
although they are not shorter than using semi-private keys.
### Any public key algorithm, no semi-private keys, with traversalcap ### Any public key algorithm, no semi-private keys, with traversalcap
Since a secure pubkey identifier (either H(pubkey) or the original privkey) Since a secure pubkey identifier (either H(pubkey)[:K+T] or the original privkey)
is present in all caps, it's easy to insert arbitrary intermediate levels. It is present in all caps, it's easy to insert arbitrary intermediate levels. It
doesn't even change the way the existing caps are used: doesn't even change the way the existing caps are used:
* (1K) writecap = K-bit random string = privkey * (1K) writecap = K-bit random string = privkey
* (3K) readcap = H(writecap)[:K] + H(pubkey) * (2K + T) readcap = H(writecap)[:K] + H(pubkey)[:K+T]
* (3K) traversalcap: H(readcap)[:K] + H(pubkey) * (2K + T) traversalcap: H(readcap)[:K] + H(pubkey)[:K+T]
* verifycap = H(pubkey) * (K + T) verifycap = H(pubkey)[:K+T]
* storage-index = truncated verifycap * storage-index = truncated verifycap
## Shorter readcaps (insecure) ## Shorter readcaps (insecure)