I have public key sent to me. I want to use it in encryption. But key is in .pub format. So its just a plain text, not a certificate. How do I convert this public key to an object like PublicKey key = ....;
In file I see: -----BEGIN PUBLIC KEY-----
MIIBIjANB.........
HwIDAQAB
-----END PUBLIC KEY----- Later I want to use this code:
enter code here
Private static byte[] encrypt(String text, PublicKey key) {
byte[] cipherText = null;
try {
final Cipher cipher = Cipher.getInstance("RSA/None/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, key);
cipherText = cipher.doFinal(text.getBytes());
} catch (Exception e) {
e.printStackTrace();
}
return cipherText;
}
Please someone tell me how to use .pub file to have a public key in program code.
Related
I'm trying to decrypt data that is encrypted with AES/SIC/PKCS7Padding. I'm making use of BouncyCastleProvider to achieve this, but on decryption BadPaddingException is thrown.
Here's the code i'm using to decrypt, am i doing something wrong? Any help is appreciated, thanks!
public class AesEncryption {
public static String decrypt(String aesKey, String cipherText) {
try {
Security.addProvider(new BouncyCastleProvider());
Cipher dcipher;
SecretKey key = new SecretKeySpec(Base64.getDecoder().decode(aesKey), "AES");
dcipher = Cipher.getInstance("AES/SIC/PKCS7Padding", "BC");
dcipher.init(Cipher.DECRYPT_MODE, key, generateIv());
byte[] dec = Base64.getDecoder().decode(cipherText);
byte[] utf8 = dcipher.doFinal(dec);
return new String(utf8, "UTF-8");
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public static IvParameterSpec generateIv() {
byte[] iv = new byte[16];
new SecureRandom().nextBytes(iv);
return new IvParameterSpec(iv);
}
}
With the code below I can easily encrypt a file and decrypt it, using the password that the user enters. I am now imploding the use of the fingerprint to enter my app. When the fingerprint is correct, I want to decrypt the file. But how do I do if the user has not entered the password? is there a relatively safe way to do this? Thanks
public class CryptoUtils {
private static final String ALGORITHM = "AES";
private static final String ENCRYPTION_IV = "4e5Wa71fYoT7MFEX";
private static String ENCRYPTION_KEY = "";
public static void encrypt(String key, File inputFile, File outputFile)
throws CryptoException {
doCrypto(Cipher.ENCRYPT_MODE, key, inputFile, outputFile);
}
public static void decrypt(String key, File inputFile, File outputFile)
throws CryptoException {
doCrypto(Cipher.DECRYPT_MODE, key, inputFile, outputFile);
}
private static void doCrypto(int cipherMode, String key, File inputFile, File outputFile)
throws CryptoException {
try {
ENCRYPTION_KEY = key;
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(cipherMode, makeKey(), makeIv());
FileInputStream inputStream = new FileInputStream(inputFile);
byte[] inputBytes = new byte[(int) inputFile.length()];
inputStream.read(inputBytes);
byte[] outputBytes = cipher.doFinal(inputBytes);
FileOutputStream outputStream = new FileOutputStream(outputFile);
outputStream.write(outputBytes);
inputStream.close();
outputStream.close();
//Log.d("cur__", "Encryption/Decryption Completed Succesfully");
} catch (NoSuchPaddingException | NoSuchAlgorithmException | InvalidKeyException | BadPaddingException | IllegalBlockSizeException | IOException ex) {
throw new CryptoException("Error encrypting/decrypting file " + ex.getMessage(), ex);
} catch (InvalidAlgorithmParameterException ex) {
Logger.getLogger(CryptoUtils.class.getName()).log(Level.SEVERE, null, ex);
}
}
private static AlgorithmParameterSpec makeIv() {
return new IvParameterSpec(ENCRYPTION_IV.getBytes(StandardCharsets.UTF_8));
}
private static Key makeKey() {
try {
MessageDigest md = MessageDigest.getInstance("SHA-256");
byte[] key = md.digest(ENCRYPTION_KEY.getBytes(StandardCharsets.UTF_8));
//Log.d("Lenghtis", new SecretKeySpec(key, ALGORITHM).getEncoded().length + "");
return new SecretKeySpec(key, ALGORITHM);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return null;
}
}
You first need to generate a Key. You can use the following function
fun generateKey(storeKey: StoreKey): SecretKey {
val keyGenerator =
KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, "MyKeyStore")
val keyGenParameterSpec = KeyGenParameterSpec.Builder(storeKey.Alias,
KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT)
.setBlockModes(KeyProperties.BLOCK_MODE_CBC)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7)
.setUserAuthenticationRequired(true)
.setRandomizedEncryptionRequired(false)
.build()
keyGenerator.init(keyGenParameterSpec)
return keyGenerator.generateKey()
}
You need setUserAuthenticationRequired(true) for biometric authentication.
Then you can provide this key to your biometric authenticator to authenticate the user and in return you will receive cipher from it.
Then you can use that cipher (encrypt cipher OR decrypt cipher) to perform encrypt/decrypt data directly using this cipher.
androidx.biometric:biometric:1.0.0-beta01
like this
val biometricCallbacks = object : BiometricPrompt.AuthenticationCallback() {
override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) {
super.onAuthenticationSucceeded(result)
result.cryptoObject?.cipher?.let { cipher ->
val encryptedData = cipherUtils.encryptAES(dataToEncrypt, cipher)
dismiss()
}
}
override fun onAuthenticationError(errorCode: Int, errString: CharSequence) {
super.onAuthenticationError(errorCode, errString)
if (errorCode == BiometricPrompt.ERROR_CANCELED || errorCode == BiometricPrompt.ERROR_USER_CANCELED) {
dismiss()
}
}
override fun onAuthenticationFailed() {
super.onAuthenticationFailed()
Log.e("BIOMETRIC", "FAILED")
}
}
val biometricPrompt = BiometricPrompt(this, biometricExecutor, biometricCallbacks)
val biometricPromptInfo = BiometricPrompt.PromptInfo.Builder()
.setTitle("APP")
.setSubtitle("Enable Biometric for Encryption")
.setDescription("")
.setNegativeButtonText("Cancel")
.build()
biometricPrompt.authenticate(
biometricPromptInfo,
BiometricPrompt.CryptoObject(
cipherUtils.getBioEncryptCipher(keyStoreUtils.generateNewKey(StoreKey.Pass, true))
)
)
You can encrypt users password and keep it securely in database somewhere and use the biometric authentication. Since the key you are generating is strictly bind to users biometrics, users encrypted password will not get compromised.
Here's the androidx.biometric demo app for using biometric-bound keys (key can only be unlocked by strong biometric sensors).
Basically
Generate a key that's only usable after being authenticated via biometrics, with the associated capabilities you'd like the key to be able to perform (encrypt, decrypt, etc)
Wrap the cryptographic operation you wish to perform in a CryptoObject. The key will only become usable after a user has authenticated with biometrics
Invoke BiometricPrompt#authenticate(CryptoObject)
Use the key after onAuthenticationSucceeded
For completeness, there's also authentication-bound keys (key can be unlocked by biometrics OR device credential), which become available for use by your app whenever the user has authenticated within t seconds, where t is specified in KeyGenParameterSpec.Builder#setUserAuthenticationValidityDurationSeconds. You can see an example usage here.
So I'm using a simple Blowfish encryption/decryption for an application I'm making. It works sometimes but isn't reliable.
Form template being encrypted:
email#gmail.com
message
END
It works perfectly when I use an email like test1#gmail.com or test2#gmail.com.
When I use my personal email: tywemc#gmail.com, the form is encrypted but when it's decrypted, it returns î/ÅÝ®Îmail.comÄþ4œ’>L/ND
So it seems like it decrypts part of the form but not the whole thing and I can't figure out why. It seems to decrypts other forms partially with different real emails but still not completely. I'm using a static key within the Crypto.java class for simplicity.
I've tried to make sure the longer emails were causing it to not work because of a block size or string length issue but I don't think that's the problem.
Crypto.java
package core;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
public class Crypto {
private static String key = "key12345";
public static String encrypt(String strClearText,String strKey) {
String strData = "";
try {
SecretKeySpec skeyspec = new SecretKeySpec(key.getBytes(), "Blowfish");
System.out.println("Ëncryption keyspec: " + skeyspec.toString());
Cipher cipher = Cipher.getInstance("Blowfish");
cipher.init(Cipher.ENCRYPT_MODE, skeyspec);
byte[] encrypted = cipher.doFinal(strClearText.getBytes());
strData = new String(encrypted);
} catch (Exception e) {
e.printStackTrace();
}
return strData;
}
public static String decrypt(String strEncrypted,String strKey) {
String strData = "";
try {
SecretKeySpec skeyspec = new SecretKeySpec(key.getBytes(),"Blowfish");
System.out.println("Decryption keyspec: " + skeyspec.toString());
Cipher cipher = Cipher.getInstance("Blowfish");
cipher.init(Cipher.DECRYPT_MODE, skeyspec);
byte[] decrypted = cipher.doFinal(strEncrypted.getBytes());
strData = new String(decrypted);
} catch (Exception e) {
e.printStackTrace();
}
return strData;
}
}
Should I use a different encryption type/method or is there something I'm doing wrong? Thanks in advance!
Updated Code:
package core;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
public class Crypto {
private static String key = "key12345";
public static byte[] encrypt(String strClearText, String strKey) {
byte[] encrypted = null;
try {
SecretKeySpec skeyspec = new SecretKeySpec(key.getBytes(), "Blowfish");
System.out.println("Ëncryption keyspec: " + skeyspec.toString());
Cipher cipher = Cipher.getInstance("Blowfish");
cipher.init(Cipher.ENCRYPT_MODE, skeyspec);
encrypted = cipher.doFinal(strClearText.getBytes());
// strData = new String(encrypted);
} catch (Exception e) {
e.printStackTrace();
}
return encrypted;
}
public static String decrypt(byte[] strEncrypted, String strKey) {
String strData = "";
try {
SecretKeySpec skeyspec = new SecretKeySpec(key.getBytes(),"Blowfish");
System.out.println("Decryption keyspec: " + skeyspec.toString());
Cipher cipher = Cipher.getInstance("Blowfish");
cipher.init(Cipher.DECRYPT_MODE, skeyspec);
byte[] decrypted = cipher.doFinal(strEncrypted);
strData = new String(decrypted);
} catch (Exception e) {
e.printStackTrace();
}
return strData;
}
}
[B#164b077d is what is passed in as strEncrypted.
Error
javax.crypto.IllegalBlockSizeException: Input length must be multiple of 8 when decrypting with padded cipher
I have been given an RSA public Key and an RSA private key with OAEP SHA-256 padding. I am attempting to simply encrypt a random string and then decrypt it to assert the result is equalt to the original.
This is the public key i have been given:
-----BEGIN RSA PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAq8tiBtDmkeS/ruY3rrkq
dz6Lc6XWFRbI/GjPtIokrtpM+Ujyv6wX8TBqY8e03gzh+eE7VUyEVPapDnceAqgJ
ZQah2h+N5AEQKqNDM4/1to1V0F+m1ISR7CIUU8dvU+bPk67DU5VkEtLxf+mW8/es
hy0u6oSB04WCDPNnh+9GDF7tN7lOzBH1FxKPWIb5Gqg6GoXS+KgvQhYEk0TajIBk
+mefzTv1D4HJlhFYybgY+/p3k4P2kM5HnbEtoVpz/PL9+94YVp5RBHTQHmk/3SAX
RkPP34IjY6LZqTJGWQGxc64Qci54ZJsq4wSTXvfdHgUWz7eX+v1jA+GLjFExNcYZ
nQIDAQAB
-----END RSA PUBLIC KEY-----
This is the private key I have been given:
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDAUQiHdHuMBCnF
P/7RQoRWrp62dGWQLDLP9l+3KUMlSPheN2R5jHDZ/WEGJGF2WYKxaQvv5XCocdnt
uxVZTNM1PVyduokJaJzrSIj+jGWDd4hTWvVoS3vhds8u6W0jD3M4ayrF6c7NYuHc
tE5YLLIgK1DTn+ZZCr3VGbScISDJ/WPx3+1YTNQDvm+T7MfjhetJqqzWIsunMUiw
nQOQvkdjCVWpk+L10SaMrezixtIS5wfpOTjGIZ0w5VunvtsPxg1TkuvGURa9S3rS
7D3uhDPY+V8UDMpBPso3j7TGD5axlBJcpavWeF8qde3sWztmqUFQ3JDypZWGSAe2
d8e4mY65AgMBAAECggEAal8nwYxbHZnb5L892U7aVfuly7Nbzb+0pzRVwsBu5DuV
LL+kslpMvTYZqUUMJ2LhF/HLaXhVtMWsTYLSDx+gHu1+wbtAOtUDHlxzcaAEMhA2
dix0WqiNr6qAdCkmdWMBTu5vrSJigVW1KdcNElY+e+6ZeUQTK6L2Vt0t+cGVGkM4
K5PdHcGLR1BiAf3k4BguHE4TGGnqN9dF5Rn9nPP6C7QihWzGn15efD2dAXn3Kbho
dMIRgyYiO7uXPm2LrIjtldYb8tPus+V9SWT4hcgnJZrtd9atkqZrJ3dhQf9ZetGs
UwTCzHJ169NNbVyrjCbcy4Uht8Na+t/94Im9hI8n0QKBgQDO6tYnwh1hPg3E+4DY
xCiDAp7v3afJIvC9a1sBtif8KkzZTYH31ww+PRcfDPQUlk/MIDie0u6xIawnBYkC
oN1u9erojcvQbBP0GFylP5hNxYZbI7gPA/7AiGRxyezZPOiVMwdd5fCM7Wv4kucr
c1JCcvtPoDQcFFZOfI+wqqdWnQKBgQDt745Pvckt7/XL7wbfv4BV+cwpLNjc4/3k
ajOLtasgpT8mc0gUH2ejHhpkuhjSUpSTrlFB8EN1kAwmBYy0GOoO9967hm6twmqk
Q5L3OHJ96pYkf1rbyXNE1N7inh5Z3M1H5ONIaliAYLHXOzKsZvI5eUdKAJdSqFLo
uvVCwr4PzQKBgG6W3rzDJ9a4Rr24OgYg2RIkTXQgALQko4xpm2tPwxEoPoiJv2QK
ILYHCpuC3dU+/Qk5U2m3jPFI8OyuLask9RSABPwkBQGxMfztJF8BnVI7tvJxJceI
uBiJDT4v0RHOVvSfIFnUMnvvzRw+z6TObvGq6JyHIDK9v98U/etLWkKVAoGAIIxF
lmjqzUrm/8ep1A+5OYmbQQKug8D4aTeR54mpaCTSt6rLcF0/axPiHmdKn/LF+lG9
MdzxDXLwBn952OUTl4qWwGZKW6Cdv+yyfPkOyGS/tyxovGoZR5ArESr6Eebfefc4
lB5gDuerTDr/2o+WkQAjHV9pU9hMxyNUC5biMv0CgYEAiDlw8lBf3cQs6FxNXs9t
whWpfL0yY7WAONvhfFB0Dpsz52gGDCYRvJekGRz6jOlKDuXJ+Mm1AX4BaufMETI5
QseZxtVPIn+BXm0A1x8w/DifmE1JqQZmPCQPOh3eLx5nSn9LKGIbMgd17mfH3HhU
8WX2mzWjmRA3C/CzdGfCKSk=
-----END PRIVATE KEY-----
I am reading this key from a pem file "crypt_pkcs8.pem" but recive the public key as a byte array from a gRPC call.
Here is my Java code:
public class Encryption{
public static void main(String args){
ByteString publicKey = client.getPublicKey(nonce).getRSAEncryptionKey();
String strKeyPEM = "";
BufferedReader br = new BufferedReader(new FileReader("crypt_pkcs8.pem"));
String line;
while ((line = br.readLine()) != null) {
strKeyPEM += line+"\n";
}
br.close();
byte[] pt;
try {
pt = "h".getBytes("UTF-8");
byte[] ct =encrypt(publicKey, pt);
byte[] response= decrypt(strKeyPEM, ct);
assertEquals(pt, response);
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static byte[] encrypt(ByteString rawKey ,byte[] message){
String strippedKey=stripKey(rawKey.toStringUtf8());
byte[] keyBytes = Base64.getDecoder().decode(strippedKey);
System.out.println(keyBytes.length);
Cipher cipher_RSA;
try {
cipher_RSA = Cipher.getInstance("RSA/ECB/OAEPWITHSHA-256ANDMGF1PADDING");
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes);
PublicKey pk = keyFactory.generatePublic(spec);
System.out.println(pk.getAlgorithm()+" format : "+pk.getFormat());
cipher_RSA.init(Cipher.ENCRYPT_MODE, pk);
return cipher_RSA.doFinal(message);
} catch (NoSuchAlgorithmException | NoSuchPaddingException | IllegalBlockSizeException |
BadPaddingException | InvalidKeyException | InvalidKeySpecException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return null;
}
}
public static byte[] decrypt(String rawKey ,byte[] message){
String strippedKey=stripPrivateKey(rawKey);
byte[] keyBytes = Base64.getDecoder().decode(strippedKey);
System.out.println(keyBytes.length);
Cipher cipher_RSA;
try {
cipher_RSA = Cipher.getInstance("RSA/ECB/OAEPWITHSHA-256ANDMGF1PADDING");
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes);
PrivateKey pk = keyFactory.generatePrivate(spec);
System.out.println(pk.getAlgorithm()+" format : "+pk.getFormat());
cipher_RSA.init(Cipher.DECRYPT_MODE, pk);
return cipher_RSA.doFinal(message);
} catch (NoSuchAlgorithmException | NoSuchPaddingException | IllegalBlockSizeException |
BadPaddingException | InvalidKeyException | InvalidKeySpecException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return null;
}
}
public static String stripKey(String key){
key = key.replace("-----BEGIN RSA PUBLIC KEY-----\n", "");
key = key.replace("-----END RSA PUBLIC KEY-----", "");
key = key.replace("\n", "");
return key;
}
public static String stripPrivateKey(String key){
key = key.replace("-----BEGIN PRIVATE KEY-----", "");
key = key.replace("-----END PRIVATE KEY-----", "");
key = key.replace("\n", "");
return key;
}
}
I cannot find anything obviously wrong with my actaul code so I believe this is to do with the keys not matching.
I also notice the header/footer is different on the public key and private key. From looking online this is because the public key is in PKCS#8 format.
Will I need to change the public key to pkcs#8 format as well? If so what is the easiest way to do this?
I have also been told I should be able to extract the public key (in pkcs8 format) from the private key given above. Can this be done easily?
If you can get a valid public key then the key is not in PKCS#8 format, it will be in X.509 (SubjectPublicKeyInfo) format as Java expects. However, your public and private keys do indeed not match. You can use the answer here to create the correct public key file from the private key file.
Java doesn't directly contain code to retrieve the public exponent from an RSAPrivateKey without CRT parameters. However, if you want a Java only solution you could cast the PrivateKey even further to RSAPrivateCrtKey which does contain a getPublicExponent method to retrieve the public exponent. Then you can use an RSA KeyFactory to generate a public key using RSAPublicKeySpec.
You could also parse the PEM file to retrieve the public key in Java using e.g. the Bouncy Castle API. But expect a steep learning curve if you do.
Hi I am trying to decrypt the stuff from my public key on Android:
public String decrypt(String basetext) {
try {
FileInputStream iR = new FileInputStream("/sdcard/publickkey");
ObjectInputStream inputStream = new ObjectInputStream(iR);
final PublicKey key = (PublicKey) inputStream.readObject();
byte[] text = Base64.decode(basetext, Base64.DEFAULT);
// get an RSA cipher object and print the provider
final Cipher cipher = Cipher.getInstance("RSA");
// decrypt the text using the public key
cipher.init(Cipher.DECRYPT_MODE, key);
byte[] dectyptedText = cipher.doFinal(text);
iR.close();
return new String(dectyptedText,"UTF-8");
} catch (Exception ex) {
ex.printStackTrace();
return null;
}
}
It works fine on my marshmallow, tried to run on emulator 4.2.2 and it throws below error:
caused by java.lang.noclassdeffounderror com/android/org/constcrypt/OpenSSLRSAPublicKey android
If I see my imports there is no imports like above error
import javax.crypto.Cipher;
import java.security.PublicKey;
import java.io.ObjectInputStream;
import java.io.FileInputStream;
This works fine on real device android marshmallow,4.2.2 on emulator it crashes
full class :-
import android.util.Base64;
import java.io.File;
import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import javax.crypto.Cipher;
public class EncryptionUtils {
public static final String ALGORITHM = "RSA";
public static final String PRIVATE_KEY_FILE = "/sdcard/private.key";
public static final String PUBLIC_KEY_FILE = "/sdcard/public.key";
public static void generateKey() {
try {
final KeyPairGenerator keyGen = KeyPairGenerator.getInstance(ALGORITHM);
keyGen.initialize(2048);
final KeyPair key = keyGen.generateKeyPair();
File privateKeyFile = new File(PRIVATE_KEY_FILE);
File publicKeyFile = new File(PUBLIC_KEY_FILE);
// Create files to store public and private key
if (privateKeyFile.getParentFile() != null) {
privateKeyFile.getParentFile().mkdirs();
}
privateKeyFile.createNewFile();
if (publicKeyFile.getParentFile() != null) {
publicKeyFile.getParentFile().mkdirs();
}
publicKeyFile.createNewFile();
// Saving the Public key in a file
ObjectOutputStream publicKeyOS = new ObjectOutputStream(
new FileOutputStream(publicKeyFile));
publicKeyOS.writeObject(key.getPublic());
publicKeyOS.close();
// Saving the Private key in a file
ObjectOutputStream privateKeyOS = new ObjectOutputStream(
new FileOutputStream(privateKeyFile));
privateKeyOS.writeObject(key.getPrivate());
privateKeyOS.close();
} catch (Exception e) {
e.printStackTrace();
}
}
public static String encrypt(String text, PrivateKey key) {
try {
// get an RSA cipher object and print the provider
final Cipher cipher = Cipher.getInstance(ALGORITHM);
// encrypt the plain text using the private key
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] cipherText = cipher.doFinal(text.getBytes("UTF-8"));
String base64 = Base64.encodeToString(cipherText, Base64.DEFAULT);
return base64;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public static String decrypt(String basetext, PublicKey key) {
try {
byte[] text = Base64.decode(basetext, Base64.DEFAULT);
// get an RSA cipher object and print the provider
final Cipher cipher = Cipher.getInstance(ALGORITHM);
// decrypt the text using the public key
cipher.init(Cipher.DECRYPT_MODE, key);
byte[] dectyptedText = cipher.doFinal(text);
return new String(dectyptedText,"UTF-8");
} catch (Exception ex) {
ex.printStackTrace();
return null;
}
}
}
It pays to be specific when defining the cipher you intend to use. Instead of using:
final Cipher cipher = Cipher.getInstance("RSA");
You should try:
final Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
I believe there were some inconsistencies between plain Java and Android, I don't recall what versions, but in most cases the adjustment above fixes the problem.
well the only thing is that real cryptography is added in android 4.3 and up,so on android 4.2 and below it will cause problem because openssl class was made default in api 18,so using this rsa encrypting/decryption is fine on 4.3+ else to support below use some other techniques.
thats whay is the solution from my side,if anybody else get this porblem you can see the solution here,
or if someone managed to make it work without using third party libraries then he is most welcome to write it here
You should not use ObjectOutputStream / ObjectInputStream to store the keys. The underlying implementation class of PublicKey vary between versions and the serialization of an object using an internal class will fail if the class it is not present in a upper version.
I suggest to store the public key data directly
byte publicKeyData[] = publicKey.getEncoded();
And load it using
X509EncodedKeySpec spec = new X509EncodedKeySpec(publicKeyData);
KeyFactory kf = KeyFactory.getInstance("RSA");
PublicKey publicKey = kf.generatePublic(spec);
Note also that in android previous to 4.3 the cryptographic provider is not fully implemented and non conventional operations like decryption with RSA public key and encryption with private key can be used with guarantees.
UPDATED - Spongycastle
Alternatively you can use spongycastle cryptographic provider to generate and load the keys
Gradle dependencies
compile 'com.madgag.spongycastle:core:1.51.0.0'
compile 'com.madgag.spongycastle:prov:1.51.0.0'
compile 'com.madgag.spongycastle:pkix:1.51.0.0'
Adding the provider
static {
Security.insertProviderAt(new org.spongycastle.jce.provider.BouncyCastleProvider(), 1);
}
USAGE
Add SC to the provider parameter. For example
KeyPairGenerator keyGen= KeyPairGenerator.getInstance("RSA", "SC");
KeyFactory keyFactory = KeyFactory.getInstance("RSA", "SC");
See more info here