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
|
||||
continue to need protection unless/until they too are replaced with
|
||||
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