Reputation: 73
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
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
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