2

I understand that WebauthN is designed to perform authentication, but I'd like to use my Yubikey to create symmetric encryption keys to encrypt content on my web browser without relying on a backend server.

Here's my approach:

  • During the assertion challange ( navigator.credentials.get({ publicKey }) ) the Yubikey signs a challenge string that the client sends to the authenticator.
  • I extract the signed challenge, hash it with SHA256 and use it as my new symmetric encryption key for AES256 encryption.
  • As long as the same challenge string is sent to the Yubikey, the encryption key will always be the same.

In order to be able to decrypt the content on the web browser. I would have to be in possession of the Yubikey and the challenge string for 2 factor authentication.

Is there anything wrong with this approach?

ucipass
  • 923
  • 1
  • 8
  • 21

4 Answers4

2

Why don't you use the Web Crypto API?

This API is designed for cypher operations on client side and is suitable for your use case (client side encryption). It is supported by all recent browsers.

Note that the main concern you may have is that this API does not supports hardware devices (smartcards, security tokens...).

However, your Yubikey is certainly capable of generating a secured static password you can use as a master key you will derive to encrypt/decrypt your data.

Spomky-Labs
  • 15,473
  • 5
  • 40
  • 64
  • I was planning to use the crypto API for symmetric encryption, I just need to secure my symmetric key with a hardware token. This "hack" would require something you know (the challenge string) and something you have (token). The static password is a viable option but not as secure (not 2 factor) – ucipass Nov 27 '21 at 11:19
  • AFAIK, the static Yubikey password is not protected by any means (just the golden button to push). If it is mandatory for you to have an additional factor, then the [OnlyKey](https://onlykey.io/) might be more appropriate. Either way, the Webauthn protocol won't help you here because the output from the FIDO device is never the same, even though the challenge is the same. Signature algorithms are designed as such and there is an internal counter to avoid reusable outputs. – Spomky-Labs Nov 27 '21 at 11:43
  • Perhaps, I missed something about the inner workings of FIDO/CTAP2. I thought that the private key stored on the authenticator is used to sign the challenge string only, so that portion of the devices response must always be the same. So if send the same request with ( `navigator.credentials.get({ publicKey })` ), the assertion signature coming back from the authenticator will be different, due to a counter also being included during the signing? I have not seen this anywhere in the doc, but if you happen to have a quick reference I'd appreciate it. Thanks again! – ucipass Nov 27 '21 at 13:26
  • The counter (`signCount`) is modified each time the authenticator sign the data. As [signCount is part of the signed data](https://www.w3.org/TR/webauthn-2/#sctn-authenticator-data), the computed signature will undoubtedly be different – Spomky-Labs Nov 27 '21 at 14:10
  • You are correct about the counter, so this will definitely NOT work to create a consistent symmetric key. Thank you! :-) – ucipass Nov 27 '21 at 14:19
1

Perhaps you could leverage the hmac-secret extension (https://fidoalliance.org/specs/fido-v2.0-rd-20180702/fido-client-to-authenticator-protocol-v2.0-rd-20180702.html#sctn-hmac-secret-extension)?

aseigler
  • 504
  • 3
  • 7
  • I was not aware of this extension. Do you happen to have a reference repo somewhere demoing this functionality? This may be exactly what I am looking for and I do not even need a "hack" for it. :-) Thanks!!! – ucipass Nov 27 '21 at 21:09
  • Github looks completely down at the moment (!) but when it's back I would check https://github.com/Yubico/libfido2, there's probably something there that will get you started – aseigler Nov 27 '21 at 21:17
  • Hi @aseigler, I was not aware of this extension. I have one question though: what if the user verification is discouraged? Is it still possible to get the static password when no PIN or fingerprint is requested? – Spomky-Labs Nov 28 '21 at 15:58
  • I don't see anything in the spec indicating that UV would be required. – aseigler Nov 28 '21 at 18:05
  • Check out https://github.com/Yubico/python-fido2/blob/master/examples/hmac_secret.py – aseigler Nov 28 '21 at 18:14
1

No. This is a bad idea for these reasons:

  • RS256/ES256 are not deterministic signatures. So you will get a new, random signature every time.
  • Even if you could, there are things like XSS, and this would be broken swiftly.
  • Use crypto API as mentioned above.
  • HMAC-Secret is reserved for Platforms at the moment. You can not access it via WebAuthn API.
  • In the future, there is a large blobs functionality, and largeBlobsKey... But this is a very long future...
Ackermann Yuriy
  • 537
  • 3
  • 10
  • Your statement **RS256/ES256 are not deterministic signatures. So you will get a new, random signature**. That is not correct for RS256. If that were true, RS256 signing could not be validated. – John Hanley Dec 09 '22 at 03:24
0

You could (mis)use the user.id parameter of the public key request payload, i.e., the user object in the example here: Web Authentication API (example) like this:

  1. Use Web Crypto API to generate a symmetric key
  2. then use that key as user.id in navigator.credentials.create({ user: {id: YOUR_KEY } }) to store the key in the authenticator
  3. store the returned key id/rawId somewhere in your application

To retrieve the key you can use navigator.credentials.get({ publicKey }) by supplying the rawId

Jakob
  • 1
  • 1
  • Yes, but wouldn't this be insecure? I may be missing something but the actual key should never leave the Yubikey. – ucipass Sep 02 '22 at 21:21
  • You are correct, the key will be transferred between authenticator and browser. This solution just mimics your original proposed hack, except that instead of using the signed payload as key it uses a data field that is stable between authentication request. – Jakob Sep 05 '22 at 08:36