I am implementing a demo for RSA Encryption and Decryption in Android. I can Perform Encryption very well, but In Decryption I get an Exception: >>java.security.InvalidKeyException: unknown key type passed to RSA
.
KeyPairGenerator kpg;
KeyPair kp;
PublicKey publicKey;
PrivateKey privateKey;
byte [] encryptedBytes,decryptedBytes;
Cipher cipher,cipher1;
String encrypted,decrypted;
public String RSAEncrypt (final String plain) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException
{
kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(1024);
kp = kpg.genKeyPair();
publicKey = kp.getPublic();
privateKey = kp.getPrivate();
cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
encryptedBytes = cipher.doFinal(plain.getBytes());
encrypted = new String(encryptedBytes);
System.out.println("EEncrypted?????"+encrypted);
return encrypted;
}
public String RSADecrypt (final String result) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException
{
cipher1=Cipher.getInstance("RSA");
cipher1.init(Cipher.DECRYPT_MODE, privateKey);
decryptedBytes = cipher1.doFinal(result.getBytes());
decrypted = new String(decryptedBytes);
System.out.println("DDecrypted?????"+decrypted);
return decrypted;
}
And I am calling the function from here:
encrypt.setOnClickListener(new OnClickListener()
{
public void onClick(View arg0)
{
try
{
RSAEncrypt rsaencrypt=new RSAEncrypt();
rsaencrypt.RSAEncrypt(name);
result=rsaencrypt.RSAEncrypt(name);
Toast.makeText(getBaseContext(), result.toString(),Toast.LENGTH_SHORT).show();
System.out.println("Result:"+result);
}
catch(Exception e)
{
e.printStackTrace();
Toast.makeText(getBaseContext(), e.toString(),Toast.LENGTH_LONG).show();
}
}
});
decrypt.setOnClickListener(new OnClickListener()
{
public void onClick(View arg0)
{
{
try
{
RSAEncrypt rsadecrypt=new RSAEncrypt();
rsadecrypt.RSADecrypt(result);
ans=rsadecrypt.RSADecrypt(result);
System.out.println("Result is"+ans);
Toast.makeText(getBaseContext(), ans.toString(),Toast.LENGTH_LONG).show();
}
catch(Exception e)
{
e.printStackTrace();
Toast.makeText(getBaseContext(), e.toString(),Toast.LENGTH_LONG).show();
System.out.println("Exception is>>"+e);
}
}
});
To decrypt a ciphertext C using an RSA public key we simply compute the plaintext M as: M = Cd mod N. Note that both RSA encryption and RSA decryption involve a modular exponentiation and so we would be well advised to use the Repeated Squares Algorithm if we want to make these processes reasonably efficient.
Encryption is the process of encoding all user data on an Android device using symmetric encryption keys. Once a device is encrypted, all user-created data is automatically encrypted before committing it to disk and all reads automatically decrypt data before returning it to the calling process.
RSA is a public-key or asymmetric crypto system. It uses a public key for encryption and a private key for decryption. Anyone can use the public key to encrypt a message, but it can be decrypted only by the private key owner.
RSA is the standard cryptographic algorithm on the Internet. The method is publicly known but extremely hard to crack. It uses two keys for encryption. The public key is open and the client uses it to encrypt a random session key.
My class:
package com.infovale.cripto; import java.io.UnsupportedEncodingException; import java.math.BigInteger; import java.security.InvalidKeyException; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; import java.security.PublicKey; import java.util.Arrays; import javax.crypto.BadPaddingException; import javax.crypto.Cipher; import javax.crypto.IllegalBlockSizeException; import javax.crypto.NoSuchPaddingException; public class RSA { KeyPairGenerator kpg; KeyPair kp; PublicKey publicKey; PrivateKey privateKey; byte[] encryptedBytes, decryptedBytes; Cipher cipher, cipher1; String encrypted, decrypted; public String Encrypt (String plain) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException { kpg = KeyPairGenerator.getInstance("RSA"); kpg.initialize(1024); kp = kpg.genKeyPair(); publicKey = kp.getPublic(); privateKey = kp.getPrivate(); cipher = Cipher.getInstance("RSA"); cipher.init(Cipher.ENCRYPT_MODE, publicKey); encryptedBytes = cipher.doFinal(plain.getBytes()); encrypted = bytesToString(encryptedBytes); return encrypted; } public String Decrypt (String result) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException { cipher1=Cipher.getInstance("RSA"); cipher1.init(Cipher.DECRYPT_MODE, privateKey); decryptedBytes = cipher1.doFinal(stringToBytes(result)); decrypted = new String(decryptedBytes); return decrypted; } public String bytesToString(byte[] b) { byte[] b2 = new byte[b.length + 1]; b2[0] = 1; System.arraycopy(b, 0, b2, 1, b.length); return new BigInteger(b2).toString(36); } public byte[] stringToBytes(String s) { byte[] b2 = new BigInteger(s, 36).toByteArray(); return Arrays.copyOfRange(b2, 1, b2.length); } }
In RSA you should use the public key for encryption and the private key for decryption.
Your sample code uses for encryption and decryption the public key - this can not work.
Hence in the decryption part you should initialize the cipher this way:
cipher1.init(Cipher.DECRYPT_MODE, privateKey);
Furthermor your code has a second significant bug:
You are converting a byte array with binary content to a String.
Never ever convert binary data to a String!
Strings are for string characters, not binary data. If you want to pack binary data into a String encode it to printable characters for example using Hex or Base64.
The following example uses the hexadecimal encoder fro org.apache.common.codec package - a third party library with has to be installed.
public byte[] RSAEncrypt(final String plain) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException { kpg = KeyPairGenerator.getInstance("RSA"); kpg.initialize(2048); kp = kpg.genKeyPair(); publicKey = kp.getPublic(); privateKey = kp.getPrivate(); cipher = Cipher.getInstance("RSA"); cipher.init(Cipher.ENCRYPT_MODE, publicKey); encryptedBytes = cipher.doFinal(plain.getBytes()); System.out.println("EEncrypted?????" + new String(org.apache.commons.codec.binary.Hex.encodeHex(encryptedBytes))); return encryptedBytes; } public String RSADecrypt(final byte[] encryptedBytes) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException { cipher1 = Cipher.getInstance("RSA"); cipher1.init(Cipher.DECRYPT_MODE, privateKey); decryptedBytes = cipher1.doFinal(encryptedBytes); decrypted = new String(decryptedBytes); System.out.println("DDecrypted?????" + decrypted); return decrypted; }
Here is an example for Android of:
These methods deal with all the base 64 encoding/decoding.
public void TestEncryptData(String dataToEncrypt) {
// generate a new public/private key pair to test with (note. you should only do this once and keep them!)
KeyPair kp = getKeyPair();
PublicKey publicKey = kp.getPublic();
byte[] publicKeyBytes = publicKey.getEncoded();
String publicKeyBytesBase64 = new String(Base64.encode(publicKeyBytes, Base64.DEFAULT));
PrivateKey privateKey = kp.getPrivate();
byte[] privateKeyBytes = privateKey.getEncoded();
String privateKeyBytesBase64 = new String(Base64.encode(privateKeyBytes, Base64.DEFAULT));
// test encryption
String encrypted = encryptRSAToString(dataToEncrypt, publicKeyBytesBase64);
// test decryption
String decrypted = decryptRSAToString(encrypted, privateKeyBytesBase64);
}
public static KeyPair getKeyPair() {
KeyPair kp = null;
try {
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(2048);
kp = kpg.generateKeyPair();
} catch (Exception e) {
e.printStackTrace();
}
return kp;
}
public static String encryptRSAToString(String clearText, String publicKey) {
String encryptedBase64 = "";
try {
KeyFactory keyFac = KeyFactory.getInstance("RSA");
KeySpec keySpec = new X509EncodedKeySpec(Base64.decode(publicKey.trim().getBytes(), Base64.DEFAULT));
Key key = keyFac.generatePublic(keySpec);
// get an RSA cipher object and print the provider
final Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWITHSHA-256ANDMGF1PADDING");
// encrypt the plain text using the public key
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] encryptedBytes = cipher.doFinal(clearText.getBytes("UTF-8"));
encryptedBase64 = new String(Base64.encode(encryptedBytes, Base64.DEFAULT));
} catch (Exception e) {
e.printStackTrace();
}
return encryptedBase64.replaceAll("(\\r|\\n)", "");
}
public static String decryptRSAToString(String encryptedBase64, String privateKey) {
String decryptedString = "";
try {
KeyFactory keyFac = KeyFactory.getInstance("RSA");
KeySpec keySpec = new PKCS8EncodedKeySpec(Base64.decode(privateKey.trim().getBytes(), Base64.DEFAULT));
Key key = keyFac.generatePrivate(keySpec);
// get an RSA cipher object and print the provider
final Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWITHSHA-256ANDMGF1PADDING");
// encrypt the plain text using the public key
cipher.init(Cipher.DECRYPT_MODE, key);
byte[] encryptedBytes = Base64.decode(encryptedBase64, Base64.DEFAULT);
byte[] decryptedBytes = cipher.doFinal(encryptedBytes);
decryptedString = new String(decryptedBytes);
} catch (Exception e) {
e.printStackTrace();
}
return decryptedString;
}
I think the problem is that you should use the same key pair to encrypt and decrypt the cipher. Referring to the JavaDoc:
genKeyPair() This will generate a new key pair every time it is called.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With