Score:3

Basic, easily implementable (and small code size) algorithm for validating signature/token

cn flag

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)

Amit avatar
ci flag
What you're looking for is something like "Secure generation of a license key via asymmetric cryptography". There's a lot of information about that. Naturally, this is a sensitive aspect of any software and probably needs to be addressed by someone with a good grasp of security *and* cryptography (since it's not only about encryption, but also about the protocol for activating the product). Good luck.
Amit avatar
ci flag
(The upshot is that you will ideally want to sign whatever data, perhaps UUID, the user has typed in the browser, under a private key, and then the watch can verify the signature under a public key. The watch *should not* contain the private key.)
fgrieu avatar
ng flag
One serious problem with what you are trying to do is the size of the signature, which must be keyed in. The smallest reasonably secure (public key) signature is about 200 bits (give or take), and that's a few times as much as can realistically be keyed in. Instead, you'll have to accept there is something secret involved in the verification of what the user keys in (and then 50 bits are perfectly fine). Update: comment made a [full answer](https://crypto.stackexchange.com/a/105688/555)
Score:1
ci flag

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.

Gavriel avatar
cn flag
What I don't understand is who generates the pepper? If the client, then both the UUID an the pepper has to be sent to the server, but then the bad guy knows the pepper when he sends it to the server. If the server generates the pepper, then it has to send to the client both the UUIDHash and the pepper.
Amit avatar
ci flag
@Gavriel - No, I am assuming that as you manufacture those watches, you also create a record for each of them in your DB which is of course on the server side. That's where you generate the Pepper, but you don't insert the Pepper to the watch. It should only be on the server DB. Please look again: I tried to write clearly what is saved on the server side first, and then on the client side (watch) second. In particular SHA256(UUID || Pepper) does *not* mean you are saving the pepper on the watch. The pepper cannot be deduced from this hash value.
Gavriel avatar
cn flag
Ah no, it's not manufactured by me :) I am creating an app to a Garmin watch. Anyone can buy a watch from Garmin, and download my app to it for free, and use the basic functions, but only pro users who paid will be able to use the pro features
Amit avatar
ci flag
@Gavriel - Okay, I suppose it still doesn't matter, if you have access to all those watches UUIDs - you can generate Peppers for each of them after the fact as well. The point is simply being able to generate pairs of (UUID , Pepper) on the server side, where the pepper is of course secret. And then insert the pair (UUID, Hash) to the watch, with the hash calculated as described above.
Gavriel avatar
cn flag
yes, but where? on the watch or on the server?
Amit avatar
ci flag
The Pepper *must* only exist on the server! The watch only contains the hash of (UUID || Pepper).
Amit avatar
ci flag
Let us [continue this discussion in chat](https://chat.stackexchange.com/rooms/142940/discussion-between-amit-and-gavriel).
Gavriel avatar
cn flag
My point is that the server needs to send both the UUIDHash and the pepper to the watch, which is quiet a different flow. Besides because the communication is by copy&pasting basically the bad guy can create a random pepper with the UUID, and paste back the UUIDHash + pepper he created
Score:0
ng flag

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.

mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.