3

I'm looking for some basic algorithm to:

  • generate a code
  • send it to a website,
  • where after payment a token is generated from the code and sent back,
  • where the token is validated.

I'm not sure how to ask in cryptography terms, so I'll explain what am I looking for:

I have an app that runs on a watch. I'd like to display a short code (number or textual string) on the watch, then use this code in a website (that I'll implement) where the user can purchase a license, and as an output gets a token (or signature). Then the user types in this token in the watch settings. And then the watch validates the returned token.

The watch has very limited capacity, memory, code size, etc, so I'd like to have an algorithm that is tiny (at least the part that runs on the watch)

Every watch has a unique identifier uuid (that is unique for the physical watch + the app) that can be used as an input (wouldn't use it as the code probably, something shorter, like an 8-12 character number would be more useful)

The website can do probably anything, there's no issue with resources there.

The token would be some short string or number.

And then when the token is typed back into the watch the algorithm on the watch should be able to verify that:

  • the token was generated using the code that was generated from it's uuid

  • the token was generated/signed by the website. The website probably knows some secret. The watch doesn't know the secret, only some "public key" related to it that is hard-coded in the watch app.

The point is that the code that runs on the watch should be as short as possible.

There's no need for super secure stuff, just something that makes it a little harder to hack than what other similar apps do: just sent me some static string as a "token" like "PaidAPP123" (that is easily passable to another watch user)

Rohit Gupta
  • 489
  • 2
  • 5
  • 10
Gavriel
  • 131
  • 2

2 Answers2

1

Perhaps the simplest cryptographic solution I can think of is to generate a Pepper value for each watch UUID and save that as a column in your DB. The pepper value can be as short or as long as you like. The important thing is that no two peppers should be identical across different UUIDs - if you guarantee that, you won't have the "static string" problem you've mentioned.

So on the server side you have:

  1. UUID
  2. Pepper

Then, on the watch (aka client side), you store two values:

  1. UUID
  2. UUIDHash = SHA256(UUID || Pepper)

Where || means concatenation.

SHA256 is only 32 bytes long. For comparison SHA512 is 64 bytes long. You can use either and it'll be good enough, or even SHA-3 if you want to.

Now, a payment request is successfully completed for a certain UUID. So all you need to do is send back the Pepper value to the user, the user types it in, and then the watch performs the following verification:

if (SHA256(UUID || ReceievedPepper) == UUIDHash) bActivated = true; else bActivated = false;

I apologize for the sketchy pseudo code :) but hope that can be helpful.

This may be trivially broken if you allow for an attacker that is able to reverse engineer the watch. All he needs to do, after figuring out the algorithm, is to perform an exhaustive search for the Pepper value that will give him the correct "SHA256(UUID || Pepper)" result. He will presumably run that search on a very fast machine and not on the watch :) That's where the length of the pepper comes in. I recommend it to be 16 bytes or longer to make such an attack computationally infeasible.

Note also, that even if an attacker recovers the pepper for a single watch, he can't find a "universal pepper" to unlock all watches. Although, if you choose to go with a short pepper value (anything less than 10 bytes is rather risky in that respect) it will be rather easy to create a universal "KeyGen".


Just as a rough sketch: If you're concerned about such attacks, the "next level" solution I suppose, would be to create a unique asymmetric key pair for every watch (either RSA or ECDSA). Instead of saving the Pepper on the server, and the hash on the watch, you now save the private key on the server, and the corresponding public key on the watch. An activation request comes in for a certain UUID... the server signs a plaintext via the corresponding private key that includes the UUID of the watch and sends it back. The watch is able to verify received signature via its public key and its UUID as input. Again, only a rough sketch, because from what you say you are not interested in that level of security, but note that here the attacker is faced with forging an RSA/ECDSA signature, which is much more difficult, assuming of course you're using them with secure parameters and with secure key sizes....

An obvious question is why a unique key pair for every watch? Actually this is probably not necessary, if there is no clever attack that you haven't anticipated... you see once you allow all signatures to be created via the same private key, then the decryption part of the signature verification by definition will always succeed.. and that means you've given the attacker a slightly bigger attack vector, since you're now running more code before returning an error. Finally, I think that assuming you already have a DB containing all UUIDs (actually I may be wrong about this, and then also the first scheme fails) the overhead of generating a key pair for each one is not that significant.

Edit: @fgrieu mentioned in the comments a good point, which is that a signature is practically problematic because the length of a secure signature is too long to be keyed in, at least for the algorithms which are widely used. There are probably ways around this, there are apparently "exotic" algorithms like BLS that provide shorter signatures of supposedly adequate security. Also, if the watch is able to sync with a local phone app, that can scan a QR code, that is much less of a problem - but of course I don't know if your product has such a capability. At any rate, if you choose to go the signature route, these are definitely issues to take into consideration.

Amit
  • 432
  • 3
  • 13
0

One serious problem with what you are trying to do is the required size of the signature: like 50 bits, determined by the fact that the signature must be keyed in.

The smallest mildly secure (public key) signature we know how to make is about 200 bits (give or take), and that's a few times as much as can realistically be keyed in. The best known option for short or no message (as seems to be the case in the question) is BLS signature, but choice of parameters is a subject on which dust has not settled yet, see this question.

Sadly, you'll have to accept there is something secret involved in the verification of what the user keys in; and then a 50 bits symmetric Message Authentication Code is perfectly fine.

fgrieu
  • 149,326
  • 13
  • 324
  • 622