Skip site navigation (1)Skip section navigation (2)
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>