52
$\begingroup$

I have finished developing an app for Android and intend to publish it with GPL -- I want it to be open source. However, the nature of the application (a game) is that it asks riddles and has the answers coded into the string resource. I can't publish the answers! I was told to look into storing passwords securely -- but I haven't found anything appropriate.

Is it possible to publish my source code with a string array hidden, encrypted, or otherwise obscured? Maybe by reading the answers from an online database?

Update

Yuval Filmus's solution below worked. When I first read it I was still not sure how to do it. I found some solutions, for the second option: storing the hashed solution in the source and calculating the hash everytime the user guesses. To do this in javascript there is the crypto-js library at http://code.google.com/p/crypto-js/. For Android, use the MessageDigest function. There is an application (on fdroid/github) called HashPass which does this.

$\endgroup$
10
  • 12
    $\begingroup$ I wonder how ontopic this is here; it may be better suited to Information Security in any case. $\endgroup$
    – Raphael
    Commented Oct 6, 2014 at 5:02
  • 2
    $\begingroup$ @YuvalFilmus Don't be fooled by "Hot Question" votes. But point taken. $\endgroup$
    – Raphael
    Commented Oct 7, 2014 at 5:25
  • 4
    $\begingroup$ The important details missing here are: Do you want to just verify user answers or do you want to be able to print the correct answer too? And, do you need any fuzzines, or is there just a clear limited set of correct answers (which so you can check user answer against this set one-by-one)? $\endgroup$
    – hyde
    Commented Oct 7, 2014 at 19:40
  • 4
    $\begingroup$ All answers are asking what the problem is you want to solve. Why can't you publish the answers? $\endgroup$
    – Rhymoid
    Commented Oct 7, 2014 at 22:37
  • 1
    $\begingroup$ What does your code need to be able to do with these strings? Does it need to be able to decode them? Or is being able to compare strings to them sufficient? $\endgroup$ Commented Oct 8, 2014 at 18:09

6 Answers 6

87
$\begingroup$

You have at least two options, depending on what problem you want to solve.

If you want innocent readers of your code to not get the answers inadvertently, or you at least want to make it a bit difficult so that users are not tempted, you can encrypt the solutions and store the key as part of your code, perhaps a result of some computation (to make it even more difficult).

If you want to prevent users from retrieving the answer, you can use a one-way function, or in computer jargon, a hash function. Store a hash of the answer, and they you can test whether the answer is correct without it being possible to deduce the answer at all without finding it first. This has the disadvantage that it is harder to check for an answer that is close to the correct answer, though there are some solutions even to this problem.

$\endgroup$
9
  • 9
    $\begingroup$ One thing I'd add is that if you need even more security, each answer should probably be salted with a different salt. This avoids a dictionary attack against all answers at once. If you want to see how the "real" crypto people do it, take a look at the String-to-Key system in OpenPGP. $\endgroup$
    – Pseudonym
    Commented Oct 6, 2014 at 0:19
  • 1
    $\begingroup$ Keeping hashes in code means all information is static and salt/whatever else will be readily available too. I believe as result it would be reasonable if answer space is large enough (like full range of 32-bit integer values), otherwise (i.e. in case of multiple choice questions) rainbow table would quickly give correct answers. $\endgroup$ Commented Oct 6, 2014 at 3:49
  • 3
    $\begingroup$ As Alexei points out, if your possible inputs span a small space, storing the answers in the code will open them up to any determined attacker - and I'm guessing most riddles will have rather small state spaces, in that their answers generally must be either words or relatively small numbers. You can hash or encrypt to avoid innocent mistakes, but there's no preventing somebody from getting the answer who really wants it. (Plus, they could just ask somebody who already solved your riddle!) $\endgroup$ Commented Oct 6, 2014 at 5:01
  • 4
    $\begingroup$ To counter what Chris is mentioning, you can choose a hashing process that is very slow, say it takes 100ms (that's the approach taken by some PK standards). This is still very fast from the user's perspective, but makes enumeration much more difficult. $\endgroup$ Commented Oct 6, 2014 at 5:06
  • 12
    $\begingroup$ @YuvalFilmus Again, to an extent. If your riddle ends in "Was Jan, Joe or Jane the criminal?" then it's going to be very easy to enumerate even if you make the hash take a full minute. Unless the entire game is written with this in mind, and all of the questions are extremely open-ended, this will pose a problem. But yes, if your questions are that open-ended that the state space is sufficiently large, the answers can be protected. $\endgroup$ Commented Oct 6, 2014 at 5:23
29
$\begingroup$

You have two three options:

Keep the answers separate from the rest of the source code

If you want your code to be open source, however don't want the answers to be open source, then you open source the code for the application without the questions & answers, with the questions & answers being a separate closed source "plugin" or data file. Your Android app would bundle both of these together into a single app.

Put the answers in your source code

Alternatively, if you consider the questions and answers to be a core part of what you want open sourced then you should put the answers into the source code, preferably un-obfuscated so that others can read and modify them. Obfuscating source code so that it can't be understood and modified isn't really in keeping with the principles of open source code.

Put the answers on a server on the internet

With both of the above solutions it's possible for someone who has downloaded your app to find out the answers without playing your program in either case - no matter how you obfuscate / encrypt your answers, if your program can identify the answer without additional information, so can a human examining your compiled app.

If you really want to make sure that nobody can find out the answers then the only real option is not to give them the answers and have the app call a web service etc... whenever they want to know the answer. The app should send the answer that the user has entered and the web service should tell the app whether or not the answer is correct, that way the user has no way of telling what the answer is until after they already have the correct answer (short of brute-forcing the web service, which you can detect and protect against).

If you are looking for ways to obfuscate your answers the that suggests to me that you don't really want to open source your answers in the first place, so you should consider the first options.

If it's critical that the user not be able to find the answer in advance then the third option is your only real choice, however I'm struggling to think of a scenario where this would be worth the effort, not least because it prevents your users from using your app without an Internet connection.

$\endgroup$
4
  • 8
    $\begingroup$ The Q&A doesn't even have to be a plugin, it can be a simple data file. Input data files are not necessarily included as part of the licensed software and can be covered under their own separate license. As long as you provide a (different) sample data file to use with the source code, you are not obstructing free use of the source or programs compiled from said source, and thus should not be in violation of the GPL. $\endgroup$
    – Doktor J
    Commented Oct 6, 2014 at 18:19
  • $\begingroup$ I'm not sure that really solves his problem - whether the answers are encrypted and hard-coded in the code or distributed as a separate file, the code still needs to be able to decrypt the answers, so whoever downloads his app can do what the source code does to get to the answers. (unless they are hashed, as suggested in another answer) $\endgroup$
    – Johnny
    Commented Oct 8, 2014 at 0:54
  • 1
    $\begingroup$ If the goal is to check answers and doesn't require them to be shown then it can be done the same way as passwords with a one way hash. $\endgroup$
    – JamesRyan
    Commented Oct 9, 2014 at 9:48
  • $\begingroup$ @Justin, thanks for you answer, and your comments on whether it constitutes open source is interesting. I think that hiding the answers is not intended to obfuscate the source code, or how the application works, but rather to preserve the integrety of the challenge. Cryptography, as it turns out, is a wonderful means to distribute riddles without having to be there when the user guesses ('is it this, is it this?') $\endgroup$
    – Nevermore
    Commented Oct 20, 2015 at 9:05
4
$\begingroup$

If the object is to obscure strings from casual reading of the source code but keep them open so other people can easily make their own changes - for example if you were publishing the source to a text adventure and didn't want any descriptive text to appear which would constitute a spoiler, then use something reversible like rot13.

In fact, you could rot13 all your translation files and flip them back on the fly.

That's keeping the open spirit. Random "magic" hashes isn't really programmer-friendly.

$\endgroup$
1
  • 4
    $\begingroup$ Remember that many GeoCaching folks amongst us read rot13 almost as fluently as the original. $\endgroup$
    – yo'
    Commented Oct 6, 2014 at 12:43
4
$\begingroup$

Open source requires the source code to be made public and available, not the game data. So you could easily put the data in another file and not publish that one. Add some crypto if you want to prevent casual reading of the file. I doubt a strong crypto is necessary for your application.

$\endgroup$
4
  • 1
    $\begingroup$ In what sense can you "not publish" the game data? The game has to be able to access that data so anyone who has a copy of the game has a copy of the data. That's pretty much exactly what publishing is: making public. $\endgroup$ Commented Oct 6, 2014 at 10:56
  • 1
    $\begingroup$ @DavidRicherby Depends on what you want to publish and to waht end. That game or your engine that could be used to create many similar games? Allow people to manipulate your game, inspect the code for security holes ore just re-use components? If your interface is as simple as "CSV with q&a + program = game" I think it's conceivable to publish only the program, not the CSV. $\endgroup$
    – Raphael
    Commented Oct 6, 2014 at 11:16
  • 1
    $\begingroup$ @Raphael But distributing a game that consists of an executable and a plain text data file doesn't achieve the goal of making the answers secret. If you want to propose an encrypted version of the datafile, that's fine, as long as everyone understands that this is just security by obscurity (the key is in the source). But then we get into the question of whether the plaintext of the datafile constitutes source code in the sense of the GPL and, at that point, the question becomes a matter of interpretation of the GPL, rather than computer science. $\endgroup$ Commented Oct 6, 2014 at 12:10
  • $\begingroup$ @DavidRicherby: Agreed. Still, although IANAL, I very much doubt that a data file consisting of riddles and their answers would be considered such an essential and irreplaceable part of the program that it could not be licensed separately -- especially if you included an unencrypted sample data file in the source distribution, along with instructions for modifying and encrypting it if necessary, to make it clear that anyone with the source code can indeed create their own customized data files and use them with the program. $\endgroup$ Commented Oct 6, 2014 at 14:35
4
$\begingroup$

Why would you store your answers in your GPL source code if you don't want your users to know them? Even if they're not known or easily crackable now, they can (and likely will) be in the future.

Instead of storing them in your app, use an external database. Make a small web service that compares the answers to what's in your database. Then let your application make a call to that webservice whenever it has to verify. The main problem is that, because it requires internet access, you will lose some speed and potential userbase. your app license should only apply for the app itself, not the webservice.

You could also just put your answers in a small database and put that in your program. As far as I know, GPL only applies to source code, not any data that your app stores. I might be wrong on that, though.

$\endgroup$
1
  • 1
    $\begingroup$ "As far as I know, GPL only applies to source code, not any data that your app stores". Well, the GPL says "You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy." So you might think we now need to decide whether the data is part of the "entire work". But actually, surely all the GPL's restrictions (including that one) only apply to licensees. It is nice for licensors to keep to the spirit of the GPL too, but they shouldn't need to worry about a visit from the copyright police. $\endgroup$
    – Peter Ford
    Commented Jan 31, 2015 at 23:31
1
$\begingroup$

Remember that even if you store a database in a remote web server, the database can still be duplicated by simply writing down all correct key/value pairs that have been seen. And generally speaking, mobile apps should try to not give errors or cease to function because the network is down (use queued messaging, and "update when you can").

So if you want a local database, but don't like the idea of it getting blatantly decrypted, you can use a bloom filter (to avoid talking to a network or having a big decrypted database locally). This is how spell checkers used to work when memory space was really tight.

So, if you add question/answer pairs into the filter like:

Hash(NormalizeString(Question[n]))+Hash(NormalizeString(Answer[n]))

If you ask if "Capitol of Virginia?Richmond" is in the set, it will either answer "definitely no", or "almost certainly yes". If you get too many false positives, then make the database larger.

You could have an immense database in a tiny space, assuming that the user will spell the Question and Answer exactly as you expect. Keeping the database small helps with updates, because they probably have to be transferred over wireless networks.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.