Date: Mon, 28 Feb 2005 14:02:01 -0800 (PST) From: "ALeine" <aleine@austrosearch.net> To: elric@imrryr.org Cc: tech-security@NetBSD.org Subject: Re: RFC: backporting GEOM to the 4.x branch Message-ID: <200502282202.j1SM21qs042751@marlena.vvi.at>
next in thread | raw e-mail | index | archive | help
elric@imrryr.org wrote: > This does not work. The problem is that in GBDE for sector n > which is written, there are two operations: > > 1. change the key by which sector n is encrypted, and > 2. write sector n ecnrypted with the new key. > > If one of these fails, how could the write be ignored? If one of > the two completes but not both, then one is left in the situation > of either: > > 1. trying to decrypt the old sector with the new > encryption key, or No. > 2. trying to decrypt the new sector with the old > encryption key. Yes, the data sector is written first and then the key sector. Since, as you pointed out, GBDE is more susceptible to dictionary attacks than CGD one can then use this advantage (it's a feature, not a design flaw!) to recover the lost key so no data is lost. :-> Seriously, how can one make writing atomic without breaking compatibility with existing GBDE volumes? Which approach does CGD use to solve the problem of atomic writing? How about changing GBDE in a backwards-incompatible way by adding one key shadow sector for every n key sectors (n would be chosen at volume initialization)? The key shadow sector would hold the xor of the last encrypted key in the zone to be replaced and its replacement key, a 32 byte status chunk to indicate the status of the operation: all zeros (0x0) would indicate the new key has not been written to the key sector yet (but it is present in xor-ed form in the key shadow sector), all ones (0xFF) would indicate the new encrypted data sector has been written successfully and random garbage would indicate that both the new key and the encrypted data have been successfully written to disk. Then the relative offset of the key sector from the key shadow sector would follow and then the offset of the key within the key sector. The rest of the sector would also be padded with random garbage which would be regenerated every x writes (this value could be tunable via sysctl, kern.geom.bde.garbage_recycle_freq). The whole write procedure would look something like this: 1. read old key from key sector 2. xor-ed key = new key ^ old key 3. pad xor-ed key with: - status chunk: 32 0x0 characters - relative offset of key sector from key shadow sector (chosen at volume initialization, 8 bytes by default) - relative offset of key within key sector (8 bytes by default) 4. write padded xored key to key shadow sector 5. encrypt data with new key 6. write encrypted data to disk 7. set status chunk in key shadow sector to 0xFF 8. write new key to key sector 9. if (number of key writes % kern.geom.bde.garbage_recycle_freq == 0) then overwrite control chunk in key shadow sector and the rest of sector with random garbage else overwrite only control chunk in key shadow sector with random garbage (not to waste entropy) endif > Either way, the sector has been lost. Neither the original > contents of the sector nor the new contents can be recovered without > breaking AES-128. Fsck(8) does not contain this functionality (and it > would be rather impressive if it did.) The solution I proposed always provides consistent atomic writes. If only the encrypted data sector gets written and the key does not get written to the key sector, you can recover the new key by xor-ing the xor-ed key from the key shadow sector with the old key. That way fsck(8) would only need to walk through all the key shadow sectors and check for 0xFF status chunks and recover new keys automatically. Zero control chunks would have to be handled by the user since fsck(8) would have no way of telling whether a zero chunk means the newly encrypted data got written to disk (and the plug was pulled just before the control chunk was to be set to 0xFF) or not (the new key just got written to disk in xor-ed form, but the existing key and data are unchanged). The simplest way would be to let fsck(8) report and record all zero chunks in the form which could be fed to a utility which would set the key directly. The input (output generated by fsck(8)) for such a utility would consist of the device name, relative offset and the key. Both options would always be listed and then the user could try all the alternatives and see which key is the right one. There would be a performance hit, but I would like to see this implemented to see just how big the difference would be. What do you guys think of this solution? ALeine ___________________________________________________________________ WebMail FREE http://mail.austrosearch.net
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200502282202.j1SM21qs042751>