cornelinux / yubikey-luks

Two factor authentication for harddisk encryption
614 stars 58 forks source link

change the challenge #1

Open cornelinux opened 10 years ago

cornelinux commented 10 years ago

Should be able to change the challenge, so that we get some kind of one time password effect. At the moment the process results in one static password to unlock one key slot.

ghost commented 10 years ago

or maybe what if scheme was like this:

final_password_for_slot_2 = yubikey_get_response(user_entered_pin + local_data)

local_data would be locally stored random byte array. since local_data should be appended to password by script there would be less risk of user exposing real key by just typing in pin for challenge. but my real intent behind is this: should user enter wrong pin local_data could be wiped forcing user to enter full long password that we normally use. so even if someone snags yubikey and makes even single attempt at unlocking - further attempts for possibly guessing/bruteforcing (for example 4 digit) pin would be blocked. What do you think?

cornelinux commented 10 years ago

At the moment it is done in key-script line 41. In your notation:

final_password_for_slot_2 = yubikey_get_response(user_entered_pin)

As the "user entered pin" could be anything (i assume a 12 character password ;-) this does not add a moving factor. The thing is, that always the same response will open the slot.

You are right, that wiping the local_data would mitigate a brute force attack (if the attacker does not change the key-script, which would wipe the local_data.

So the local_data would add a brute force protection, not a replay protection. Nevertheless, it could be done...

ghost commented 10 years ago

well... to make replay attack successful attacker would need to do few things:

  1. Get person to insert pre-boot yubikey. This is easy.
  2. Get person to enter pre-boot PIN. That would be not smart thing to do at any time except on boot. So this would be hard (given person is smart ofc).
  3. Use entered PIN in together with local_data bit. This is even harder because it would require access to local machine. If attacker gains remote access we are fked anyway.

So while replay attack would be within realm of possibility it would be significantly harder to carry out. Now im not sure where local_data could be stored. think remounting /boot as rw and using that is a good idea?

privacyidea commented 10 years ago

There is a totally easy way to do a replay attack. Modify the initrd, sniff the response from the yubikey. This is (no matter is local_data used or not) the passphrase for the LUKS-slot. THis way I could boot the notebook/open the LUKS without the yubikey and without the users password... :-/

ghost commented 10 years ago

but that requires local extended access. with that no matter what is done there is no way to protect against it. even if some 100 character password was used it always can be sniffed that way.

cornelinux commented 10 years ago

...if we only could use a smartcard ;-)

So again, you would use local_data to avoid black box brute force. If you wipe the local_data, you need to write.

There is one problem, that I also experienced with my investigation on the OTP thing: I do not know a way WHERE to WRITE to. At the LUKS-Passphrase entering stage the user is on the initrd, which can not be written to. So where to store the local_data, so that it can be overwritten.

Is remounting /boot possible at all? is the /boot partition a kernel command line parameter? Otherwise we need to store the information, where the /boot partition is, in the initrd.

Hm, this write-location could also be used for the OTP challenge...

ghost commented 10 years ago

Actually yubikey neo has some smart-cardish capabilities, namely RSA public/private key support. However for a perfect solution i personally would wish dongle to work only for one try pin attempt. Like try once and it automatically gets wiped after delivering whatever key output, however if key is correct dongle could be re-setup for next use. As for writing - i read yubikey FDE impl manual. It mentions counter to be used with hmac challenge/response scheme. Obviously that counter must be stored somewhere. Yubikey configuration tool also can set that counter on yubikey so thats one possible storage location that could be exploited. Just need to find out which tools can do it and how to properly use it. Im probably stressing this matter too much but i really want it to make bulletproof against bruteforcing if adversary manages to get yubikey and access to system. Maybe im bit too idealistic ^_^

cornelinux commented 10 years ago

I once implemented the authentication for etoken pro with LUKS. Unfortunately LUKS has only a very limited capability of authentication (in fact the slot's passphrase). So even in this case, I was only able to store secret data on the smartcard, read this from the smartcard and push it as passphrase to the slot.

As long as you are not modifying the C source of LUKS, I am bound to this limitation.

Even if you would use RSA. What could you do? At the end you need an unencrypted, symmetric passphrase to push to the slot. You could encrypt the slot's passphrase with the public key. This way you could also assign more than 8 users by encrypting one passphrase with 100 pubkeys, but each user would be capable of decrypting the passphrase manually...

kylemanna commented 10 years ago

I have a few ideas about this that I'll try to implement in the coming week(s) when I get time. Essentially, the trick is to leverage the LUKS salts stored in the LUKS headers as the challenge.

Requirements

  1. Challenge changes on every mount to guard against replay attacks
  2. The new challenge is committed to the LUKs header before the last is removed to prevent a power failure/software bug from rendering the header incomplete (fixes the problem where the key is removed, fpower is lost before the new challenge is saved).

Implementation

Key slots are examples are given for simplicity.

First time configuration

  1. Generate a key in the highest open slot (i.e. 7) which will generate a salt. Make the data submitted to LUKs reasonably strong so that it doesn't compromise the integrity of the real key. (Long term this can be optimized out to maybe write directly to the salt location in the header and skip generating any key that would conceivably work).
  2. Use the salt from the highest numbered slot (i.e. 7) as the challenge to the YubiKey. Take the response from the YubiKey and add a new lowest numbered key slot (i.e. 1, assume slot 0 is a failsafe setup by the user).

Boot

  1. Read the salt from the highest numbered keyslot
  2. Challenge the YubiKey and get a response (keep in mind that YubiKey could be in blocking mode which would require a touch, to consider later)
  3. The response is submitted to cryptsetup open and should unlock the device
  4. Generate a new salt/challenge in in the next highest LUKs key slot (i.e. 6)
  5. Challenge the YubiKey and store the response in the next lowest key slot (i.e. 2)
  6. Delete the old challenge and response in previous slots (i.e. 1, 7)

This should work to accomplish my two requirements. Thoughts?

cornelinux commented 10 years ago

Let me wrap things up.

  1. You need 4 additional slots for the one user, 2 holding the challenge/salt, and 2 holding the Yubikey-Response.
  2. If you have powerfail during step 6, you might have deleted only slot 1, not slot 7. So you need some logic on the next boot to determine the active slot pair -- either 1/7 or 2/6 and then clean up the rest.
  3. Getting the salt from the slot is a bit nasty, to my knowledge you will only get it from luksDump, where you need to do some fancy grep-things.

    cryptsetup luksDump /dev/sda3 | grep "Key Slot 7" -A 7 | grep "Salt:" -A1 | cut -f 3 | sed -e s/" "/""/g

    (is grep, cut, sed available in initrd. Even awk? Many pipes to break ;-)

My recommendation would be to add a user password to the challenge/slot, concatenate the password with the salt, before sending it to the yubikey.

But in theory this looks like a possible solution!

cornelinux commented 10 years ago

I am wondering if a feature request to https://code.google.com/p/cryptsetup/, to dump the salt of a defined slot would make more sense...

kylemanna commented 10 years ago

Getting the salt from the slot is a bit nasty, to my knowledge you will only get it from luksDump, where you need to do some fancy grep-things.

I am wondering if a feature request to https://code.google.com/p/cryptsetup/, to dump the salt of a defined slot would make more sense...

I bet upstream might frown on this as hacky. If possible, a luksGetSalt and luksSetSalt would be ideal.

Not sure what's in the initrd (busybox + shell headache?), but a statically compiled C app could reference libcryptsetup and get the data directly might be the easiest and most robust path forward.

My recommendation would be to add a user password to the challenge/slot, concatenate the password with the salt, before sending it to the yubikey.

I think doing anything to get the challenge up to 64 bytes per the YubiKey's max input is the goal. The per-key salt is only 32 bytes. I think that the master key (MK salt, also 32 bytes) concatenated with the key slot salt would be better then a user password? It would also be exactly 64 bytes. :)

The other thing I'd like to do if possible is to make sure that "salt" key slots couldn't unlock the actual master key on accident, that is to say setting only the salt value in the slot would be preferred.

cornelinux commented 10 years ago

Confirmed, a small static binary would be the best way to go. I know my limits and only very seldom try to write c.

I'd like to concatenate the userpassword, since this adds a second factor. Otherwise you would only authenticate with one factor - the yubikey.

We could do a sha256 of the password to get 32bytes. Of course the password should be long enough and good enough --- as always.

Storing only the salt in the slot is a good idea.

In the cryptsetup issues (https://code.google.com/p/cryptsetup/issues/list) I had the impression, that they are thinking of being able to store additional information (challenge) in a newer version of LUKS.

So I think it is a good idea to define the requirements and put them to their project :-)

kylemanna commented 10 years ago

I'll take a swing at writing something up in C to test it.

cornelinux commented 10 years ago

Great! I am really curious!

lorenzleutgeb commented 9 years ago

What's the status on this? It's the only thing that keeps me from rolling it out.

Have you checked this and respectively flowolf/initramfs_ykfde?

kylemanna commented 9 years ago

What's the status on this? It's the only thing that keeps me from rolling it out.

Life and other projects happened and then forgot about it. Still would like to do it, but don't have time.

mpokorny commented 9 years ago

Hello. I've been playing with this code a bit, and decided to have a look at writing a small C module that can return the salt for a given LUKS device key slot in order to support further development as described in the discussion of this issue. After reviewing the libcryptsetup API, I believe that that functionality isn't supported by the API. Investigating the implementation of the "cryptsetup luksDump" command shows that it uses references to private data structures that aren't in the API. Unfortunately, it seems to me that extracting the salts from the output of luksDump seems like the only possibility at this time. Can anyone else confirm my analysis of the libcryptsetup API?

cornelinux commented 9 years ago

Hi, I can not confirm this. But this sounds really nasty and seems a possible source for many errors...

Tormen commented 7 years ago

Hi,

I admit, I did not read the whole thread, but only skimmed through it, because I also thought the same: The effect of passing the knowledge into the hardware results in a static password of sorts.

But isn't the solution to this problem quite simple ? (I probably missed something ;)):

  1. If you use a static challenge that can be publicly stored somewhere (e.g. configured in the initramfs). Then pass this to the yk to get the response, which can (usually) ONLY be obtained via passing the challenge to the key (possession factor).
  2. And then you /add/ to this response a password that the user has to enter every time (knowledge factor).
  3. And so the concatenation of 1. and 2. becomes your LUKS password :)

Then this becomes true two factor authentication, no ?

Tormen

cornelinux commented 7 years ago

First I thought No, then I think Yes. We need to take a look at the threats...

Current Implementation

  1. The attacker would shoulder surf to get my password.
  2. The attacker would wait for me going to the toilet. Grab the yubikey and generate with the password the LUKS passphrase. Return the yubikey - me not realizing it.
  3. Several days later the attacker could grab only my notebook and use the generated LUKS passphrase to unlock the disk.

Your suggestion

  1. The attacker would shoulder surf to get my password.
  2. The attacker would wait for me to go to the toilet and grab the yubikey. He can not generate the LUKS passphrase.

Rather:

  1. The attacker would shoulder surf my password.
  2. The attacker would grab my notebook to fetch the challenge in the initramfs. For this he would need and unlocked notebook or to reboot the notebook with an external media or remove the hard disk an mount it somewhere else. If my notebook was running, I would realize that s.o. rebooted my notebook. So the attacker needs to find the time, when my notebook is powered off, so that I will not realize, that the attacked took a look at my notebook.
  3. Now the attacker would need to fetch my yubikey and use the challenge from the initramfs with the yubikey to generate the 2nd part of the LUKS passphrase.
  4. Now the attacker needs to fetch my notebook a 2nd time and use the my password from (1) and the 2nd part LUKS passphrase from (3) to unlock the harddisk.

Thoughts

You are right. Due to the fact that the attacker needs to fetch the notebook two times it is more difficult for the attacker, since in step 2 he needs to fetch my notebook, without me realizing it. This might be a difficult part given, that most notebooks are usually suspended and not turned off. But as an attacker I would take the risk to reboot a suspended notebook. I could also try to discharge the battery, so that the owner of the notebook might wonder: my notebook turned off due to the battery running low...? Again it is more complicated for the attacker and thus it is a bit more secure.

But it is still no real 2FA. Since once the attacker has gone through the complicated process, he can always access the data with 1FA - the LUKS passphrase.

Imagine this: The attacker has time. He is running the attack and gets the LUKS passphrase without you realizing it. THen he knows, the data he is looking for is not stored on the notebook, yet. THe attacker could come back months later without 2FA and still use the same LUKS passphrase to access the data. And I think this is the bigger problem that is immanent to both solutions. It is due to the fact of the symmetric key/LUKS passphrase.

Protecting against such a late attack would only be possible by rotating the LUKS passphrase.

Tormen commented 7 years ago

Thanks a lot. I agree 100%.

As it is still better than nothing (as you pointed out too), I implemented it here: https://github.com/Tormen/yubikey-full-disk-encryption

Vincent43 commented 7 years ago

I think that you overestimate rotating password utility and the whole "One Time Password" concept with LUKS. Keep in mind that LUKS passphrase is used only for decrypting real key used for actual data encryption, which stays the same. That means attacker with physical access to your notebook can just copy your LuksHeader with it's current LUKS passphrase, seal it in safe for 10 years, then return, restore header and unlock your disk with the same LUKS passphrase from 10 years ago regardless if you rotated it 10000 times since then or not.

cornelinux commented 7 years ago

You are right about that. If an attacker has the hard disk or the header, he can run offline attacks.

But changing/rotating the challenge and rewriting the slot still protects you from an attacker, who has managed to fetch your passwort (which acts as the only challenge for the yubikey) and month later fetch your yubikey and create the LUKS passphrase. This can be done without access to the harddisk or header.

And rotating the slot/passphrase would protect you from such an attack.

Vincent43 commented 7 years ago

Well, if you setup 2FA and attacker get all of them your are owned no matter what.

I'm not sure if I understand you correctly but as you said password is enough to trigger yubikey challenge so it doesn't matter how you obfuscate the challenge-response process, password + yubikey still be enough to unlock disk.

To mitigate this you can rotate your password but how you will generate and memorize them? How you make sure that attacker sniffed your old password but not new one? Even NIST finally admitted that changing passwords regularly doesn't make practical sense.

Of course you can make it 3FA by adding additional secret but setting it through some custom binary which does some magic with luks keys and slots isn't best way to do it. At best it will make the whole scheme fragile and at worst it will decrease actual security.

Much better would be having a keyfile encrypted with gpg RSA cert stored in yubikey protected with PIN/password. If you are interested in such mechanism, you can look at https://github.com/xdbob/mkinitcpio-gpg-encrypt and https://github.com/xdbob/mkinitcpio-gnupg

TimFW commented 6 years ago

You could always detach luks header and store it on a USB flash drive. You could take that one step further and make that usb flash drive a Aegis with a 10 button digit keypad that is AES XTS encrypted and allows for limit tries as low as 2-20 attempts then secure erase. The Aegis from my research is the best and most secure of the secure flash drives. Its black box but they give more documentation than others. This would get you true 2 FA and possible 3. 2 for sure as you have to use the pin code which can be up to 16 characters. Thus really something you have and something know even in most every conceivable situations. For this to be defeated you would have to have a backdoor thru the aegis device ( this almost certainly means state involvement targeting you and the same could be said for all the hw making up the laptop) , obtain the device, shoulder surf the password and grab the yubikey. If its the state they are just going to bully (waterboard) you into giving it all to them.

Fact is there ALWAYS has to be some OPSEC involved. No system will prevent its own user from being stupid. Such as leaving your yublkey at your desk or anywhere other than in your pocket with you at all times or around your neck. The chances of someone getting all of these things would take a lazy user and an amazing social/ HW/SW hack.

For that matter you could also move the boot /mbr partition to the same USB drive. This would prevent any evilmaid attack as their would be no unencrytped space on the HD. You could also ensure no firmware or HW device changes by using the TPM to seal the PCRs hash and check on boot i.e antievilmaid.

It takes multiple defenses to protect against physical attacks. But a combo such as this on say a thinkpad laptop would go a long ways in this area of security. Do something to the backplate screws of the laptop to show tampering as another small step.

If it were me also and I used a laptop where IF I lefts it unattended in a none secure location a small hidden camera somewhere at my desk or hotel room etc to record anyones comings and goings that could be checked. Motion sensor even better. See someone on your laptop means there could be trouble. At least you have a warning.

Vincent43 commented 6 years ago

How rotating LUKS password helps you when you store header on AEGIS? What's the point of using yubikey at all then?

I think that your ideas described here are fine but I don't see how they're related to rotating yubikey challenge.

TimFW commented 6 years ago

A person mentioned that it was not true 2FA and another mentioned wanting 3FA. They also were after a goal to defeat the scenario depicted where a yubikey physical security was compromised and password was socially hacked. The issue with this setup is the yubikey in this config has to be kept secure which is fine but they presented it as a sec hole. You need the something to be protected by its own security either HW or software gpg key pin accessed ie smart card yubikey.

Fact is the more steps a opposition must make i.e more walls to tear down the greater the chance of discovery and or thwarting the action. In almost all solutions these days measures are stacked.

It can be made much harder to obtain 2 usb devices than one and if one of those has its own pin plus can show login attempts but is almost no extra effort to plug 2 usb dev in vs 1. Further you then add in the physical access to the computer needed as well as obtaining the password. They all are walls that must be gotten thru. You want to balance PITA factor for user with number of countermeasures. After this you no longer have to worry about freq password changes if you so chose as its still a huge jump in difficulty to circumvent. The Aegis key also allows for the setting of a self destruct password. Thus it even has a way to prevent forcing a person to give up password. Set up a false flag by writing down self-destruct password or putting on something only moderately hard to hack and you are not even directly responsible for the effect. There are so many paths to venture down the rabbit hole imagination in really the limit.

In general you want each wall to cover a weakness of another wall hence why I offered this.

Password can be seen > so we add yubikey C@R which protects is password is seen. Yubikey can be stolen and used if laptop can be accessed> Aegis with pin and self destruct protects even if taken yet it could be backdoored by manf or state > we have password and we have now come full circle.

Next you add someone switching out HW firmware on PC and we have TPM sealed hash comparison. Trust then comes down to intital HW and bios which in most cases we are forced to trust. At some point you are forced to trust its where you want and can afford for that line to be and its worth vs threat faced.

Security can not be piece meal it has to be thought of in the over all picture.

cornelinux commented 6 years ago

Hi @TimFW,

you are totally right. Of course it is the best solution to have your boot partition not on your notebook but on a physically encrypted device and add additional layers.

I am totally aware of the limitations of this approach here. And it will basically protect against the attack vector of a shoulder surfer stealing the passphrase. And there are a lot of attack vectors, against which this approach with the yubikey does not protect. (altering the boot partition, grabbing the password AND later the yubikey to finally optain the LUKS passphrase.)

But after all LUKS sill uses only passphrases!

And this project here is about using the yubikey (since it is a widely spread device) and using a setup, that does not derivate to much from a default installation (boot partition on the same harddisk). Why? To address a lot of people since the hurdle to do so is lower. And as the name of this project also indicates, it is about the using the yubikey.

Your approach is totally legit but it would be another project. And I would be thrilled to take a look at such a project. As this is open source, you are welcome to fork.

Security is a matter of being aware of the remaining risks and evaluate, if you are willing to take these.

Thanks a lot Cornelius