I am currently evaluating PasswordSafe+ YubiKey combination and I have a couple of basic questions:
According to the documentation the YubiKey "Re-encrypts password database with a new random challenge each time"
Let's say I have a Password Safe database opened using the Yubi Key - at this point the information is decrypted since I can read it on the screen. So when is the database re-encrypted? Is it when I close the database?
also, next time I open it again with my backup YubiKey how is it possible to decrypt it with a different key?
To open and update entries in the password Safe requires to have access to the internet?
I think the answer is NO since I have tested this although, I would have expected some kind of connectivity to validate the Yubi Key... or am I missing something?
Is an internet connection ever required under any circumstances?
According to the documentation the YubiKey "Re-encrypts password database with a new random challenge each time"
According to the documentation the YubiKey "Re-encrypts password database with a new random challenge each time"
Someone should probably ask Yubico to remove this claim from their website, as it is not accurate. In the current implementation, Password Safe simply asks the YubiKey to calculate the HMAC of the user's Password Safe password. So unless the password changes or Password Safe changes its implementation, the database is encrypted with the same key every time.
Yes, this is a bug that I hope to address soon.
I have a question about the security of Yubikey + Password Safe. I have been reading the on this forum and the yubico forum and I am trying to understand how the challenge response process works in Password Safe.
when Yubikey sends the hash-based message authentication code (HMAC) back to Password Safe, this code is always the same? Or is there some randomness in the process (such as a counter or
a random number?)
If it the HMAC is always the same, and Yubikey is basically a USB keyboard, isn't the HMAC vulnerable to keyloggers?
If you do have a keylogger on your PC and if the above is true, it is safe to assume that your master password has been compromised, too.
In other words, can an attacker access a locked database without having the physical object of Yubikey in his hand?
I am also interested in the answer to lusich's questions. If the same hash is used each time, it appears the implementation is vulnerable to a replay attack.
More broadly, it would be very helpful if the technical details of the Yubikey implementation were described in the help file for each release of PasswordSafe. From my reading of this forum and the yubico site, it appears that the implementation changes frequently, and is poorly documented. The details for each release should be described in a single, easily accessible location, so users don't have to be guessing and wondering how PasswordSafe works, and can decide for themselves if PasswordSafe + Yubikey is for them.
I'll try to describe what kind of protection is currently (3.33) used in pwsafe. If I missed something, Rony or David (or anyone else) will correct me. My English isn't great, alo I'm not a crypto expert, so to avoid any misunderstands, it shouldn't be treated as “official description of Password Safe protection mechanisms” until Rony say that all is correct.
The short answer is: if someone can install trojan/keylogger on your systems, he can get access to your passwords.
Below there is “long version” with some ([over]simplified) implementation details where I'll try to show, that not all things are obvious and not all solutions that “lie on the surface” make application more secure. [Of course, most of security solutions that are used in pwsafe aren't pwsafe-only features, in opposite pwsafe try to use solutions that are proven by time and in theory. I just wanted to make it a bit clear and show that before applying any new technique one should check if it give additional security and not inversely].
Let's describe different attacker skills and measures that may or may not stop him.
A1 is least powerful attacker, who have a copy of PasswordSafe database and haven't any additional information from the user's host.
PasswordSafe uses strong crypto algorithm (TwoFish), so while there is no known weaknesses that may help to recover key in short time the only way, that A1 may get unencrypted data is “brute force”+”dictionary” attack. As usual, key factor here is “password strength”: if password is long enough and isn't dictionary-based (or predictable), A1 must to check a lot of passwords. But there are two things that may help A1:
A1.1 - computing performance (using multiple computers and/or GPU);
A1.2 - some common data in container that may help to check for password correctness in parallel (if A1 have many containers and want to break them all), or some precalculations may reduce time for checking passwords when A1 will try to attack another container.
To prevent this, pwsafe use some sort of Password-Based Key Derivation Function (PBKDF) that do two things: “stretch” and “salt” password, the first helps to use password with block ciphers, and the second make collation attacks more complex:
- To prevent capability A1.1 we need to force attacker to spend more time on every password correctness check. The first thing may be “let's add a delay after each login attempt”. But this will help only in some remote (authentication) checks. When attacker have container locally, have access to code (or binary, it's doesn't matter because of Kerckhoffs's assumption) he can remove this delay, or write it's own check function. So, to slowdown A1 we need to make check for password operation “hard to compute”. This is achieved by using multiple iteration of crypto hash on password (p'=h(h(h(...h(p)...)))). Because of crypto hash properties, if we decided to use 1000 iteration of hash functions, attacker will need to calculate hash 1000 times, and can't get much speed up with writing it's own version. [In v3.32 option to increase number of hash iteration was added to user interface.]
- When computing crypto key from password, PBKDF also uses “salt” (some random value). Salt added to password when calculating result crypto key, so every two databases that use the same password will be encrypted with different key and it effectively limit capability A1.2. (Salt is stored unencrypted in database and will be known to A1 we he'll get the container, but it doesn't matter). [more details at docs/formatV3.txt]
So to prevent A1 attacks, one need to use “strong master password”.
Now let's add some more power to attacker and consider A2 – attacker that have power of A1 and
A2.1 - keylogger on user's PC.
In that case PBKDF don't help much. Attacker have list of keystrokes and don't need to check all key space to find right password. All he need is to check which sequence of captured symbols will unlock the safe.
What we can do to resist A2.1? Right, we need to prevent keystroke generation when entering passwords. It may be done using “virtual keyboard”: we don't press keys but instead click somewhere. (One can use some third-party virtual keyboard or virtual keyboard that is implemented in pwsafe). But there is one problem: attacker may have one more capability:
A2.2: capture mouse clicks and take screenshots (full screen or some region under mouse pointer at click time).
Implementation of A2.2 capabilities isn't hard, so we may assume, that any attacker from A2 group have both A2.1 and A2.2 capabilities. In that case “virtual keyboard” in most cases should be treated as a way to type password with international characters if correspondent physical keyboard layout isn't available and not as security measure.
Another way to prevent A2 attacks is to use something that will be needed to unlock database, but what will be invisible and unpredictable by A2. For such cases 2-factor authentication is used. Where the 2nd factor is a different way of getting part of key (so when app uses 2 password, or password and “security question” it is not 2-factor authentication, because A2 can collect both passwords, and this case will be not much different for attacker than one-password case). One of the ways to implement it is to use hardware token as 2nd factor. In our case it's YubiKey. YubiKey can work in 4 modes:
Y1 - static password;
Y2 – HOTP (HMAC-based One-time Password);
Y3 – TOTP (Time-Based One-Time Password);
Y4 - HMAC-based challenge-response mode.
Y1 doesn't add additional protection, because in that case password in not changed and, for the application it looks like user type this password on keyboard (YubiKey here works as keyboard-like HID (Human Interface Device)), so A2.1 will catch it. And, because it's not changed, A2 may use it to open container.
Y2 and Y3 looks interesting because each time additional password isn't known to A2 and can't be predicted by A2, because he don't know key, that is stored inside external token. But these algorithms are designed to use with client-server architecture and can't be used with pwsafe. The main problem is in a way how Y2 and Y3 generate keys:
- Y2 change key on each call, Y3 change it with time (each 30 seconds, or something like) so without serious modifications,
- it will be impossible to user to open safe that was saved some time before (for example, manual or automatic backup);
- we'll have to remove Read-Only mode because after each open we'll need to change “additional key” to the next in the sequence and reencrypt database, otherwise we can't open database with new value that will be generated by token next time;
- if someone mistakenly generate “next key” (touch button on YubiKey) pwsafe can't open database next time (in standard use-cases for Y2/Y3, problem solved on the server side by checking for some values ahead, but until container is opened, pwsafe can't know OTP's secret key and can't move OTP sequence back or forward).
So pwsafe uses Y4. In challenge-response mode pwsafe send user's master password (or empty string, if user decided to use YubiKey only mode) to YubiKey, which transform (HMAC-SHA1) it and send back (response). Then response is used instead of “master password” for PBKDF. [because of HMAC properties there is no security problem to have empty challenge value in "token only" mode (besides the case, when attacker got both YubiKey and container, but it's not our case)] In short, HMAC is crypto hash based function and transformation is like calculating hash from given value, but there is one difference: it uses secret key, to prevent A2 from calculating that valued by itself (because hash function is known to A2 (Kerckhoffs's assumption), without addition of secret key, A2 can calculate this hash and it will return us to 1-factor case). Secret key for HMAC is stored in YubiKey and HMAC(p) is calculated inside YubiKey too, so in most cases secret key can't be intercepted by A2 (the only way for A2 to intercept it is to make a screenshot when user initialize YubiKey using “Manage->YubiKey...” dialog and press ”Show” button). Each time “2-factor master key” will be the same (HMAC(p)), but A2 can't intercept HMAC result, because for challenge-response mode YubiKey uses another way to pass data to/from token than key presses (some other HID functions).
Small note: One may ask if we need to use PBKDF after HMAC? [HMAC procedure will “stretch” the password to hash output length and secret key plays a role of salt (but more stronger, because attacker don't know it)]. I see here two cases
- at first [and I think it's a main reason] this way allow to ensure that key will have needed length (in case if in future other HMAC function with different output length will be used) and it simplifies integration to pwsafe, thereby reducing number of possible implementation errors;
- But it also may help to provide security level not less than that we have with non-Yubi auth, if some major error in HMAC implementation or process of generation of secret key for HMAC will be found (for example, let say, that attacker can have a password and predict a part of secret key, or predict full secret key, but don't know non-empty password), without PBKDF he'll have ability to iterate over remaining part with much more speed that in usual case, when PBKDF is used.
So adding YubiKey will allow to resist A2 attacks.
But let's go further and consider A3 attacker, that have the power of A2 and
A3.1 - can sniff USB (HID) traffic.
(In most cases A3 will need to install additional driver or have some additional privileges, but it may not be a problem for some malware. These type of loggers less widespread than A2, but I think they are exist.). A3 can intercept response from YubiKey and use it to open container without YubiKey.
So current YubiKey implementation isn't resistant for A3 type of attackers.
Let's see what we can do here. Let's try to add some randomness to this process. We may add some sort of salt to password before asking YubiKey to calculate HMAC. But if we implement it directly, we'll have one limitation: before each save we'll need to ask user to touch YubiKey. [In non-open source and not focused on security product it may be turned to feature: “No one can ever change data in your safe without having the key”]. But there are two problems here:
- to make “auto save on change” and “fail safe” copies we will need user assistance, that may prevent from creating such copies (especially “fail safe”),
- it only slightly change possibilities of A3.1: because we need to ask token to give us HMAC for encryption, attacker may caught it and use it for this copy as in plain non-randomized way.
Also here we can consider one more A3's capability, that make this attacker active:
- A3.2 - change HID data sent in request or response.
We haven't considered active form of A2, because it may be not easy to him to detect when data change should be made, and these changes may be visible to user. But A3.2 have more possibilities for such intervention: user can't see challenge-response data, pwsafe uses slot 2, agent can compare password typed at keyboard with part of challenge, that is sent to the token, etc.
So when A3.2 correctly determine that request go from pwsafe, he can remove random part (if we simply attach it to password without hashing), changing it to some fixed value so this case will be degraded to non-randomized case, or even change the response to some known-to-attacker value. User may notice this when he'll try to open database on non-infected computer, or when attacker change request/response for container that was created before machine was infected or when attacker incorrectly detect that request from pwsafe (in last case A3.2 keylogger can send non-changed response if the second call to token was with the same challenge data, so on the second call application correctly get access and user will think that it was communication failure).
What we can do here? We need change a way of computing next password, so it will not be disclosed before attempt to unlock.
To do this, we need to ask YubiKey for HMAC only when unlocking container, and calculate HMAC when changing key to new one without access to the token (except the case when container created). It may be done if we have HMAC secret inside container (it should be stored in encrypted container's header [and we already have it here in container that was used to initialize YubiKey to allow user create backup copies of YubiKey]) and know what kind of HMAC is used. Also, we may add some protection to prevent challenge spoofing by A3.2: instead of sending simple “random|password” to token, we may hash it before, to make application detection harder. One more way to detect spoofing when creating first encryption key with YubiKey if we know HMAC's secret key is to check that token send us correct response, comparing received value with one that we calculated internally (something like this already used to check that entered password is correct: hash of encryption key h(e) is stored in header and after getting the result of PBKDF transformation hashes are compared h(e) == h(PBKDF(p)), [because of crypto hash properties, having hash of encryption key in header doesn't reveal key to attacker]).
This case looks better and one could say that we defeat A3... But wait, we forgot one thing: backup copies. If backup copies (intermediate or auto) aren't disabled (I think that in most cases disabling them isn't good idea, because most of time you'd like to have a way to restore your data in case of failure at save time) before saving changes to new file old file is renamed to “*.ibak” and than new file is created. Because we make backup by rename and not create new one, A3 can open it (he captured response from token when container was opened) and if we have HMAC secret stored in it, extract it and use to open any containers that will be saved in future with the same secret key and password (captured using A2 capabilities). So, while we have intermediate/auto backup enabled, this solution also can't stay against A3.
[Manage->Make Backup works differently and it's possible to change a challenge's random part when backup is created.]
You may ask, why backup is created as rename: I think it's made to prevent failures while creating backups. For example, if you have not enough of free space on the drive, or access rights on parent folder were changed, you can't create new files to save backup information to it and even may not have ability to save new one (changed) too. Also if there is something wrong in program itself, you may create both (new and backup) files incorrectly and will lost your passwords (when using rename, you'll not change the file, so backup will not be damaged).
And, at the end, the time for few more bad news:
- Don't forget, that attacker from A2/A3 group may capture passwords that you are typing/copying. Some attackers from A2 group may have A2.3 capability – capture data from clipboard and intercept software-generated keystrokes. So besides master password, A2 may get any password that you've used while keylogger is run. (pwsafe have “dragbar” and “autotype” functionality that may resist for some keylogger implementation, but, in common case, “dragbar” and “autotype” should be treated as “usability features” and not as “security features”.)
- It can be one more class of attackers: A4 that may dump process memory, hook (API) functions, etc. Password Safe store data in memory encrypted, but this attacker too powerful and may extract information (at least passwords that were used in this session) using some side channels, when they are decrypted for usage or displaying. He also may have ability to extract YubiKey master key from database header, when it is stored to allow user to make (backup) copies of YubiKey. (Probability to have such agent, that is focused on PasswordSafe, is lesser that for A2/A3 attackers, but, as always, is not zero.)
PS: As for documentation, Password Safe is Open Source project, so anyone who have time to write good documentation may send it to Rony:)
Thank you for that long explanation. It made a lot of sense to me, mostly because I've thought through most of it already. I think that your attacker A3.1 is the strongest threat worth worrying about--it isn't beyond the power of a well-implemented trojan, even one not specifically written for PwS. This is why I was worried about the static challenge response (static meaning that the same challenge is given each time, and the same response is used to encrypt).
The solution I think is what you described to defeat A3: use a random challenge each time the container is encrypted. To do that, you would need to store the challenge unecrypted outside the container, and the secret key inside the encrypted container. Each time the container is saved, then, PwS would generate a random challenge, ask for the password, calculate the HMAC from password|challenge (or a hashed version) using the stored secret key, encrypt the container with the HMAC (or PBKDF transformation), and finally store the challenge on the outside of the container. When unlocking, it would ask for the password, send password|challenge (or a hash) to the Yubikey, and unencrypt the container with the response.
The one semi-serious problem I see is the one you identified above, concerning the backups. But honestly, I would be willing to give up the auto backups for something that can defeat A3. It would require a bit more user interaction, but what I would like to do, if PwS supported it, is to use the random challenge method described above, disable the auto backups, and make my own backups using the Mange > Make Backup menu, which I hope would then generate a new challenge. I would not mind the small additional risk of creating a corrupted backup and not noticing. (I just realized that you can't "test" the backup, because that would expose the HMAC used to encrypt that copy.) It isn't perfect (nothing is) but for me the tradeoffs would be worth it.
Thanks to the developers for all the hard work!
There will be one more usage/implementation issue for randomized challenge: we know the Yubi's secret key only when initialize it, so if you want to use one YubiKey with several containers you'll need to somehow "derive" new database from that was used to initialize the key (to copy key from it).
As for implementation, you may create feature request with the link to this thread.
This is now feature request #745:
Thanks for the good discussion, Andrey.
This is just to publicly acknowledge the correctness of Andrey's description, and to thank him for the time and trouble he took in writing it out so clearly.
I wonder if adding a Secure Desktop functionality to the login screen, as KeePass does, would help. I don't know if such an environment is compatible with USB access, and even if it does it probably would not protect the USB data exchange against keyloggers, but it seems that it may provide some added protection to Andrey's A2 attack scenario (excellent treatise by him!).
I know that Secure Desktop can expand the protection against keyloggers, although I can envision some smart loggers that may circumvent that protection.
Some interesting discussion about Secure Desktop:
Yes, using the Secure Desktop would in general be a Good Idea (although not a bullet-proof solution). Don't expect a problem with USB/Yubi and this.
Any volunteers for coding this? My todo queue is a bit long lately...
Since I now have some free time, I am prepared to research this and, hopefully, implement it.
Let me know if you agree as I wouldn't want more than one person spending time doing the same enhancement! Maybe add this as a FR and assign as appropriate.
PS: FR 1 is similar but not exactly this feature and I think this FR could be closed as I implemented a multi-language virtual keyboard in PWS quite a while ago.
Sorry off topic, but I am running pwsafe 3.32 under OSX with the brew installation of wine (not crossover). Everything appears to work as expected, EXCEPT, pwsafe does not detect my yubikey. The serial number box is empty and the generate button is grey. Any suggestions ? Thanks.
Edit : I upgraded to 3.33, same result.
Log in to post a comment.