8

I am confused by this bit of advice from http://developer.android.com/guide/google/play/billing/billing_integrate.html#billing-signatures

To keep your public key safe from malicious users and hackers, do not embed your public key as an entire literal string. Instead, construct the string at runtime from pieces or use bit manipulation (for example, XOR with some other string) to hide the actual key. The key itself is not secret information, but you do not want to make it easy for a hacker or malicious user to replace the public key with another key.

Does this mean that

String one = "thisIs";
String two = "MyKey";
String base64EncodedPublicKey = one + two;
PublicKey key = Security.generatePublicKey(base64EncodedPublicKey);
verified = Security.verify(key, signedData, signature);

is safer than

String base64EncodedPublicKey = "thisIsMyKey";
PublicKey key = Security.generatePublicKey(base64EncodedPublicKey);
verified = Security.verify(key, signedData, signature);

? If not, could you please give me an example in code of how to do this?

Kalina
  • 5,244
  • 16
  • 59
  • 98

2 Answers2

4

Something that involves some serious change of the key is best. Personally, I prefer using encryption, something like this would work. For the key, string together a few parts, and it should help to getting it together. Use encryptKey to get your key encrypted, then delete the real key from the source code, and you should be fairly secure. Better is to somehow get the key from a secure server, but that isn't always an option.

String encryptKey(String input)
{
    byte[] inBytes=input.getBytes();
    String finalString=null;
    try {
        Cipher cipher=Cipher.getInstance("AES/CBC/PKCS5Padding");
        MessageDigest md = MessageDigest.getInstance("SHA-1");
        byte[] keyBytes=md.digest((KeyPart1+KeyPart2).getBytes());
        keyBytes = Arrays.copyOf(keyBytes, 16);
        SecretKey key= new SecretKeySpec(keyBytes,"AES");
        IvParameterSpec ivSpec = new IvParameterSpec(new byte[] {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0});
        cipher.init(Cipher.ENCRYPT_MODE,key,ivSpec);
        byte[] outBytes = new byte[cipher.getOutputSize(inBytes.length)];
        //cipher.update(encrypted, 0, encrypted.length, decrypted, 0);
        outBytes=cipher.doFinal(inBytes);
        finalString=new String(Base64.encode(outBytes,0));
        Log.v(TAG,"Encrypted="+finalString);

    } catch (NoSuchAlgorithmException e) {
        Log.e(TAG,"No Such Algorithm",e);
    } catch (NoSuchPaddingException e) {
        Log.e(TAG,"No Such Padding",e);
    } catch (InvalidKeyException e) {
        Log.e(TAG,"Invalid Key",e);
    } catch (InvalidAlgorithmParameterException e) {
        Log.e(TAG,"Invalid Algorithm Parameter",e);
    } catch (IllegalBlockSizeException e) {
    } catch (BadPaddingException e) {}
    return finalString;
}

String decryptKey(String base64Text)
{
    byte[] encrypted=Base64.decode(base64Text,0);
    //encrypted=base64Text.getBytes();
    String decryptedString=null;
    try {
        Cipher cipher=Cipher.getInstance("AES/CBC/PKCS5Padding");
        MessageDigest md = MessageDigest.getInstance("SHA-1");
        byte[] keyBytes=md.digest((KeyPart1+KeyPart2).getBytes());
        keyBytes = Arrays.copyOf(keyBytes, 16);
        SecretKey key= new SecretKeySpec(keyBytes,"AES");
        IvParameterSpec ivSpec = new IvParameterSpec(new byte[] {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0});
        cipher.init(Cipher.DECRYPT_MODE,key,ivSpec);
        byte[] decrypted = new byte[cipher.getOutputSize(encrypted.length)];
        //cipher.update(encrypted, 0, encrypted.length, decrypted, 0);
        decrypted=cipher.doFinal(encrypted);
        decryptedString=new String(decrypted);
    } catch (NoSuchAlgorithmException e) {
        logStackTrace(e);
    } catch (NoSuchPaddingException e) {
        logStackTrace(e);
    } catch (InvalidKeyException e) {
        logStackTrace(e);
    } catch (InvalidAlgorithmParameterException e) {
        logStackTrace(e);
    } catch (IllegalBlockSizeException e) {
        logStackTrace(e);
    } catch (BadPaddingException e) {
        logStackTrace(e);
    }
    return decryptedString;
}
PearsonArtPhoto
  • 35,989
  • 16
  • 107
  • 136
3

Yes. Although in this case you're just concatenating strings which is not much better. The reason for this is that somebody could easily disassemble your code and access your public key. If you have to reassemble the key, it makes it much more challenging to grab the key out of the disassembled code.

Chris Thompson
  • 33,380
  • 11
  • 76
  • 105