1

I have a requirement of OTP applications on mobile devices not sharing the same secret (even if the mobile devices are owned by the same user). A single secret must be present in a single device.

Open source applications that implement OTP (like Google Authenticator and FreeOTP) do not satisfies my requirement: the secret is not device unique, due the fact that I can scan the QR-Code with more than one device and backend never will know about that. I think it is not something related with the application itself, but with the RFC 4226 that not specifies this requirement.

So I thought about a process to mitigate the risk of users using OTP secret in more than one device (need internet connection - not a requirement be offline). The steps:

  1. App generate unique secret protection key on first execution
  2. App send the secret protection key to the server
  3. Server generate a unique secret for app
  4. Server encrypt the secret using the secret protection key from the app and return the blob to the app
  5. App decrypt the info using the generated key and starts to generate OTPs
  6. Both encrypted secret and secret protection key would be storaged on app

I know that this approach is not tamper-proof and the secret could be restored from storage but would be more difficult.

About all explained here, my questions are:

  • Would be a good approach exchange OTP's secret through web, even if it is protect by TLS?
  • Is the unique secret protection adding security or a flaw to the process?
  • Would be possible to achieve a similar result in a offline sync?
  • Is there open source frameworks to achieve a better protection of the secret key (i.e. not exposing directly to user, like QR-Code does)?
rcorreia
  • 155
  • 5
  • What sort of attack are you planing on preventing? Are you trying to stop a casual user from sharing secrets between devices, or are you trying to prevent a determined hacker from doing the same? If it's the latter, you would need some way of ensuring someone doesn't spoof both the secret AND the checks to make sure the secret is unique (such as using a different device's unique ID) – Cort Ammon Jul 20 '17 at 16:51

3 Answers3

4

If you're designing your own authentication app; instead of scanning the OTP token, scan an authorization token that will then be used to retrieve the OTP from a server. The server can then be setup to only release the token once. Bundle certificate pinning into your application, and you're good to too.

The flow would look like this.

  • User requests OTP token from website
  • User opens app and scans QR code, which contains one time use API key
  • App then contacts server, verifies certificate with pinned cert
  • App submits one time use API key, server returns OTP token and marks the API key as defunct.
zzarzzur
  • 1,112
  • 8
  • 8
  • interesting. I can continue using QR-Code but with secret protected by API. I think my approach is more obscure, due the user can't see the URL, but I think is equal to yours when talking about effective security. Thanks. – rcorreia Jul 20 '17 at 16:22
  • @rcorreia Nowhere is the URL shown to the user, only the key that they would use to retrieve the token is shown. The URL would be hardcoded in your app. The extra encryption step is over complicating it in my opinion, as you should be already using TLS. I'd recommend switching the secret ID to the device UUID generated from the system API. On initial setup transmit a hash of the UUID. From there on you can append the UUID hash to the OTP hash to ensure security. If you continue to use the system function, keys will be unique. – zzarzzur Jul 20 '17 at 16:41
  • @rcorreia Using the device UUID would further protect your app, as the saved hash would be useless without the UUID. – zzarzzur Jul 20 '17 at 16:43
  • For perspective: this is mighty similar to how Bank of America handles its two-factor-authentication. They issue a token which can be "released" by sending a message with the token and the code from a text message. – Cort Ammon Jul 20 '17 at 16:54
2

You may wish to use the device ID to implement a deterministic secret unique per device as described in the RFC 4226, nothing enforce the secret to be transmitted (but it's recommended to use the random generation).

 We distinguish two different cases:

      - A single master key MK is used to derive the shared secrets;
        each HOTP device has a different secret, K_i = SHA-1 (MK,i)
        where i stands for a public piece of information that identifies
        uniquely the HOTP device such as a serial number, a token ID,
        etc.  Obviously, this is in the context of an application or
        service -- different application or service providers will have
        different secrets and settings.

Alternative to your scenario of the random key generated on first execution, the app may use the device uuid as encryption key in your 1 and 2, which makes it harder to reproduce on another device.

Tensibai
  • 513
  • 2
  • 10
  • Hi! Thanks for the answer. I did not read all the RFC 4226 and derivation is a nice approach. – rcorreia Jul 20 '17 at 16:07
  • I would not deem the device ID as a secure/secret identifier. Please note, that this derivation is ment for key management within the validation server. RFC4226 was written long before smartphones existed. HOTP was designed for hardware tokens! – cornelinux Aug 10 '17 at 20:06
  • @cornelinux indeed, the concern here is users sharing the same key by mistake or intentionally, using the phone uuid as derivation base sound a valid approach but is not as secure as a random generation. – Tensibai Aug 11 '17 at 07:26
2

I totally understand your need, since scanning the QR Code with the Google Authenticators KeyURI will result in "copies" of the authentication possession.

Interesting enough there is an RFC for this: https://www.rfc-editor.org/rfc/rfc6063.txt But my suspicion is that this might be a bit overkill.

I am working on our own authentication server which apart from many other authentication devices also support smartphone apps like the Google Authenticator which scan the OTP secret in "plain text". As stated, I really do not like this, so we also began to think about improving the rollout process. These are our thoughs so far: https://github.com/privacyidea/privacyidea/wiki/concept%3A-SmartphoneApp

Basically we want to be able to enroll a smartphone without internet connected. Sometimes the smartphone does not have a connection or sometimes the authentication server, where the token is enrolled, is not accessable by the smartphone, but only by the desktop client. So we thought about still relying on QR Code.

But instead of only transporting the secret key within the QR Code and thus making the token copyable to many smartphones, we need a second component generated by the smartphone. The simplest way is this:

  1. The authentication server provides the first compoment of the secret key in a QR Code
  2. The user scans this QR code with his new, shiny App
  3. The App generates the second component and simply displays this to the user.
  4. The user types in this second component into the enrollment page of the authentication server.
  5. Both, the server and the smartphone app calculate the final secret key based on the component generated by the server and the component generated by the smartphone app.

Plus: The workflow is rather easy and not prone to errors

Minus: An evil user could still write down the first component of the server and the second component generated by the smartphone and "manually" calculate the secret key and use this secret key on several smartphone apps. But this is still a nasty process. The main goal was to protect from lazy, evil users, who might simply ask their colleague: "Hey scan my token, too."

I am curious, what you think of this. If you like this follow us on github or contribute, maybe this might be a solution for you, too.

cornelinux
  • 1,993
  • 8
  • 11
  • Wow, awesome. It is a great approach indeed. In fact the best answer so far. Would be even possible to continue the process online and give the chance to the user type the code if no internet is available. I liked the use of HMAC to sign the info from server. The only problem is that I can't force the user to type large keys due usability. What would be a good lenght typeble by the user in your opinion? – rcorreia Aug 15 '17 at 13:41
  • We probably will make the length of the user's part configurable. The final secret key will be made up of the server's part and the user's part. Even a length of 6+checksum (7 characters) will be enough, to prevent easy copying of the secret. Although you probably need a longer user's part to be "cryptographically safe". Again: It is a question of against which threats you need protection. – cornelinux Aug 15 '17 at 14:28