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]
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
|
||||||
|
|
Loading…
Reference in a new issue