update for Ed25519, and fix a bug that would allow meet-in-the-middle attacks against the private exponent

[Imported from Trac: page NewMutableEncodingDesign, version 21]
davidsarah 2012-01-10 21:06:17 +00:00
parent db28fb6080
commit 730ec1c0e9

@ -32,7 +32,7 @@ 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 ECDSA keys are short enough (in most cases) to put and hashed as necessary. The Ed25519 keys are short enough (in most cases) to put
directly in the filecap, although note that this still increases the cap length directly in the filecap, although note that this still increases the cap length
relative to using a hash truncated to K+T bits. relative to using a hash truncated to K+T bits.
@ -84,7 +84,7 @@ Adding 2 metadata characters and a clear separator gives us:
* once we get the ciphertext, it gets segmented and erasure-coded in the * once we get the ciphertext, it gets segmented and erasure-coded in the
same way as immutable files. Shares include a merkle tree over the share same way as immutable files. Shares include a merkle tree over the share
blocks, and a second one over the ciphertext segments. blocks, and a second one over the ciphertext segments.
* we'd like to add a merkle tree over the plaintext, without reintroducing * we'd like to add a Merkle tree over the plaintext, without reintroducing
the partial-information-guessing attack that prompted us to remove it. the partial-information-guessing attack that prompted us to remove it.
This means encrypting the nodes of this merkle tree with a key derived This means encrypting the nodes of this merkle tree with a key derived
from the readcap. from the readcap.
@ -106,7 +106,7 @@ Adding 2 metadata characters and a clear separator gives us:
hash of the pubkey. The SI must be long enough to meet our hash of the pubkey. The SI must be long enough to meet our
collision-resistance criteria. collision-resistance criteria.
## ECDSA, semi-private keys, no traversalcap ## ECDSA or Ed25519, semi-private keys, no traversalcap
Zooko captured the current leading semi-private-key-using mutable file design Zooko captured the current leading semi-private-key-using mutable file design
nicely in the ["StorageSS08" paper](http://allmydata.org/~zooko/lafs.pdf) nicely in the ["StorageSS08" paper](http://allmydata.org/~zooko/lafs.pdf)
@ -147,11 +147,12 @@ Without semi-private keys, we need something more complicated to protect the
readkey: the only thing that can be mathematically derived from the writecap readkey: the only thing that can be mathematically derived from the writecap
is the pubkey, and that can't be used to protect the data because it's public is the pubkey, and that can't be used to protect the data because it's public
(and used by the server to validate shares). One approach is to use the (and used by the server to validate shares). One approach is to use the
current (discrete-log DSA) mutable file structure, and merely move the current mutable file structure (with any signature algorithm), and merely
private key out of the share and into the writecap: move the private key out of the share and into the writecap:
* (K + T) writecap = (K+T)-bit random string = privkey * (K + T) writecap = (K+T)-bit random string
* (2K + T) readcap = H(writecap)[:K] + H(pubkey)[:K+T] * (2K) privkey = H(writecap)
* (2K + T) readcap = H(privkey)[:K] + H(pubkey)[:K+T]
* (K + T) verifycap = H(pubkey)[:K+T] * (K + T) verifycap = H(pubkey)[:K+T]
* storage-index = verifycap * storage-index = verifycap
@ -163,31 +164,35 @@ on H(pubkey) to attain K-bit second-preimage resistance for 2^T^ targets. (To
obtain collision-resistance, set T = K, although that shouldn't be necessary obtain collision-resistance, set T = K, although that shouldn't be necessary
for mutable files.) The verifycap is K+T bits. for mutable files.) The verifycap is K+T bits.
### include ECDSA pubkey in cap ### include ECDSA or Ed25519 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:
* (K + T) writecap = (K+T)-bit random string = privkey * (K + T) writecap = (K+T)-bit random string
* (minimum 3K) readcap = H(writecap)[:K] + pubkey * (2K) privkey = H(writecap)
* (minimum 3K) readcap = H(privkey)[:K] + pubkey
* (minimum 2K) verifycap = pubkey * (minimum 2K) verifycap = pubkey
* storage-index = H(pubkey) * storage-index = H(pubkey)
ECDSA pubkeys are slightly more than 2*K long, so this would increase the The hash to obtain the privkey is necessary because directly using a (K+T)-bit
length of the readcaps whenever K > T. The advantage would be simplifying/speeding up exponent would allow meet-in-the-middle attacks. ECDSA or Ed25519 pubkeys are
the download process. It is highly unlikely that there is any public key algorithm slightly more than 2*K long, so this would increase the length of the readcaps
because 2*K > T. The advantage would be simplifying/speeding up the download
process. It is highly unlikely that there is any public key algorithm
with keys shorter than 2*K for a K-bit security level. Since we can use shorter with keys shorter than 2*K for a K-bit security level. Since we can use shorter
hashes than public keys, the H(pubkey) design above gives us shorter read caps, hashes than public keys, the H(pubkey) design above gives us shorter read caps,
although they are not shorter than using semi-private keys. although they are not shorter than using semi-private keys.
### Any signature algorithm, no semi-private keys, with traversalcap ### Any signature algorithm, no semi-private keys, with traversalcap
Since a secure pubkey identifier (either H(pubkey)[:K+T] or the original privkey) Since a secure pubkey identifier (either H(pubkey)[:K+T] or the original writecap)
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:
* (K + T) writecap = (K+T)-bit random string = privkey * (K + T) writecap = (K+T)-bit random string
* (2K + T) readcap = H(writecap)[:K] + H(pubkey)[:K+T] * (2K) privkey = H(writecap)
* (2K + T) readcap = H(privkey)[:K] + H(pubkey)[:K+T]
* (2K + T) traversalcap: H(readcap)[:K] + H(pubkey)[:K+T] * (2K + T) traversalcap: H(readcap)[:K] + H(pubkey)[:K+T]
* (K + T) verifycap = H(pubkey)[:K+T] * (K + T) verifycap = H(pubkey)[:K+T]
* storage-index = verifycap * storage-index = verifycap