copy in some of the proposed designs
[Imported from Trac: page NewMutableEncodingDesign, version 2]
parent
2490e8ab87
commit
e5874c99d9
|
@ -41,3 +41,142 @@ directly in the filecap, simplifying the design considerably.
|
||||||
easier and remove one need for an encrypted channel (lease secrets would
|
easier and remove one need for an encrypted channel (lease secrets would
|
||||||
continue to need protection unless/until they too are replaced with
|
continue to need protection unless/until they too are replaced with
|
||||||
signature verification). However, it would also increase server load.
|
signature verification). However, it would also increase server load.
|
||||||
|
|
||||||
|
## Filecap Length
|
||||||
|
|
||||||
|
A likely security parameter K (=kappa) would be 96 or 128 bits, and most of
|
||||||
|
the filecaps will be some multiple of K.
|
||||||
|
|
||||||
|
Assuming a `tahoe:` prefix and no additional metadata, here's what
|
||||||
|
various lengths of base62-encoded filecaps would look like:
|
||||||
|
|
||||||
|
* 1*K:
|
||||||
|
* 96 `tahoe:14efs6T5YNim0vDVV`
|
||||||
|
* 128 `tahoe:4V2uIYVX0PcHu9fQrJ3GSH`
|
||||||
|
* 2*K:
|
||||||
|
* 192 `tahoe:072Og6e75IOP9ZZsbR1Twjs6X5xXJnBAF`
|
||||||
|
* 256 `tahoe:fZeioazoWrO62reiAjzUAyV0uz3ssh6Hnanv8cKMClY`
|
||||||
|
* 3*K:
|
||||||
|
* 288 `tahoe:11DriaxD9nipA10ueBvv5uoMoehvxgPerpQiXyvMPeiUUdtf6`
|
||||||
|
* 384 `tahoe:3a31SqUbf8fpWE1opRCT3coDhRqTU7bDU2AvC3RQJBu6ZNFhVscyxA9slYtPVT79x`
|
||||||
|
|
||||||
|
Adding 2 metadata characters and a clear separator gives us:
|
||||||
|
|
||||||
|
* 96: `tahoe:MW-14efs6T5YNim0vDVV`
|
||||||
|
* 128: `tahoe:DW-4V2uIYVX0PcHu9fQrJ3GSH`
|
||||||
|
* 192: `tahoe:MR-072Og6e75IOP9ZZsbR1Twjs6X5xXJnBAF`
|
||||||
|
* 256: `tahoe:DR-fZeioazoWrO62reiAjzUAyV0uz3ssh6Hnanv8cKMClY`
|
||||||
|
* 288: `tahoe:MR-11DriaxD9nipA10ueBvv5uoMoehvxgPerpQiXyvMPeiUUdtf6`
|
||||||
|
* 384: `tahoe:MR-3a31SqUbf8fpWE1opRCT3coDhRqTU7bDU2AvC3RQJBu6ZNFhVscyxA9slYtPVT79x`
|
||||||
|
|
||||||
|
# Design Proposals
|
||||||
|
|
||||||
|
## Commonalities
|
||||||
|
|
||||||
|
* 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
|
||||||
|
blocks, and a second one over the ciphertext segments.
|
||||||
|
* we'd like to add a merkle tree over the plaintext, without reintroducing
|
||||||
|
the partial-information-guessing attack that prompted us to remove it.
|
||||||
|
This means encrypting the nodes of this merkle tree with a key derived
|
||||||
|
from the readcap.
|
||||||
|
* We'll continue to use the signing layout of the current mutable files:
|
||||||
|
there will be a UEB that includes the root of the hash trees (and
|
||||||
|
everything else in the share), which will be hashed to compute the
|
||||||
|
"roothash" (which changes with each publish). A block of data that
|
||||||
|
includes the roothash and a sequence number (as well as any
|
||||||
|
data-encrypting salt) will be signed.
|
||||||
|
* It might be good to make the layout a bit more extensible, like the way
|
||||||
|
that immutable files have a dictionary-like structure for the UEB.
|
||||||
|
* In general, the share will always contain a full copy of the pubkey, for
|
||||||
|
the benefit of server-side validation. I don't think it matters whether
|
||||||
|
the pubkey is stored inside or outside of the signed block, but it will
|
||||||
|
probably make the upload-time share-verification code simpler to put it
|
||||||
|
inside.
|
||||||
|
* In general, the storage-index will be equal to the pubkey. If the pubkey
|
||||||
|
is too long for this, the storage-index will be a sufficiently-long secure
|
||||||
|
hash of the pubkey. The SI must be long enough to meet our
|
||||||
|
collision-resistance criteria.
|
||||||
|
|
||||||
|
## ECDSA, semi-private keys, no traversalcap
|
||||||
|
|
||||||
|
Zooko captured the current leading semi-private-key-using mutable file design
|
||||||
|
nicely in the ["StorageSS08" paper](http://allmydata.org/~zooko/lafs.pdf)
|
||||||
|
(in Figure 3). The design is:
|
||||||
|
|
||||||
|
* (1K) writecap = K-bit random string (perhaps derived from user-supplied
|
||||||
|
material) (remember, K=kappa, probably 128bits)
|
||||||
|
* (2K) readcap = 2*K-bit semiprivate key
|
||||||
|
* (2K) verifycap = 2*K-bit public key
|
||||||
|
* storage-index = truncated verifycap
|
||||||
|
|
||||||
|
On each publish, a random salt is generated and stored in the share. The data
|
||||||
|
is encrypted with H(salt, readcap) and the ciphertext stored in the share. We
|
||||||
|
store the usual merkle trees.
|
||||||
|
|
||||||
|
This provides offline attenuation and full server-side validation. It removes
|
||||||
|
the need to pull a copy of the pubkey or encprivkey from just one of the
|
||||||
|
servers (the salt must still be fetched, but it's small and lives in the
|
||||||
|
signed block that must be fetched anyways).
|
||||||
|
|
||||||
|
### add traversalcap
|
||||||
|
|
||||||
|
Like above, but create two levels of semiprivate keys instead of just one:
|
||||||
|
|
||||||
|
* (1K) writecap = K-bit random string
|
||||||
|
* (2K) readcap = 2*K-bit first semiprivate key
|
||||||
|
* (2K) traversalcap = 2*K-bit second semiprivate key
|
||||||
|
* (2K) verifycap = 2*K-bit public key
|
||||||
|
* storage-index = truncated verifycap
|
||||||
|
|
||||||
|
The dirnode encoding would use H(writecap) to protect the child writecaps,
|
||||||
|
H(readcap) to protect the child readcaps, and H(traversapcap) to protect the
|
||||||
|
child verifycap/traversalcaps.
|
||||||
|
|
||||||
|
## ECDSA, no semi-private keys, no traversalcap
|
||||||
|
|
||||||
|
Without semi-private keys, we need something more complicated to protect the
|
||||||
|
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
|
||||||
|
(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
|
||||||
|
private key out of the share and into the writecap:
|
||||||
|
|
||||||
|
* (1K) writecap = K-bit random string
|
||||||
|
* (3K) readcap = H(writecap)[:K] + H(pubkey)
|
||||||
|
* (2K) verifycap = H(pubkey)
|
||||||
|
* storage-index = truncated verifycap
|
||||||
|
|
||||||
|
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
|
||||||
|
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
|
||||||
|
confidentiality, but require 2*K bits on H(pubkey) to attain K-bit collision
|
||||||
|
resistance. The verifycap is 2*K.
|
||||||
|
|
||||||
|
### include pubkey in cap
|
||||||
|
|
||||||
|
Or, if the pubkey is short enough, include it in the cap rather than
|
||||||
|
requiring the client to fetch a copy:
|
||||||
|
|
||||||
|
* (1K) writecap = K-bit random string
|
||||||
|
* (3K) readcap = H(writecap)[:K] + pubkey
|
||||||
|
* (2K) verifycap = pubkey
|
||||||
|
* storage-index = H(pubkey)
|
||||||
|
|
||||||
|
I think ECDSA pubkeys are 2*K long, so this would not change the length of
|
||||||
|
the readcaps. It would just simplify/speed-up the download process. If we
|
||||||
|
could use shorter hashes, then the H(pubkey) design might give us slightly
|
||||||
|
shorter keys.
|
||||||
|
|
||||||
|
### add traversalcap
|
||||||
|
|
||||||
|
Since a secure pubkey identifier (either H(pubkey) or the original privkey)
|
||||||
|
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:
|
||||||
|
|
||||||
|
* (1K) writecap = K-bit random string
|
||||||
|
* (3K) readcap = H(writecap)[:K] + H(pubkey)
|
||||||
|
* (3K) traversalcap: H(readcap)[:K] + H(pubkey)
|
||||||
|
* (2K) verifycap = H(pubkey)
|
||||||
|
* storage-index = truncated verifycap
|
||||||
|
|
Loading…
Reference in a new issue