Daniel Foo
Daniel Foo

Reputation: 73

How can convert android PublicKey to string and back?

I am trying to create an app which will encrypt user messages. The user Public Key needs to be published to server as a string. I am generating Android KyeStore PublicKey like this:

    public static PublicKey getOrCreatePublicKey(String alias) throws GeneralSecurityException, IOException {

    KeyStore keyStore = KeyStore.getInstance(ANDROID_PROVIDER);
    keyStore.load(null);
    if (!keyStore.containsAlias(alias) || keyStore.getCertificate(alias) == null) {

        KeyGenParameterSpec spec = new KeyGenParameterSpec.Builder(
                alias,
                KeyProperties.PURPOSE_DECRYPT | KeyProperties.PURPOSE_ENCRYPT)
                .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_OAEP)
                .setDigests(KeyProperties.DIGEST_SHA256,
                        KeyProperties.DIGEST_SHA512)
                .build();
        KeyPairGenerator generator = KeyPairGenerator.getInstance(KeyProperties.KEY_ALGORITHM_RSA, ANDROID_PROVIDER);
        generator.initialize(spec);
        generator.generateKeyPair();
    }
    return keyStore.getCertificate(alias).getPublicKey();
}

Then I try to convert the PublicKey to string and back to PublicKey like this:

public static PublicKey stringToPublicKey(String publStr)  {

    PublicKey publicKey = null;
    try {
        byte[] data = Base64.decode(publStr, Base64.DEFAULT);
        X509EncodedKeySpec spec = new X509EncodedKeySpec(data);
        KeyFactory fact = KeyFactory.getInstance("RSA");
        publicKey = fact.generatePublic(spec);
    } catch (GeneralSecurityException e) {
        e.printStackTrace();
    }
    return publicKey;
}


public static String publicKeyToString(PublicKey publ) {
    String publicKeyString = null;
    try {
        KeyFactory fact = KeyFactory.getInstance("RSA");
        X509EncodedKeySpec spec = fact.getKeySpec(publ,
                X509EncodedKeySpec.class);
        publicKeyString = Base64.encodeToString(spec.getEncoded(), Base64.DEFAULT);
    } catch (GeneralSecurityException e) {
        e.printStackTrace();
    }
    return publicKeyString;
}

Then I try to encrypt and decrypt user messages with the Public and Private keys.

If I don't convert Public Key the encryption works fine. But if I convert Public Key to string and back to Public Key the encryption doesn't work anymore. What am I doing wrong? Thank you.

   PublicKey publicKey1 = getOrCreatePublicKey("alias");
        String publicKeyStr = publicKeyToString(publicKey1);
        PublicKey publicKey2 = stringToPublicKey(publicKeyStr);

    //this one works            
        String message = encrypt(str, publicKey1);
        String decryptm = decrypt(message, privateKey);

    //this one doesn't work
    String message = encrypt(str, publicKey2);
        String decryptm = decrypt(message, privateKey);

Upvotes: 4

Views: 3422

Answers (2)

Adam Winter
Adam Winter

Reputation: 1914

Your publicKeyToString function is going around the very long way. It's not supposed to be all the steps from stringToPublicKey done again in "reverse". I mean, you don't have to construct an object, you already have the public key as the object. Getting PublicKey to String is basically just one line.

public static String publicKeyToString(PublicKey publ) {
    String publicKeyString = Base64.encodeToString(publ.getEncoded(), 2);
    return publicKeyString;
}

That should output a String that works with your stringToPublicKey function (which looks right to me as it is).

Upvotes: 2

Daniel Foo
Daniel Foo

Reputation: 73

I have replaced

KeyProperties.ENCRYPTION_PADDING_RSA_OAEP with KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1.

I have also replaced

Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding");

with

Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");

And now it works. But I still don't know why it was not working first time.

Upvotes: 1

Related Questions