Gentoo Forums
Gentoo Forums
Gentoo Forums
Quick Search: in
dm-crypt largest practical keyfile?
View unanswered posts
View posts from last 24 hours

 
Reply to topic    Gentoo Forums Forum Index Networking & Security
View previous topic :: View next topic  
Author Message
Zazzman
n00b
n00b


Joined: 09 May 2012
Posts: 32

PostPosted: Mon Jan 08, 2018 12:24 am    Post subject: dm-crypt largest practical keyfile? Reply with quote

Looking to update hard drive physical security, and my search engine skills are failing me. What is the largest possible key-size for use in cryptsetup? Is it different between LUKS and plain dm-crypt?
Back to top
View user's profile Send private message
frostschutz
Advocate
Advocate


Joined: 22 Feb 2005
Posts: 2971
Location: Germany

PostPosted: Mon Jan 08, 2018 1:02 am    Post subject: Reply with quote

cryptsetup itself will tell you the limits.

Code:

# cryptsetup --help
cryptsetup 2.0.0
Usage: cryptsetup [OPTION...] <action> <action-specific>
[...]
Default compiled-in key and passphrase parameters:
   Maximum keyfile size: 8192kB, Maximum interactive passphrase length 512 (characters)
Default PBKDF2 iteration time for LUKS: 2000 (ms)
Default PBKDF for LUKS2: argon2i
   Iteration time: 2000, Memory required: 1048576kB, Parallel threads: 4


So as a keyfile it supports up to 8MiB, or when typing it comes down to 512 bytes.

With LUKS PBKDF2 key derivation, one thing to take note of is that whichever algorithm you use, the supplied key will be reduced to the hash size.

So if you use an 8MiB key, it is possible to produce a significantly shorter key that also works.

Setting up a random LUKS container (100M) and key (4M):

Code:

# truncate -s 100M luks.container
# truncate -s 4M luks.key
# shred -v -n 1 luks.*
shred: luks.container: pass 1/1 (random)...
shred: luks.key: pass 1/1 (random)...
# cryptsetup luksFormat luks.container luks.key

WARNING!
========
This will overwrite data on luks.container irrevocably.

Are you sure? (Type uppercase yes): YES


Testing the key:

Code:

# cryptsetup luksOpen luks.container lukstest --key-file luks.key --test-passphrase && echo OK || echo FAIL
OK


Reducing the key:

Code:

# rhash --printf '%@{sha-256}' luks.key > luks.sha256
# ls -l luks.*
-rw-r--r-- 1 root root 104857600 Jan  8 01:36 luks.container
-rw-r--r-- 1 root root   4194304 Jan  8 01:35 luks.key
-rw-r--r-- 1 root root        32 Jan  8 01:41 luks.sha256
# cryptsetup luksOpen luks.container lukstest --key-file luks.sha256 --test-passphrase && echo OK || echo FAIL
OK


So while our key is 4MiB in size, the 32 byte key (raw binary sha256 hash of the 4MiB file) is also accepted due to an internal oddity of the PBKDF2 algorithm used by LUKS.

Using huge keyfiles is mostly pointless. Basically the only advantage of large keyfiles is to defeat data remanence - recovering 32 bytes is a lot more likely, than recovering megabytes of data. This is also why LUKS uses 128KiB as key material per keyslot. LUKS doesn't want data in say, a hard drive's reallocated sectors you can no longer reliably delete, to be useful to recover LUKS headers.

Using binary data keyfiles also has downsides. It's possible to use them the wrong way... when piping such keys instead of using the file directly, cryptsetup might stop reading at newline character. So the key you are actually using is a lot shorter (or even empty) than you believe it to be.

For this reason alone I prefer keys that are human-readable, without newlines, as it leaves no room for interpretation.

Code:

$ printf "%s" $(pwgen -s 32 1) > keyfile # no newline at end of file!
$ stat keyfile
  File: keyfile
  Size: 32           Blocks: 8          IO Block: 4096   regular file
$ cat keyfile
eMKhrRWQNJ7WW7cFKPrtBb0vD6wTuihA


That way you have a key that works as a keyfile, works when reading from stdin, and works when typing it on a keyboard. There is no difference between keyfile and passphrase and no room for different interperations.

As for increasing security, if you are concerned about brute-force, it is likely more important to check the iteration counts, and increase that if necessary with the --iter-time option.

By default cryptsetup will invest 1-2 seconds of CPU power into LUKS master key and each individual keyslot, however if you happened to create the LUKS container during a load spike, iteration counts might turn out order of magnitude lower than normal, so it's important to check or LUKS will not be as good against bruteforce attacks as expected.
Back to top
View user's profile Send private message
Zazzman
n00b
n00b


Joined: 09 May 2012
Posts: 32

PostPosted: Mon Jan 08, 2018 5:45 am    Post subject: Reply with quote

frostschutz wrote:
cryptsetup itself will tell you the limits.
[. . .]
Code:

Default compiled-in key and passphrase parameters:
   Maximum keyfile size: 8192kB, Maximum interactive passphrase length 512 (characters)
Default PBKDF2 iteration time for LUKS: 2000 (ms)
Default PBKDF for LUKS2: argon2i
   Iteration time: 2000, Memory required: 1048576kB, Parallel threads: 4

So as a keyfile it supports up to 8MiB, or when typing it comes down to 512 bytes.

Well... that was simpler than I imagined. Only 8MiB? Larger than that seems only useful for using the key-offset flag, for obscurity even if the key is compromised... and/or having multiple keys in one file with different offsets.
frostschutz wrote:

With LUKS PBKDF2 key derivation, one thing to take note of is that whichever algorithm you use, the supplied key will be reduced to the hash size.
[. . .]

So while our key is 4MiB in size, the 32 byte key (raw binary sha256 hash of the 4MiB file) is also accepted due to an internal oddity of the PBKDF2 algorithm used by LUKS.
Does dm-crypt operate on a similar principle to PBKDF2? If so, then yeah, key files are almost entirely useless.

frostschutz wrote:

Using huge keyfiles is mostly pointless. Basically the only advantage of large keyfiles is to defeat data remanence - recovering 32 bytes is a lot more likely, than recovering megabytes of data. This is also why LUKS uses 128KiB as key material per keyslot. LUKS doesn't want data in say, a hard drive's reallocated sectors you can no longer reliably delete, to be useful to recover LUKS headers.

Using binary data keyfiles also has downsides. It's possible to use them the wrong way... when piping such keys instead of using the file directly, cryptsetup might stop reading at newline character. So the key you are actually using is a lot shorter (or even empty) than you believe it to be.

For this reason alone I prefer keys that are human-readable, without newlines, as it leaves no room for interpretation.
[. . .]
well, there's always
[code]vim $keyfile
:%s///gc/code]
To remove line breaks. But thanks for bringing it up, I had no idea! I'd have been hosed after about ~60 characters in.
frostschutz wrote:

As for increasing security, if you are concerned about brute-force, it is likely more important to check the iteration counts, and increase that if necessary with the --iter-time option.

By default cryptsetup will invest 1-2 seconds of CPU power into LUKS master key and each individual keyslot, however if you happened to create the LUKS container during a load spike, iteration counts might turn out order of magnitude lower than normal, so it's important to check or LUKS will not be as good against bruteforce attacks as expected.

Now, cryptsetup uses the ciphers compiled into the kernel? The --iter-time option *is* choosing where I am on a trade off between security and accessibility.
Back to top
View user's profile Send private message
salahx
Guru
Guru


Joined: 12 Mar 2005
Posts: 437

PostPosted: Tue Jan 09, 2018 4:27 am    Post subject: Reply with quote

There's a difference between the passphrase key and the key ultimately passed to dm-crypt. When you create a LUKS container, a random key (or, for XTS mode, 2 random keys) are created. For each passphrase, another key is generated using PBDKF2 and THAT key is used to encrypt the random key.

The random key is then passed to dm-crypt to do the actual encrpytion/decrpytion.

So in my case:
Code:

cryptsetup luksOpen luks.container lukstest --key-file luks.sha256
dmsetup table lukstest --showkeys
lukstest: 0 200704 crypt aes-xts-plain64 9251bd2e7be7a06e74527f84ea2271fe84b1f442b5b9fdea5014d453a7e86531 0 7:0 4096


The 9251... is the actual random key (of course, yours will be different),. Note: cryptsetup 2.0.0 stash the key in the kernel keyring, hiding it from view from --show-keys - which is probably for the best, because with this information i can now bypass LUKS entirely :

Code:

# MYLOOP=`losetup -f --show luks.container`
# dmsetup create lukstest --table '0 200704 crypt aes-xts-plain64 9251bd2e7be7a06e74527f84ea2271fe84b1f442b5b9fdea5014d453a7e86531 0 '"$MYLOOP"' 4096'
[do whatever to /dev/mapper/lukstest]
# dmsetup remove lukstest
# losetup -d $MYLOOP


If you're intested in controlling the device mapper directly, see https://wiki.gentoo.org/wiki/Device-mapper
Back to top
View user's profile Send private message
Display posts from previous:   
Reply to topic    Gentoo Forums Forum Index Networking & Security All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum