views:

333

answers:

2

I want to develop a Key generator for my phone applications. Currently I am using an external service to do the job but I am a little concerned that the service might go offline one day hence I will be in a bit of a pickle.

How authentication works now.

  1. Public key stored on the phone.
  2. When the user requests a key the 'phone ID' is sent to the "Key Generation Service" and the encrypted key key is returned and stored inside a license file.
  3. On the phone I can check if the key is for the current phone by using a method getPhoneId() which I can check with the the current phone and grant or not grant access to features.

I like this and it works well, however, I want to create my own "Key Generation Service" from my own website.

Requirements:

  1. Public and Private Key
  2. Encryption:(Bouncy Castle)
  3. Written in JAVA
  4. Must support getApplicationId() (so that many applications can use the same key generator) and getPhoneId() (to get the phone id out of the encrypted license file)
  5. I want to be able to send the ApplicationId and PhoneId to the service for license key generation.

Can someone give me some pointers on how to accomplish this? I have dabbled around with some java encryption but am definitely no expert and can't find anything that will help me.

A list of the Java classes I would need to instantiate would be helpful.

+1  A: 

Interesting question which made me experiment a little bit with it. But as you might already have guessed, I haven't done this before. But maybe somebody else can confirm my thoughts - or rebut them but please without downvoting ;)

I'd use an asymmetric algorithm such as RSA to sign a string that consists of all the data that has to match in order to be valid. This signature is stored along with the public key in order to verify it without the need to access the server.

Expressed as Java code, this would look like this (based on Signature Sign and Verify):

import java.security.*;

public class Main {
  public static void main(String args[]) throws Exception {
    Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());

    // our server, imagine it's a webservice
    KeyServer server = new KeyServer(42);

    // init client with a copy of public key from server
    KeyClient client = new KeyClient(server.getPublicKey());

    // create string that identifies phone and application
    byte[] data = (getPhoneId() + ":" + getApplicationId()).getBytes("utf-8");

    // send data to server for signature creation
    byte[] digitalSignature = server.signData(data);

    // verify on client side
    System.out.println("verified = " + client.verifySig(data, digitalSignature));

    // bad data
    byte[] wrongData = ("anotherPhoneId" + ":" + getApplicationId()).getBytes("utf-8");
    System.out.println("verified = " + client.verifySig(wrongData, digitalSignature));

    // bad signature
    digitalSignature[5] = (byte) 0xff;
    System.out.println("verified = " + client.verifySig(data, digitalSignature));
  }

  private static String getPhoneId() {
    return "somephone";
  }

  private static String getApplicationId() {
    return "someapp";
  }

  public static class KeyClient {

    private PublicKey _publicKey;
    private Signature _signer;

    public KeyClient(PublicKey publicKey) {
      if (publicKey == null) {
        throw new NullPointerException("publicKey");
      }
      _publicKey = publicKey;

      try {
        _signer = Signature.getInstance("SHA1withRSA");
      } catch (NoSuchAlgorithmException e) {
        throw new RuntimeException("failed to get Signature", e);
      }
    }

    public boolean verifySig(byte[] data, byte[] sig) throws Exception {
      synchronized (_signer) {
        _signer.initVerify(_publicKey);
        _signer.update(data);
        return (_signer.verify(sig));
      }
    }
  }

  public static class KeyServer {

    private KeyPair _keyPair;
    private Signature _signer;

    public KeyServer(int seed) {
      try {
        _keyPair = generateKeyPair(seed);
      } catch (Exception e) {
        throw new RuntimeException("failed to generate key pair for seed " + seed, e);
      }

      try {
        _signer = Signature.getInstance("SHA1withRSA");
      } catch (NoSuchAlgorithmException e) {
        throw new RuntimeException("failed to get Signature", e);
      }
    }

    public PublicKey getPublicKey() {
      return _keyPair.getPublic();
    }

    public byte[] signData(byte[] data) throws InvalidKeyException, SignatureException {
      synchronized (_signer) {
        _signer.initSign(_keyPair.getPrivate());
        _signer.update(data);
        return (_signer.sign());
      }
    }

    private KeyPair generateKeyPair(long seed) throws Exception {
      KeyPairGenerator keyGenerator = KeyPairGenerator.getInstance("RSA");
      SecureRandom rng = SecureRandom.getInstance("SHA1PRNG", "SUN");
      rng.setSeed(seed);
      keyGenerator.initialize(2048, rng);
      return (keyGenerator.generateKeyPair());
    }

  }
}
sfussenegger
A: 

The problem is, that although there are algorithms which are strong enough, the problem is how do you use them, because if you combine those algorithms in a wrong fashion or use bad seeds for some algorithms, weak keys (e.g. w.r.t. their length) you will end up with something which is unsecure. So the experience says, it is better, to not try implementing it yourself and risking errors until you are confident enough with cryptology theory.

However the other answer seems to give a good example.

Gabriel Ščerbák