johnlane / grub

Grub with crypto extensions to support for DMCrypt and LUKS volumes with detached headers and key files.
GNU General Public License v3.0
50 stars 14 forks source link

Deniable encryption with encrypted key #6

Closed kriswebdev closed 8 years ago

kriswebdev commented 8 years ago

Hi and thanks for this project.

In the project page, I see no example method with both:

Ideally, I would:

To go further, the decrypted key could be used to decrypt a LUKS header located at the beginning of hd1,1. This would provide a UUID for the decrypted mount.

Can I achieve this using existing GRUB commands? Otherwise, where to start to develop this?

johnlane commented 8 years ago

Hi, the way I use this is with LUKS volumes with bootloader, headers and keys on a USB stick. The headers and keys are in an encrypted partition on the stick. So it boots, I select an option and enter a passphrase to reveal a second grub menu from which I boot.

But it isn't deniable if you have the USB stick as it will be obvious there is an encrypted partition on the stick that the bootloads has an option to open (by prompting user for passphrase). I guess you could do something where you use plain mode to open a deniable volume from the grub prompt and then chainload a second grub.cfg from that plain volume once it's unlocked. But I haven't tried to do that myself.

The LUKS header provides the ability to change the passphrase without re-encrypting the whole disk.

Unfortunately I got nowhere with upstream about getting this taken on board so haven't looked at it much for a while...

kriswebdev commented 8 years ago

Thanks for the ideas. I'll experiment this.

By the way, if you have time, you should merge upstream and this commit as it's necessary to stay compatible with upstream. I've did it after forking your project and merging upstream/master, it works. There's just 1 minor conflicting line of code when merging upstream by now.

kriswebdev commented 8 years ago

GRUB shell doesn't support pipes, but the built-in command line programs generally allow specifying files as blocklists, e.g. (hd0,1)0+1. However it must be by increments of sector-size (512 bytes).

Basically, what we need as an input is the location of the "payload" data, that must look like random data and that will be used as the encrypted keyfile/salt.

The best place to store it on disk is probably somewhere between the bootloader itself and the first partition.

Then this data should be processed by cryptomount --deny (hdW,X)Y+Z + passphrase:

  1. Either by generating a LUKS header with default settings, filled with the "payload" data (Master key payload, salt payload...)
  2. Or by processing it directly (decypher the key using the "payload" data) in a similar way than LUKS would. That's maybe harder to implement.

The payload location argument (hdW,X)Y+Z could even be omitted and defaults used in this case (i.e. (hd0)1+1).

There's another issue to solve: /boot stores initramfs images, a bad thing for deniability I guess. Chainloading a second GRUB is probably the solution for that.

johnlane commented 8 years ago

I've just merged that commit. I thought I had but I haven't looked at this for some time. I'll try to find some time to update this repo with upstream. I would have preferred them to adopt my patches however.

kriswebdev commented 8 years ago

I've voted for your pull requests at savannah.gnu.org bug tracker but I doubt it has any impact, there's no "sort by vote".

I'm actively working on a Deniable LUKS header, I'll keep you posted.

By the way, you should add insmod luks in your screenshot.

johnlane commented 8 years ago

Hi, I've just updated my repo to the latest savannah master. Like you mentioned, there was one line in cryptodisk.c that needed to be modified following an upstream commit c93d3e69 on 2015-09-13. I've also updated the patches on the website so they are compatible with the current master head (abf9beb7).

I've just looked at your fork and I think it's an interesting idea. I have a couple of comments having taken a few minutes to look at this...

If I understand you correctly, you're offsetting into the disk to pull out some 'payload' data that you're going to use to generate a LUKS header on the fly and use that to unlock the disk with the supplied passphrase. Do I have that right? Is the payload data on the disk encrypted somehow? The LUKS header format is very specific and would be easy to detect.

Oh and one other thing I noticed...

The best place to store it on disk is probably somewhere between the bootloader itself and the first partition.

Watch out for GPT formatted disks because the "no-man's land" space between the boot loader and the first partition does not exist. FYI, I am using GPT/MBR hybrid on my USB stick without issue.

Thanks for up-voting my patches. Have you discussed any of this on the grub-devel mailing list? Some more exposure there following my last postings may help get these efforts recognised :)

The reason the screenshot doesn't show insmod luks is because it isn't necessary to display the help text. It is needed for the LUKS usage however, as I show in the examples. Perhaps sometime I'll provide more screenshots...

kriswebdev commented 8 years ago

The LUKS header format is very specific and would be easy to detect.

Indeed, this "header" would contain only random-looking data (salts, digest & encrypted header). That's very similar to Truecrypt header, but with LUKS advantages (8 keys support and anti-forensic information splitter) and support in GRUB cryptomount.

Watch out for GPT formatted disks because the "no-man's land" space between the boot loader and the first partition does not exist.

You're right, I came to the same conclusion so the header will be at the start of the disk (for full disk encryption) or at the 1MiB-aligned start of the unallocated space "partition". Hoping nothing will erase it there... (GRUB core.img for GPT disks maybe?).

Have you discussed any of this on the grub-devel mailing list?

Not yet, I'll do that.

johnlane commented 8 years ago

The LUKS header begins with the identifiable string LUKS followed immediately by hex 0xBABE. I wrote some things a while back that may be of interest to you:

desmond-decker commented 8 years ago

I can confirm a pure linux-based "truecrypt-style" hidden OS with deniable encryption is possible with grub crypt, booting from a plain-mode encrypted volume (with an offset) inside the empty space at the end of a LUKS volume containing other files.

Including this in the upstream could transform the crypto/privacy/security landscape...

kriswebdev commented 8 years ago

@desmond-decker Plain-mode encrypted volumes are risky without a very strong password. It removes LUKS advantages:

I've been working on cryptsetup-deluks to specify and implement a deniable header structure, with LUKS benefits (ability to increase hashing iterations, salt, keyslots). It works fine with full disk encryption. I still need to work a bit more on grub-crypto-deluks to add GRUB support, it's almost done (not synced yet). But I'm not sure there's strong community interrest in deniable encryption, and as johnlane pointed out, GRUB developers aren't very reactive in accepting pull requests. Not speaking about the ethical questions around this level of encryption.

Finally, there are some challenges not addressed by deniable encryption:

johnlane commented 8 years ago

Surely a detached LUKS header gives you the benefits of LUKS with the deniability of plain dm-crypt?

I am not I understand sure what's needed beyond that?

I agree that just using plain mode is weaker due to the algorithms employed by LUKS for passphase processing. These include a PBKDF2 and AFsplitter which bloats the amount of data that the passphrase is embedded in.

The limit of my usage is detached LUKS and was the reason I started this fork. The plain mode support was esentially a freebie that was possible due to how LUKS works (it uses dm-crypt) and I did it to round up my understanding of how it works.

desmond-decker commented 8 years ago

If you have a plain-mode container inside of the "empty" space at the end of a LUKS container that has been properly initialized with /dev/urandom data, the empty space looks like random data and your plain-mode container hidden within it also looks like random data. The password strength issue is mitigated by the fact that the exact offset is needed to open the container, as well as the password. Without the offset you are looking for a needle in a stack of needles, or a block of random data in a block of random data.

kriswebdev commented 8 years ago

You're right, holding the key in a plain-mode container is quite secure when using a randomly-chosen offset. It's like increasing the password strength with a big number, instead of relying on PBKDF2 to hash it several times. To be as strong as 20.000 PBKDF2 iterations, you need to put it at an offset chosen randomly among at least 10MB (20.000 * 512 bytes block size) of random data.

Regarding rainbow-table attacks, I'm not sure if the plain-mode encrypted offset is well protected against it or not. xts-plain64 is adding some kind of weak salt based on aes-encrypted single-hashed password and disk offset, but given that this space contains only random data (the key), it would not be attackable. You just have to ensure that the plain-mode space containing the key has no block filled with 0 before encryption (adjust the size of the encrypted space to the minimum number of blocks required to store the key length, or fill it with random data).

It think this issue can be closed now.

I'll still work on grub-crypto-deluks to avoid remembering the offset.