Bug 1051733 - gcrypt KDF implementation is very slow
Summary: gcrypt KDF implementation is very slow
Keywords:
Status: CLOSED CURRENTRELEASE
Alias: None
Product: Fedora
Classification: Fedora
Component: libgcrypt
Version: 19
Hardware: x86_64
OS: Linux
unspecified
high
Target Milestone: ---
Assignee: Tomas Mraz
QA Contact: Fedora Extras Quality Assurance
URL:
Whiteboard:
Depends On:
Blocks:
TreeView+ depends on / blocked
 
Reported: 2014-01-11 05:15 UTC by kookyman
Modified: 2015-01-12 09:24 UTC (History)
6 users (show)

Fixed In Version:
Doc Type: Bug Fix
Doc Text:
Clone Of:
: 1052152 (view as bug list)
Environment:
Last Closed: 2015-01-12 09:24:04 UTC
Type: Bug
Embargoed:


Attachments (Terms of Use)
Bash script for automated reproduction (1.06 KB, text/plain)
2014-01-11 21:15 UTC, kookyman
no flags Details
Proposed patch (921 bytes, patch)
2014-01-11 22:19 UTC, Milan Broz
no flags Details | Diff
Proposed patch (945 bytes, patch)
2014-01-11 22:26 UTC, Milan Broz
no flags Details | Diff
Proposed patch (975 bytes, patch)
2014-01-11 22:34 UTC, Milan Broz
no flags Details | Diff

Description kookyman 2014-01-11 05:15:20 UTC
Description of problem:
Opening LUKS Encrypted container with a keyfile takes excessive amounts of time (have seen between 5 and 25 minutes) to process.  Utilizes 100% of one core (of four core system).  Does not have the same effect with password, even on same container.

Version-Release number of selected component (if applicable):
1.6.3

How reproducible:
100% on Fedora 19 Installed, Live CD (KDE), 20 Live CD (Desktop and KDE spin)


Steps to Reproduce:
--Reproduction Notes:
-Multiple ways to reproduce known, listing easiest
-'-v' and  '--debug' can be omitted without affecting, included her to help show points of trouble.

As root or sudo:

With Password (Behaves Normally)
1.  'dd if=/dev/urandom of=keyfile bs=32K count=1'
2.  'dd if=/dev/zero of=container bs=4M count=16'
3.  'cryptsetup -v --debug --force-password luksCreate container'
4.  Enter 'YES'.
5.  Enter 'password'

6.  'cryptsetup -v --debug luksOpen container Demo'
7.  Enter 'password'

With Keyfile (Improper behavior)
1.  'dd if=/dev/urandom of=keyfile bs=32K count=1'
2.  'dd if=/dev/zero of=container bs=4M count=16'
3.  'cryptsetup -v --debug luksCreate container --key-file=keyfile'
4.  Enter 'YES'.

6.  'cryptsetup -v --debug luksOpen container Demo -d keyfile'

Cleanup
1.  rm keyfile
2.  rm container

Actual results:
Takes excessive time to create and open the container using a keyfile.

Expected results:
The keyfile should take approximately the same amount of time as the password.

Additional info:
Keyfile size does have some bearing on the amount of 'delay' introduced.  However I have containers that use keyfiles in excess of 1MB, but with Fedora 16, 17, and 18, the cryptsetup only takes seconds to open the container, Fedora 19/20 take 10-25 minutes.

Adding a keyfile to a container with a password (or vice versa) shows same effect when trying to open the container, regardless of which key was in place first.  Have not reproduced the steps of actually adding the second key, I had containers with both keys available however and have opened using both seeing similar results as above.

Debug information from cryptsetup shows the "hang" occurs between these two debug statements:

# Trying to open key slot 0 [ACTIVE].
# Reading key slot 0 area.

Additionally the only way to stop the process is to 'kill -9 <pid>'.  Ctrl-C has no effect.

Fedora 18 does not exhibit the behavior, even with cryptsetup 1.6.3 installed.  Fedora 19 does exhibit the behavior with a old kernel from Fedora 17 running.  Leads me to believe the cause may not be directly cryptsetup package related.

Comment 1 Milan Broz 2014-01-11 09:30:34 UTC
(In reply to kookyman from comment #0)
> With Password (Behaves Normally)
> 1.  'dd if=/dev/urandom of=keyfile bs=32K count=1'
> 2.  'dd if=/dev/zero of=container bs=4M count=16'
> 3.  'cryptsetup -v --debug --force-password luksCreate container'
> 4.  Enter 'YES'.
> 5.  Enter 'password'

How can you enter password generated from urandom here?

It will trim the password on the first occurence of EOL (\n) char...

Moreover, if you run cryptsetup --help, you will see that hard limit is 512 chars for password inserted trhough terminal while hard keyfile limit is 8192kB.

So the test doesn't make sense to me.

And if you are using 32K keyfile of course it will take long time...
And it if is random string even if you use 4096bit key (512 bytes) it is more than enough. (I guess you will not have enough computing power to brute force it even if you borrow some parallel universe ;-)

> With Keyfile (Improper behavior)
> 1.  'dd if=/dev/urandom of=keyfile bs=32K count=1'
> 2.  'dd if=/dev/zero of=container bs=4M count=16'
> 3.  'cryptsetup -v --debug luksCreate container --key-file=keyfile'

Try to add --keyfile-size=512 (so you are measuring the same limit as interactive query).

> Fedora 18 does not exhibit the behavior, even with cryptsetup 1.6.3
> installed.  Fedora 19 does exhibit the behavior with a old kernel from
> Fedora 17 running.  Leads me to believe the cause may not be directly
> cryptsetup package related.

Really? Kernel is not used here at all (except one read from keyslot)... Are you sure you are using the same keyfile? Note that EOL problem.

Comment 2 Milan Broz 2014-01-11 10:10:52 UTC
I forgot to add one comment:

passwords and keyfiles are processed the same in LUKS - both are input of PBKDF2 (password based derivation function) and output is used to unlock keyslot (plus there is anti-forensic filter).

There is a benchmark of PBKDF2 performance, which should calibrate iteration time to unlock keyslot (parameter --iter-time). Unfortunately, this benchmark uses fixed (and short) password for calibration but iteration time depends also on length of password (and some internals of used hash algorithm). So for longer passwords or keyfiles it takes longer time tnah benchmarked. With your 32K keyfile it is waaaaay longer...

There is no easy solution - once we will calibrate loop for user password length, it will open room some side channels.

So the current workaround is that --iter-time parameter is not in miliseconds for longer passphrases but still can be used to decrease iteration time to requested time. I have open upstream issue for this problem http://code.google.com/p/cryptsetup/issues/detail?id=185
(I will probably add some explenation to next release note.)

Anyway, if you use real random and long keyfile (so you do not need slow-down bruteforce search), you can use minimal iterations (use --iter-time 1 or -i 1). 

But still I would like how is possible that you get different times on F19 vs F18 :)

Comment 3 kookyman 2014-01-11 21:15:34 UTC
Created attachment 848766 [details]
Bash script for automated reproduction

Basic script to automate correct reproduction steps.

Comment 4 kookyman 2014-01-11 21:16:46 UTC
Apparently I was a little too sleepy when I wrote the reproduction steps, as I have noted not only the mistake you mentioned, but an additional mistake that makes the reproduction not workable. I've included a correction below, as well as writing a short script to automate the creation, open, and close of a test case. (Removal of the directory and two files are left to the reproducer.) [Script appended to bug in previous comment.]

With regards to the password /dev/urandom, my mistake.  Originally I had the reproduction ordered differently, and it was not necessary perform step #1 on the password entry version.  The corrected reproduction method is below.

Additionally, I failed to mention why I used the '--force-password' parameter on the step-by-step using a Password instead of a key file. It is to allow testing with any password (used 'password' above), without failing due to insufficient complexity / dictionary words.

## Corrected Reproduction Procedure
Steps to Reproduce:
--Reproduction Notes:
-Multiple ways to reproduce known, listing easiest
-'-v' and  '--debug' can be omitted without affecting, included here to help show points of trouble.

As root or via sudo:

With Password (Behaves Normally and as expected)
1.  'dd if=/dev/zero of=container bs=4M count=16'
2.  'cryptsetup -v --debug --force-password luksFormat container'
3.  Enter 'YES'.
4.  Enter 'password'

5.  'cryptsetup -v --debug luksOpen container Demo'
6.  Enter 'password'

With Keyfile (Improper behavior)
1.  'dd if=/dev/urandom of=keyfile bs=32K count=1'
2.  'dd if=/dev/zero of=container bs=4M count=16'
3.  'cryptsetup -v --debug luksFormat container --key-file=keyfile'
4.  Enter 'YES'.

6.  'cryptsetup -v --debug luksOpen container Demo -d keyfile'

Cleanup
1.  cryptsetup luksClose Demo
2.  rm keyfile
3.  rm container
## End Corrected Reproduction

With regards to a 32K keyfile taking a long time, there in lies the issue.  On Fedora 18 it does not take a long time. (Nor on 16 and 17 which are notably EOL.)  The reason I filed this as a bug against 19 is this is not behavior as expected from the past years of experience.  In fact, I have keyfiles that are considerably larger than 32K (Over 1024MB to be specific) and when using Fedora 18 or lower, the container is opened near instantly.  When using Fedora 19 or higher, it now takes 25 minutes or more to process the keyfile.  This may be the intended design, but if this is, then a bug still exists in Fedora 18

Additionally, by specifying the --key-size=512 flag, on existing keyfiles this results in truncating the and the keyfile will no longer work.  Creation of new containers can simply use with small keyfiles, but for existing containers with large keyfiles it will require new keyfiles to be made and/or used.

Utilizing my reproduction script, I tested Fedora 17-20, and here were the results:

Fedora 17 Live CD (KDE)
  Cryptsetup 1.4.2
  Creation Time 5.43 seconds
  Open Time: 1.25 seconds

Fedora 18 Live CD (KDE)
  Cryptsetup 1.5.1 - 
  Creation Time 5.226 seconds
  Open Time 1.208 seconds

--Updated to 1.6.3 -
  Creation Time: 5.013 seconds
  Open Time 1.278 seconds

Fedora 18 Installed (Minimum Install, not updated)
  Creation Time: 4.374 seconds
  Open Time: 1.608 seconds

--Updated (yum update)
  Creation Time: 8.346 seconds
  Open Time: 1.618 seconds

Fedora 19 Live CD (KDE)
  Creation Time 47.285s
  Open Time 43.439

Fedora 19 (Installed)
  Creation time 45.117 seconds
  Open Time 41.525 Seconds

Fedora 20 Live CD (KDE)
  Creation Time: 48.95seconds
  Open Time: 43.892s

Comment 5 Milan Broz 2014-01-11 21:32:51 UTC
Ok, the run times are definitely strange. I guiess the problem will be somewhere else (and this is just trigger) but let's see...

Strace would be useful but I will need to reproduce it myself anyway.

Thanks for the script.

Comment 6 Milan Broz 2014-01-11 21:50:45 UTC
Ok, found the problem...

On F19+ cryptsetup doesn't use internal PBKDF2 but uses gcrypt provided one (on earlier versions it is not available).

So this seems like a problem in gcrypt PBKDF2.

I will talk to gcrypt maintainer once I will have more info.

Thanks for report!

Comment 7 Milan Broz 2014-01-11 22:17:45 UTC
Since F19 cryptsetup uses internal gcrypt PBKDF2 implementation.

Unfortunately this code is extremely slow in comparison to internal cryptsetup implementation used before.

Reassigning to gcrypt (I will attach patch to solve this problem later).

Comment 8 Milan Broz 2014-01-11 22:19:33 UTC
Created attachment 848770 [details]
Proposed patch

gcrypt set key in every KDF iteration, this is not needed and slows everything down... Attached patch should fix it.

Comment 9 Milan Broz 2014-01-11 22:26:34 UTC
Created attachment 848771 [details]
Proposed patch

Comment 10 Milan Broz 2014-01-11 22:34:27 UTC
Created attachment 848772 [details]
Proposed patch

Forgot to call gcry_reset..

Comment 11 Milan Broz 2014-01-13 20:39:30 UTC
I sent fix to gcrypt upstream
http://lists.gnupg.org/pipermail/gcrypt-devel/2014-January/002865.html

(cryptsetup itself used this trick for years)

Comment 12 Milan Broz 2014-01-14 17:25:10 UTC
Patch accepted upstream, it would be nice to apply this as F19/20 libgcrypt update as well, thx.

Comment 13 kookyman 2014-02-27 15:29:55 UTC
libgcrypt has been updated upstream to v1.6.1.. RFE for version bump.

Comment 14 Fedora End Of Life 2015-01-09 21:06:05 UTC
This message is a notice that Fedora 19 is now at end of life. Fedora 
has stopped maintaining and issuing updates for Fedora 19. It is 
Fedora's policy to close all bug reports from releases that are no 
longer maintained. Approximately 4 (four) weeks from now this bug will
be closed as EOL if it remains open with a Fedora 'version' of '19'.

Package Maintainer: If you wish for this bug to remain open because you
plan to fix it in a currently maintained version, simply change the 'version' 
to a later Fedora version.

Thank you for reporting this issue and we are sorry that we were not 
able to fix it before Fedora 19 is end of life. If you would still like 
to see this bug fixed and are able to reproduce it against a later version 
of Fedora, you are encouraged  change the 'version' to a later Fedora 
version prior this bug is closed as described in the policy above.

Although we aim to fix as many bugs as possible during every release's 
lifetime, sometimes those efforts are overtaken by events. Often a 
more recent Fedora release includes newer upstream software that fixes 
bugs or makes them obsolete.


Note You need to log in before you can comment on or make changes to this bug.