Question

I tried searching for information on this, but must not know the right terms to use...

What would be the simplest way to store information in a human-readable and -writeable passcode, with enough padding to make randomly guessed codes unlikely to be valid? Not unlike 8-bit console games' password-save systems.

In my particular case, I'd like to be able to encode three unsigned integers (with a maximum length of probably about 20 bits each) into a passcode under Java 1.4.2, and decrypt them on a web server. I was thinking about also adding a random or date-based value in an attempt to make passcodes unique.

The code could use numbers, mixed-case letters and potentially some simple symbols, but should probably exclude easily-confused characters like 1lI and O0. Since the user needs to type it, obviously shorter is better.

Thanks!

Was it helpful?

Solution

  1. Choose the alphabet that you want to use. It can have as many symbols as you like, in any order. An example alphabet would be ABCDEFGHJKLMNPQRSTUVWXYZ0123456789 which contains 34 symbols.
  2. Encode the data you want to save as a single integer by using bitshifts and bitwise or, or multiplication and addition. This shouldn't be a problem if you have about 20 bits of data as you say.
  3. Encode the integer from step 1 in base-N, where N is the number of symbols in your alphabet, then print it using symbols from the alphabet.
  4. Add a "check digit" on the end. Adding all of the output digits mod N is a simple and useful system. A check digit isn't real crypto and won't stop anyone who's putting any effort into forging a save code, but it limits the chances of a randomly chosen code working. If your alphabet has 34 symbols then there's only a 1-in-34 chance of the check digit matching on a random code.
  5. To decode, first validate the check digit in the received code, then decode the base-N representation (reverse step 3), then extract the individual values from the integer value (reverse step 2).

The number of symbols needed to represent k bits of data in base n plus one check digit is ceil(k * log(2) / log(n)) + 1, which is only 5 for k=20 bits and n=34.

OTHER TIPS

You can encode your properties as Base64. The only restriction is that you must have a fixed size of your properties. You may want to apply MD5 algorithm or similar to the encoded string.

Take a look at this snipplet using apache commons codec for java 1.4

public class Base64Encoder {

/**
 * Base64 game properties encoded
 * @param properties list of properties as Strings
 * @return base64 encoded properties
 */
public String encodeProperties(List properties){
    StringBuffer buffer = new StringBuffer();
    Iterator iter = properties.iterator();
    while(iter.hasNext()){
        buffer.append(iter.next().toString());
    }
    return Base64.encodeBase64String(buffer.toString().getBytes());
}

/**
 * Decodes a based64 properties
 * @param propertiesSize list of Integer with each property size
 * @param encodedProperties base64 encoded properties
 * @return List of properties as String
 */
public List decodeProperties(List propertiesSize, String encodedProperties){
    List decodedProperties = new ArrayList();
    Iterator iter = propertiesSize.iterator();
    String decoded = new String(Base64.decodeBase64(encodedProperties.getBytes()));
    int current = 0;
    while(iter.hasNext()){
        Integer propertySize = new Integer(iter.next().toString());
        String property = decoded.substring(current, current + propertySize.intValue());
        decodedProperties.add(property);
        current += propertySize.intValue();
    }
    return decodedProperties;
}

public static void main(String[] args){
    String points = "1450";
    String level = "12";
    String lifes = "2";
    Base64Encoder encoder = new Base64Encoder();
    List properties = new ArrayList();
    properties.add(points);
    properties.add(level);
    properties.add(lifes);
    String encodedProperties = encoder.encodeProperties(properties); //MTQ1MDEyMg==
    System.out.println(encodedProperties);
    List propertiesSize =  new ArrayList();
    propertiesSize.add(Integer.valueOf(points.length()));
    propertiesSize.add(Integer.valueOf(level.length()));
    propertiesSize.add(Integer.valueOf(lifes.length()));
    System.out.println(encoder.decodeProperties(propertiesSize, encodedProperties)); //[1450, 12, 2]
}

}

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top