I am generating Asymmetric public key and private using the code below.
public static KeyPair generateRSAKkeyPair()
throws Exception {
SecureRandom secureRandom = new SecureRandom();
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(
2048, secureRandom);
return keyPairGenerator
.generateKeyPair();
}
public static byte[] do_RSAEncryption(
String plainText,
PublicKey publicKey)
throws Exception {
Cipher cipher = Cipher.getInstance(RSA);
cipher.init(
Cipher.ENCRYPT_MODE, publicKey);
return cipher.doFinal(
plainText.getBytes());
}
public static String do_RSADecryption(
byte[] cipherText,
PrivateKey privateKey)
throws Exception {
Cipher cipher = Cipher.getInstance(RSA);
cipher.init(Cipher.DECRYPT_MODE,
privateKey);
byte[] result = cipher.doFinal(cipherText);
return new String(result);
}
public static PublicKey getKey(String key) {
try {
byte[] byteKey = Base64.getDecoder().decode(key.getBytes());
X509EncodedKeySpec X509publicKey = new X509EncodedKeySpec(byteKey);
KeyFactory kf = KeyFactory.getInstance("RSA");
return kf.generatePublic(X509publicKey);
}
catch (Exception e) {
e.printStackTrace();
}
return null;
}
public static PrivateKey getPrivateKey(String key) {
try {
byte[] byteKey = Base64.getDecoder().decode(key.getBytes());
X509EncodedKeySpec X509publicKey = new X509EncodedKeySpec(byteKey);
KeyFactory kf = KeyFactory.getInstance("RSA");
return kf.generatePrivate(X509publicKey);
}
catch (Exception e) {
e.printStackTrace();
}
return null;
}
This works as expected.
String plainText = "This is the PlainText. I want to Encrypt using RSA.";
byte[] cipherText = do_RSAEncryption(plainText, keypair.getPublic());
String decryptedText = do_RSADecryption(cipherText, keypair.getPrivate());
Now, I am storing the generated the generated public key and private key in a string and trying to encrypt and decrypt and it is failing.
String base64EncodedEncryptionKey = DatatypeConverter.printBase64Binary(keypair.getPublic().getEncoded()));
String base64EccodedDecryptionKey = DatatypeConverter.printBase64Binary(keypair.getPrivate().getEncoded()));
PublicKey pubKey = getKey(base64EncodedEncryptionKey);
byte[] cipherText1 = do_RSAEncryption(plainText, pubKey);
System.out.println("Encrypted Text ===> "+ DatatypeConverter.printHexBinary(cipherText1));
PrivateKey privateKey = getPrivateKey(base64EccodedDecryptionKey);
String decryptedText1 = do_RSADecryption(cipherText1,privateKey);
System.out.println("DecryptedText ====>>> "+decryptedText1);
Error:-
java.security.spec.InvalidKeySpecException: Only RSAPrivate(Crt)KeySpec and PKCS8EncodedKeySpec supported for RSA private keys
at java.base/sun.security.rsa.RSAKeyFactory.generatePrivate(RSAKeyFactory.java:389)
at java.base/sun.security.rsa.RSAKeyFactory.engineGeneratePrivate(RSAKeyFactory.java:247)
at java.base/java.security.KeyFactory.generatePrivate(KeyFactory.java:390)
at com.apple.ist.alloy.memsqlloader.service.Asymmetric.getPrivateKey(Asymmetric.java:96)
at com.apple.ist.alloy.memsqlloader.service.Asymmetric.main(Asymmetric.java:135)
Exception in thread "main" java.security.InvalidKeyException: No installed provider supports this key: (null)
at java.base/javax.crypto.Cipher.chooseProvider(Cipher.java:930)
at java.base/javax.crypto.Cipher.init(Cipher.java:1286)
at java.base/javax.crypto.Cipher.init(Cipher.java:1223)
at com.apple.ist.alloy.memsqlloader.service.Asymmetric.do_RSADecryption(Asymmetric.java:68)
at com.apple.ist.alloy.memsqlloader.service.Asymmetric.main(Asymmetric.java:137)
Private keys are encoded with PKCS8EncodedKeySpec. You should replace X509EncodedKeySpec with that.
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);
}
}
Firstly, apologies for the amount of code I'm about to post. I'm trying to use the RSA public key from my Java application to encrypt a message in an Android app, and then send the ciphertext back to a Java environment for decryption, but upon attempting to decrypt I always get this error:
javax.crypto.BadPaddingException: Decryption error
at sun.security.rsa.RSAPadding.unpadV15(RSAPadding.java:380)
at sun.security.rsa.RSAPadding.unpad(RSAPadding.java:291)
at com.sun.crypto.provider.RSACipher.doFinal(RSACipher.java:356)
at com.sun.crypto.provider.RSACipher.engineDoFinal(RSACipher.java:382)
at javax.crypto.Cipher.doFinal(Cipher.java:2087)
...
The ciphertext does contain the correct number of bytes (512), so it's confusing to see a "bad padding" exception. Other similar posts on SO have suggested using "RSA/ECB/PKCS1Padding" as the algorithm, but this does not work.
Annoyingly, encryption and decryption in the Android environment (using Base64.URL_SAFE as the 'base64Type') works just fine, I just can't seem to get the initial encryption working with the public key produced via Java.
I have extracted the bare minimum code into examples, as shown below:
Android Code
private void exampleMethod(){
String messageString = "Why does this not work in Android?";
String serverPubKey = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoApIBIna77xq4j+M2RmyIhsB++41NHcY4KIPfX4VP4ADnkO+7ejbs4le/twrPtYGESVPF9czSMB5bzmTBZtq0jC8oT/6wiDIBlSuzo4fBrGociBIuaOjyG/j3ZhpcWpWPXuzER+ehuQ+8hZkMuJdK9IodqPR+5jmCef4rXoKObwS02LYQ1co5dEmtZVQRmmeYaVnWibd/s1d4KKGvSzXap3YBTf8peH5UGIQrLOTqvX0bo34xFxmj5U0H3xudnnwuVAlQlj9KiHPPABuwNtm1buRKJb5HZhSCveyT/2YAOmQqGrVN/nALtlZyTDZNs//Vp1zb9exSuG0t5xFc+pn4QIDAQAB";
String encryptedMessageString = getUrlEncodedCipherText(messageString, serverPubKey, Base64.NO_WRAP);
/**
* CipherText is ALWAYS the same and does not decrypt: DA_-RpCki-mjF6tSwiP2IhuW2UfPzZC7A9oVTTNptjT73HtROiQZvUC0Z2veJ5VwVx4toolvLErQmKKoQlqELSD756bu8ohEQwgJ4Xsu-3tXv-uEi5a9a_u19WnNLIF7tayDUhFeD2RzNvW895y1v-D30TvQRskNCFJfnjaytr_vmcVv8HrXURCmG6AMltaqdN72zh8p6VkKcjXSLiCApH957GXSqJCRzxbaQwf8X5EJfn8CQrPDGbE3gdhc2_hFwXQNIdxPxrOLtVbaFp9i_4GRWXJ6E2jHttV2bDv_uSVIz3OBzh7EkJiCnl3c904sH8QZae8c3SQyrTxVL7EpIA,,
*/
}
public static String getUrlEncodedCipherText(String plainText, String pubKey, int base64Type){
try {
final PublicKey publicKey = loadPublicKey(pubKey, base64Type);
final byte[] cipherBytes = encrypt(plainText, publicKey);
String cipherText = base64Encode(cipherBytes, base64Type);
String urlEncodedCipherText = urlEncode(cipherText);
return urlEncodedCipherText;
}
catch (Exception e){
e.printStackTrace();
return null;
}
}
public static final String ALGORITHM = "RSA";
public static PublicKey loadPublicKey(String stored, int base64Type) throws GeneralSecurityException {
String pubKey = stored.replace(BEGIN_PUBLIC_KEY, "");
pubKey = pubKey.replace(END_PUBLIC_KEY, "");
byte[] data = Base64.decode(pubKey, base64Type);
X509EncodedKeySpec spec = new X509EncodedKeySpec(data);
KeyFactory fact = KeyFactory.getInstance(ALGORITHM);
PublicKey pub = fact.generatePublic(spec);
return pub;
}
public static byte[] encrypt(String text, PublicKey key) {
byte[] cipherText = null;
try {
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, key);
cipherText = cipher.doFinal(text.getBytes());
}
catch (Exception e) {
e.printStackTrace();
}
return cipherText;
}
public static String base64Encode(byte[] cipherBytes, int base64Type){
byte[] base64Cipher = Base64.encode(cipherBytes, base64Type);
return new String(base64Cipher);
}
public static String urlEncode(String text){
return text.replace("+", "-").replace("/", "_").replace("=", ",");
}
Java Code
private void exampleMethod(){
String pubKey = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoApIBIna77xq4j+M2RmyIhsB++41NHcY4KIPfX4VP4ADnkO+7ejbs4le/twrPtYGESVPF9czSMB5bzmTBZtq0jC8oT/6wiDIBlSuzo4fBrGociBIuaOjyG/j3ZhpcWpWPXuzER+ehuQ+8hZkMuJdK9IodqPR+5jmCef4rXoKObwS02LYQ1co5dEmtZVQRmmeYaVnWibd/s1d4KKGvSzXap3YBTf8peH5UGIQrLOTqvX0bo34xFxmj5U0H3xudnnwuVAlQlj9KiHPPABuwNtm1buRKJb5HZhSCveyT/2YAOmQqGrVN/nALtlZyTDZNs//Vp1zb9exSuG0t5xFc+pn4QIDAQAB";
String privKey = "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCgCkgEidrvvGriP4zZGbIiGwH77jU0dxjgog99fhU/gAOeQ77t6NuziV7+3Cs+1gYRJU8X1zNIwHlvOZMFm2rSMLyhP/rCIMgGVK7Ojh8GsahyIEi5o6PIb+PdmGlxalY9e7MRH56G5D7yFmQy4l0r0ih2o9H7mOYJ5/itego5vBLTYthDVyjl0Sa1lVBGaZ5hpWdaJt3+zV3gooa9LNdqndgFN/yl4flQYhCss5Oq9fRujfjEXGaPlTQffG52efC5UCVCWP0qIc88AG7A22bVu5EolvkdmFIK97JP/ZgA6ZCoatU3+cAu2VnJMNk2z/9WnXNv17FK4bS3nEVz6mfhAgMBAAECggEBAIax4IchV0jqdbLR9cNK4yfdP0A/7jun+SImg48FLPDy1xi+v9UQZMioV3F88FDEZPrNQdI45wrWI94+wMS5V6BsMHYumOgGGxNo9m8WInrJz5GuJkdHuLMbqNZ6TlSMQOUiVUWWLSAuveOWgOJqriwRhsjDfBmbSBESUbP/wNdxX42RJudKJbVUV07urjFc3VAUrX+Sbj9KMZRe10pOzes7WKq9NMyQuitLcwCPzs2pQoXW1LdZYrVSi6MOqE1WHSL6VAgPx3cHYl7yznhspLmvDgnKTwnVbRo3BBwkxNbpvZXzgJBLEPLUtLqwNLKkU0aSF9MT5TABx4tfCaRQIiECgYEA70980I9mK74tjXlFrMKaLGigjHBss+Q/b7cRAtlQAhVOn0FCqz4Fc4iBri0iPekVIZ09lRehacEstTR8JBImMW2mqGyMwBbPaqQOf6xZ0pIoYb0ODAIjUNTWoBEr72+ko5HjaoQbxeb2QGUhMe/t3M1CMsrETEQTdA+qNP5C61UCgYEAqzOL7sSsNfTYbAF156qPPqx1IyXNqu0wbKa/zufCxGlFJDkaYoYIECKdLbpI2fqJsENqpZHgOnT0+LbqhFn07NIe1zT/zf0rh7w5fqxqy3Srs4+Mj6HwTIC7QpeXjiHxQuVrfi2W2ZatjQi8froxtEj3mpYKHsl0Ia89JSczQl0CgYAqHPXdCe8z8XK4u8esIE7bU8o1DK/EdH1JXpDqzG1NAIzmb6iY1ABHlZUknqKw/GyQjshAjXkFUE5a0RKrkloQRriWWQvn3dvAa4B1rVHdQYVDte5b5KBsYBgo8PynVSFG+6xmmTr996gMKv/NduiH+8MThyVGOpCl0v/j9X63RQKBgEmOhir6eXtdTbdqETyOPamR82o8jddIvauRIYxGa5p0GG7t0fZO3BwCo0HIbhCp4orHDIVC3fJ/2dkazjw7Yk52ISYZ8WaRxig1qQZSEjiEUll97ciwrUxRayO7ejRpRP2XEM5PzCaE5OBZxpM0cLKjPy8+E+8SY0Etx7m01ANJAoGBALUubgeKx1fut80YHLDmxOiTg9olFJi83Lj1TPQ0fRCXdJX6pHCSypBScoXuJYVwuIavHhTf8DPQ6OONq/V3DXKsGLydK/2E5yg+bz3qYfYslb3vDkZovNJDmfoyR0XakWbUTotntUQqodLk8Q9klHKp6oy+MkGY57R5OhIZBGPa";
String message = "Why does this not work in Android?";
String encryptedMessage = getUrlEncodedCipherText(message, pubKey);
try {
byte[] base64Decoded = Base64.decodeBase64(encryptedMessage.getBytes(Charset.forName("UTF-8")));
String decryptedMessage = decrypt(base64Decoded, loadPrivateKey(privKey));
System.out.println("decryptedMessage: " + decryptedMessage);
/**
* This works! Ciphertext always comes out different, as expected, and decodes successfully.
*/
}
catch (Exception e){
e.printStackTrace();
}
}
public static String getUrlEncodedCipherText(String plainText, String pubKey){
try {
final PublicKey publicKey = loadPublicKey(pubKey);
final byte[] cipherBytes = encrypt(plainText, publicKey);
String cipherText = base64Encode(cipherBytes);
String urlEncodedCipherText = urlEncode(cipherText);
return urlEncodedCipherText;
}
catch (Exception e){
e.printStackTrace();
return null;
}
}
public static final String ALGORITHM = "RSA";
public static PublicKey loadPublicKey(String stored) throws GeneralSecurityException {
String pubKey = stored.replace(BEGIN_PUBLIC_KEY, "");
pubKey = pubKey.replace(END_PUBLIC_KEY, "");
byte[] data = Base64.decodeBase64(pubKey);
X509EncodedKeySpec spec = new X509EncodedKeySpec(data);
KeyFactory fact = KeyFactory.getInstance(ALGORITHM);
PublicKey pub = fact.generatePublic(spec);
return pub;
}
public static byte[] encrypt(String text, PublicKey key) {
byte[] cipherText = null;
try {
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, key);
cipherText = cipher.doFinal(text.getBytes());
}
catch (Exception e) {
e.printStackTrace();
}
return cipherText;
}
public static String decrypt(byte[] encrypted, PrivateKey key) {
byte[] decryptedText = null;
try {
final Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, key);
decryptedText = cipher.doFinal(encrypted);
}
catch (Exception e) {
e.printStackTrace();
return null;
}
return new String(decryptedText);
}
public static String base64Encode(byte[] cipherBytes){
byte[] base64Cipher = Base64.encodeBase64(cipherBytes);
return new String(base64Cipher);
}
public static String urlEncode(String text){
return text.replace("+", "-").replace("/", "_").replace("=", ",");
}
I'm aware that the problem has to be to do with difference in the way Android and Java interpret the RSA algorithm, and/or differences with the Base64 encode/decode, but I'm stumped. Any assistance greatly appreciated.
Solved it! The issue was that I was using the same ALGORITHM String for Cipher, KeyFactory etc. I split this into two different Strings, and the full solution for my problem is...
Android Code
private void exampleMethod(){
String messageString = "This actually works in Java AND Android!";
String serverPubKey = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAjS7T3WJ+VLucnUP5WYryeg+hhOjZZl5VxwvJAgo4GrXaXdernTPtmXnOSUlbhd928QRCip7D3rLwJNvGIwhPa6coA+YQnj+aHQC02AvCJP/9jpeNmm5MASZfYFXrdmOrMhAPpDZ4rUk1mqtvpwBkYmW3VbMtG336wT1bAIKPHCZuI2n6glupJvs8gK0NuIoAPRlxiQmQD7NCcRx1Et4JmqOMIRC+HqdGv9GGqC/0PB0Fv6LXi8GdzJQPMdoRLR0rvVykNeIzmcimejoIVjI78XUZeB1hF7p55h6W4C4Xm/PrnzKuXw4lBVehZtRhyIvNO62G/eNEZ3tup1/m+vkzHQIDAQAB";
String encryptedMessageString = getUrlEncodedCipherText(messageString, serverPubKey, Base64.NO_WRAP);
System.out.println("encryptedMessageString: " + encryptedMessageString);
/**
* This works! Ciphertext always comes out different, as expected, and decodes successfully when fed into Java application.
*/
}
public static String getUrlEncodedCipherText(String plainText, String pubKey, int base64Type){
try {
final PublicKey publicKey = loadPublicKey(pubKey, base64Type);
final byte[] cipherBytes = encrypt(plainText, publicKey);
String cipherText = base64Encode(cipherBytes, base64Type);
String urlEncodedCipherText = urlEncode(cipherText);
return urlEncodedCipherText;
}
catch (Exception e){
e.printStackTrace();
return null;
}
}
public static final String ALGORITHM = "RSA";
public static final String CIPHER_ALGORITHM = "RSA/ECB/PKCS1Padding";
public static PublicKey loadPublicKey(String stored, int base64Type) throws GeneralSecurityException {
String pubKey = stored.replace(BEGIN_PUBLIC_KEY, "");
pubKey = pubKey.replace(END_PUBLIC_KEY, "");
byte[] data = Base64.decode(pubKey, base64Type);
X509EncodedKeySpec spec = new X509EncodedKeySpec(data);
KeyFactory fact = KeyFactory.getInstance(ALGORITHM);
PublicKey pub = fact.generatePublic(spec);
return pub;
}
public static byte[] encrypt(String text, PublicKey key) {
byte[] cipherText = null;
try {
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, key);
cipherText = cipher.doFinal(text.getBytes());
}
catch (Exception e) {
e.printStackTrace();
}
return cipherText;
}
public static String base64Encode(byte[] cipherBytes, int base64Type){
byte[] base64Cipher = Base64.encode(cipherBytes, base64Type);
return new String(base64Cipher);
}
public static String urlEncode(String text){
return text.replace("+", "-").replace("/", "_").replace("=", ",");
}
Java Code
private void exampleMethod(){
String pubKey = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAjS7T3WJ+VLucnUP5WYryeg+hhOjZZl5VxwvJAgo4GrXaXdernTPtmXnOSUlbhd928QRCip7D3rLwJNvGIwhPa6coA+YQnj+aHQC02AvCJP/9jpeNmm5MASZfYFXrdmOrMhAPpDZ4rUk1mqtvpwBkYmW3VbMtG336wT1bAIKPHCZuI2n6glupJvs8gK0NuIoAPRlxiQmQD7NCcRx1Et4JmqOMIRC+HqdGv9GGqC/0PB0Fv6LXi8GdzJQPMdoRLR0rvVykNeIzmcimejoIVjI78XUZeB1hF7p55h6W4C4Xm/PrnzKuXw4lBVehZtRhyIvNO62G/eNEZ3tup1/m+vkzHQIDAQAB";
String privKey = "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCNLtPdYn5Uu5ydQ/lZivJ6D6GE6NlmXlXHC8kCCjgatdpd16udM+2Zec5JSVuF33bxBEKKnsPesvAk28YjCE9rpygD5hCeP5odALTYC8Ik//2Ol42abkwBJl9gVet2Y6syEA+kNnitSTWaq2+nAGRiZbdVsy0bffrBPVsAgo8cJm4jafqCW6km+zyArQ24igA9GXGJCZAPs0JxHHUS3gmao4whEL4ep0a/0YaoL/Q8HQW/oteLwZ3MlA8x2hEtHSu9XKQ14jOZyKZ6OghWMjvxdRl4HWEXunnmHpbgLheb8+ufMq5fDiUFV6Fm1GHIi807rYb940Rne26nX+b6+TMdAgMBAAECggEAOHrlUwmWFHvBmcCZvlKx0lbyfONSJXvTwP9b+K7x5u2dYDFpfEhL4zwxZGwuaw4M3TqhDCeboDnhjD1HtLgcXarPfU/KkiRLmRKxRkTd9ENcwnCqu38odMVPHpEA06nn0O1P9Je+C0TgZvHyhtLHVf3vLB+0Ce2KJUhQYZHZgp7dBt0jgsGlEvQTtc1q3UtElNYbcPdLhg16Dcvw93+C+CWizUxHKl2VAxYBz5fGBxa+Cc6xbj4OGd0mvK9Z+71cX8sgp+WIdSV3a2SZrwYq8XxdtJJfdOwPc6LE56Ul9y3fE/biG8DM8ysu7g4C2K1tjKBTq1Rzz4NBCaGwkWQwGQKBgQDCX5nOiHYi0OYoE3WEVYVuEaf/YljurMiU4xYsy3bXzI42S+iKfVHz+/tvTrXSE0n6AdJnDHyP7mncFZodaurYR90S9VW3P+aOGoysmOmBRWW30xyIZ1g5+PJ9xPzoBfyc/AGHO5w5roY7Gg5myUC+UbucFU+9/JHUVoGV8yFz+wKBgQC58f8iY37sXf/sguv0YHpUV1suPWT90kxC25eRQz0lHWIIw4gfGXI7Tf2vtx7hUPK1z3X9lPiTsqmZIRKPrvykD8djmpfZEOzZlLxxhHUZMZppx19xSsgHaespCZir68aytBWn7FOVpehJP7MWaJurg03V8Cv0NSPU5JhN/j8xxwKBgQCkb6I78oAWtilvz/6EJKGL244HZJkd2bibFH4HCV4R9HB/CLrCpoB1a0BsCueQwFa+FVp9aTfbv/N4iCHoLzJcJHeneTu5mmqe32ERBw/MF/yUhhnGX79o0+25brQSSjZKTHuyf0CMH9RZHZL/a9TE7XpM8k6SyKBKRaC9TYGIjwKBgDZG10x4coIYZi3pgWqSBuM7pJf4v9P/YNdbNgDm+aAt1YHtYXyCdv+solJ6R39Jm69KYYylwXGLg0n5h2t9jq1tFayTYaOw9xIEAoW4Pl4eRo597fQp+f2AA261KGV2q0danb+okjVqekV3XJU778S+zSeXtZzRLiZkm7iYcGXdAoGAUEbRAsopG+blDBmuC5Fhr7Grof9lw/zRgfl516n9oujOmDY8Sl4F7jHkgKzOL1CpvMbRswr6G3tmpJMYGNy0HVX4n4QAiIvEraLUtLlh7LotUiU8zzjniK7HPANoOsQxEi6iUR6jWRf0LKgckE9aaUJjvljj1Hr4PbFpny2gjD4=";
String message = "This actually works in Java AND Android!";
String encryptedMessage = getUrlEncodedCipherText(message, pubKey);
try {
byte[] base64Decoded = Base64.decodeBase64(encryptedMessage.getBytes(Charset.forName("UTF-8")));
String decryptedMessage = decrypt(base64Decoded, loadPrivateKey(privKey));
System.out.println("decryptedMessage: " + decryptedMessage);
/**
* This works! Ciphertext always comes out different, as expected, and decodes successfully.
*/
}
catch (Exception e){
e.printStackTrace();
}
}
public static String getUrlEncodedCipherText(String plainText, String pubKey){
try {
final PublicKey publicKey = loadPublicKey(pubKey);
final byte[] cipherBytes = encrypt(plainText, publicKey);
String cipherText = base64Encode(cipherBytes);
String urlEncodedCipherText = urlEncode(cipherText);
return urlEncodedCipherText;
}
catch (Exception e){
e.printStackTrace();
return null;
}
}
public static final String ALGORITHM = "RSA";
public static final String CIPHER_ALGORITHM = "RSA/ECB/PKCS1Padding";
public static PublicKey loadPublicKey(String stored) throws GeneralSecurityException {
String pubKey = stored.replace(BEGIN_PUBLIC_KEY, "");
pubKey = pubKey.replace(END_PUBLIC_KEY, "");
byte[] data = Base64.decodeBase64(pubKey);
X509EncodedKeySpec spec = new X509EncodedKeySpec(data);
KeyFactory fact = KeyFactory.getInstance(ALGORITHM);
PublicKey pub = fact.generatePublic(spec);
return pub;
}
public static byte[] encrypt(String text, PublicKey key) {
byte[] cipherText = null;
try {
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, key);
cipherText = cipher.doFinal(text.getBytes());
}
catch (Exception e) {
e.printStackTrace();
}
return cipherText;
}
public static String decrypt(byte[] encrypted, PrivateKey key) {
byte[] decryptedText = null;
try {
final Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, key);
decryptedText = cipher.doFinal(encrypted);
}
catch (Exception e) {
e.printStackTrace();
return null;
}
return new String(decryptedText);
}
public static String base64Encode(byte[] cipherBytes){
byte[] base64Cipher = Base64.encodeBase64(cipherBytes);
return new String(base64Cipher);
}
public static String urlEncode(String text){
return text.replace("+", "-").replace("/", "_").replace("=", ",");
}
Im trying to get the RSA keys to OpenSSLRSAPublicKey and OPENSSLRSAPrivateKey format on Android.
The keys look like this (generated automatically, do not work):
Private key string:
MIICWwIBAAKBgHfvJ1jB80KZTaEYClqbM0znYlos0qTenOF+BSjC4DT31rCwLgMJ
5/c7jSUuzH34OypP8Z7sGMz4UIXzXRGUKXA0TFXvq3aKNMGa74SCB3AGJmjb4yvT
rXpTytfeuJsodJzBmwsCkgfkAYZBH06OJAxNPpqoUMUZHOg61hTHwm9nAgMBAAEC
gYBC8L3yYVaITo6won1s8wEgJGmV0TzE/udrSG5SwOppRgeTWNJlqcrKCHgQT92d
VcaYKETBIh/5j4NKMHo6zIqPpH7GxzNuG3Ua+pmi6VOcdFs7O071q6zAt9aLb/Dd
rs7gJb5/H2/LuJBbKInKb+c0IUMEQ9AFoAc70q+um4eJmQJBAOxugXf7LFlCrfun
TuR5eYVjLBM9pmVRMEYJcp9CH7qtTAKhdHAKgnZ7Sw3gTxtBi+msnm3zXwtzO/cY
Xjh+m7UCQQCB3E8xvJWICLpX/11saDUOZsoaC53A7SunptkbAyJ49yE8SVg3O92i
kqRBlFho1JL84vDZe10GXwxj6O1XwigrAkAAzfN01A73ksmCxLP5BQzLzmWU/y20
xIz0gA26yv/Oo85RZ/k8dFyzSIId3viF8DgoqGS1nRFiuZanpZaUfKHNAkAuQwDH
dCpE+u7/eE6c1wbHqaCn5Kl/WD5sDEldkSFPvKJPasWNb7tGNj1jy2gveEMg6evp
XkRGh8fPM+SRle5fAkEAmaQeOnryugbQBVOAj006jEQaidYsF8FNnKSAyxPQlbSC
Nee4pL/hKkjqtm5zKgEp8f0dHRhz5vb94EdLnl1DJA==
Public key string:
MIGeMA0GCSqGSIb3DQEBAQUAA4GMADCBiAKBgHfvJ1jB80KZTaEYClqbM0znYlos
0qTenOF+BSjC4DT31rCwLgMJ5/c7jSUuzH34OypP8Z7sGMz4UIXzXRGUKXA0TFXv
q3aKNMGa74SCB3AGJmjb4yvTrXpTytfeuJsodJzBmwsCkgfkAYZBH06OJAxNPpqo
UMUZHOg61hTHwm9nAgMBAAE=
This is my code:
public static RSAPrivateKey getPrivateKeyFromString(String key) throws IOException, GeneralSecurityException {
String privateKeyPEM = key;
privateKeyPEM = privateKeyPEM.replace("-----BEGIN PRIVATE KEY-----\n", "");
privateKeyPEM = privateKeyPEM.replace("-----END PRIVATE KEY-----", "");
byte[] encoded = Base64.decode(privateKeyPEM, Base64.DEFAULT);
KeyFactory kf = KeyFactory.getInstance("RSA");
///////// Line below is (RSA.java:37)
RSAPrivateKey privKey = (RSAPrivateKey) kf.generatePrivate(new PKCS8EncodedKeySpec(encoded));
return privKey;
}
public static RSAPublicKey getPublicKeyFromString(String key) throws IOException, GeneralSecurityException {
String publicKeyPEM = key;
publicKeyPEM = publicKeyPEM.replace("-----BEGIN PUBLIC KEY-----\n", "");
publicKeyPEM = publicKeyPEM.replace("-----END PUBLIC KEY-----", "");
byte[] encoded = Base64.decode(publicKeyPEM, Base64.DEFAULT);
KeyFactory kf = KeyFactory.getInstance("RSA");
RSAPublicKey pubKey = (RSAPublicKey) kf.generatePublic(new X509EncodedKeySpec(encoded));
return pubKey;
}
The interesting thing is that the pubKey returns this:
OpenSSLRSAPublicKey{modulus=9920c2.....,publicExponent=10001}
But the privKey gives me this exception:
W/System.err: java.security.spec.InvalidKeySpecException: java.lang.RuntimeException: error:0c0890ba:ASN.1 encoding routines:asn1_check_tlen:WRONG_TAG
W/System.err: at com.android.org.conscrypt.OpenSSLKey.getPrivateKey(OpenSSLKey.java:283)
W/System.err: at com.android.org.conscrypt.OpenSSLRSAKeyFactory.engineGeneratePrivate(OpenSSLRSAKeyFactory.java:64)
W/System.err: at java.security.KeyFactory.generatePrivate(KeyFactory.java:187)
W/System.err: at com.vladmarton.educomiit.RSA$override.getPrivateKeyFromString(RSA.java:37)
I browsed the stackoverflow for a long time but I did not find any working solution. I need to have them in the exact format as the pubKey, but cant get the private key to work.
public static PublicKey buildPublicKey() {
try {
byte[] keyBytes = Base64.decode(publicKey.getBytes(StandardCharsets.UTF_8), Base64.DEFAULT);
X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
return keyFactory.generatePublic(spec);
} catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
Logger.e(Logger.TAG, e.getMessage());
}
return null;
}
private static PrivateKey buildPrivateKey() {
String key= privateKey.replace("-----BEGIN RSA PRIVATE KEY-----", "").replace("-----END RSA PRIVATE KEY-----", "")
.replaceAll("\\s+", "").replaceAll("\\r+", "").replaceAll("\\n+", "");
try {
byte[] keyByteArray = Base64.decode(key, Base64.DEFAULT);
KeyFactory kf = KeyFactory.getInstance("RSA");
EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyByteArray);
return kf.generatePrivate(keySpec);
} catch (Exception e) {
Logger.e(Logger.TAG, e.getMessage());
}
return null;
}
im pretty new to android development and i have the following method for encryption data using RSA(2048b):
public byte[] encryptData(String base64) throws GeneralSecurityException {
byte[] dataToEncrypt = base64.getBytes(Charset.forName("UTF-8")); //lenght == 90
try {
RSAPublicKeySpec rsaPublicKeySpec = new RSAPublicKeySpec(rsaKeys.getPublicModus(), rsaKeys.getPublicExpo());
KeyFactory fact = KeyFactory.getInstance("RSA");
PublicKey pubKey = fact.generatePublic(rsaPublicKeySpec);
//default providers
//4.0.3 - BC (BouncyCastleProvider)
//4.4.2 - AndroidOpenSSL
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
byte[] encryptedData = cipher.doFinal(dataToEncrypt); //this throw exception
return encryptedData;
} catch (GeneralSecurityException e) {
throw e;
}
}
This block of code working on Android 4.4.2 like a magic. Problem comming with Android 4.0.3 where its always end with exception:
com.android.org.bouncycastle.crypto.DataLengthException: input too large for RSA cipher.
at com.android.org.bouncycastle.crypto.engines.RSACoreEngine.convertInput(RSACoreEngine.java:115)
at com.android.org.bouncycastle.crypto.engines.RSABlindedEngine.processBlock(RSABlindedEngine.java:95)
at com.android.org.bouncycastle.crypto.encodings.PKCS1Encoding.encodeBlock(PKCS1Encoding.java:184)
at com.android.org.bouncycastle.crypto.encodings.PKCS1Encoding.processBlock(PKCS1Encoding.java:132)
at com.android.org.bouncycastle.jce.provider.JCERSACipher.engineDoFinal(JCERSACipher.java:467)
at javax.crypto.Cipher.doFinal(Cipher.java:1106)
Im confuse whats wrong (data length and keysize is on both device same). I will be grateful for any clue. Thanks.
My RSAKeys class contains simple constructor and get/set for each field:
private BigInteger publicModus, publicExpo;
private BigInteger privateModus, privateExpo;
Im using this method for RSA key generation:
#SuppressLint("TrulyRandom")
public RSAKeys generateRSAKeys() throws NoSuchAlgorithmException, InvalidKeySpecException {
try {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(2048);
KeyPair keyPair = keyPairGenerator.generateKeyPair();
PublicKey publicKey = keyPair.getPublic();
PrivateKey privateKey = keyPair.getPrivate();
// Pullingout parameters which makes up Key
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
RSAPublicKeySpec rsaPubKeySpec = keyFactory.getKeySpec(publicKey,
RSAPublicKeySpec.class);
RSAPrivateKeySpec rsaPrivKeySpec = keyFactory.getKeySpec(
privateKey, RSAPrivateKeySpec.class);
rsaKeys = new RSAKeys(
rsaPubKeySpec.getModulus(), rsaPubKeySpec.getPublicExponent(),
rsaPrivKeySpec.getModulus(), rsaPrivKeySpec.getPrivateExponent());
return rsaKeys;
} catch (NoSuchAlgorithmException e) {
throw e;
} catch (InvalidKeySpecException e) {
throw e;
}
}
I edited my code for using same message to encrypt base64 = "plain text"; and same RSA keys on both devices. Without any progress. Still getting error on device with Android 4.0.3.
Devices:
HTC Desire 610 - Android 4.4.2
HTC One V - Android 4.0.3
try to specific both algorithm and provider
// example how to generate key pair
class MyKeyPair {
private static final String ALGORITHM = "RSA";
private static final String PROVIDER ="BC";
private static final int STRENGTH = 2048;
private PrivateKey _privateKey;
private PublicKey _publicKey;
public PublicKey getPublicKey {return _publicKey;}
public MyKeyPair() {
generateKeyPair(STRENGTH,RSA,BC);
}
private void generateKeyPair(int keyLength, String algorithm,
String providerName) {
KeyPairGenerator keyPairGen =
KeyPairGenerator.getInstance(algorithm,providerName);
keyPairGen.initialize(keyLength);
KeyPair keyPair = keyPairGen.generateKeyPair();
_privateKey = keyPair.getPrivate();
_publicKey = keyPair.getPublic();
}
}
Hello I build this 2 Methods the Encryption works fine but the Decryption get an error because
cipher wants a byte and i want to encrypt from a String
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
public class Test {
private byte[] encrypted;
private String encryptedtext;
private String decrypted;
public String Encrypt (String pInput) {
try {
String Input = pInput;
String key = "Bar12345Bar12345Bar12345Bar12345";
// Erstelle key and cipher
SecretKeySpec aesKey = new SecretKeySpec(key.getBytes(), "AES");
Cipher cipher = Cipher.getInstance("AES");
// Verschlüsselung
cipher.init(Cipher.ENCRYPT_MODE, aesKey);
byte[] encrypted = cipher.doFinal(Input.getBytes());
encryptedtext = new String(encrypted);
System.err.println("encrypted:" + encryptedtext);
}catch(Exception e) {
e.printStackTrace();
}
return encrypted;
}
public String Decrypt (String pInput) {
try {
String Input = pInput;
String key = "Bar12345Bar12345Bar12345Bar12345";
// Erstelle key and cipher
SecretKeySpec aesKey = new SecretKeySpec(key.getBytes(), "AES");
Cipher cipher = Cipher.getInstance("AES");
// Entschlüsselung
cipher.init(Cipher.DECRYPT_MODE, aesKey);
decrypted = new String(cipher.doFinal(encryptedtext)); // HERE IS THE PROBLEM IT WANT BYTE BUT I WANT TO ENCRYPT FROM A STRING
System.err.println("decrypted: " + decrypted);
}catch(Exception e) {
e.printStackTrace();
}
return pInput;
}
}
Byte array cannot directly convert to string, and neither do the reverse direction.
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;
public class stackoverflow_test {
private byte[] encrypted;
private String encryptedtext;
private String decrypted;
public String Encrypt(String pInput) {
try {
String Input = pInput;
String key = "Bar12345Bar12345Bar12345Bar12345";
SecretKeySpec aesKey = new SecretKeySpec(key.getBytes(), "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, aesKey);
byte[] encrypted = cipher.doFinal(Input.getBytes());
//encryptedtext = new String(encrypted);
encryptedtext = DatatypeConverter.printBase64Binary(encrypted);
System.err.println("encrypted:" + encryptedtext);
} catch (Exception e) {
e.printStackTrace();
}
return encryptedtext;
}
public String Decrypt(String pInput) {
try {
String Input = pInput;
String key = "Bar12345Bar12345Bar12345Bar12345";
SecretKeySpec aesKey = new SecretKeySpec(key.getBytes(), "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, aesKey);
encrypted = DatatypeConverter.parseBase64Binary(encryptedtext);
decrypted = new String(cipher.doFinal(encrypted));
System.err.println("decrypted: " + decrypted);
} catch (Exception e) {
e.printStackTrace();
}
return pInput;
}
public static void main(String[] ag){
stackoverflow_test test = new stackoverflow_test();
String a = test.Encrypt("Byte cannot directly convert to string");
String b = test.Decrypt(a);
}
}
Result
encrypted:UmH+3eUagjrRDblxSStArnaktoxTLX+7qvPdwiTO7VggYmYtuXu/Ygww8ZG5SrDz
decrypted: Byte cannot directly convert to string
You can use Cipher to encrypt and decrypt a String.
public class CryptUtil {
private static final String ALGORITHM = "Blowfish";
private static final String MODE = "Blowfish/CBC/PKCS5Padding";
private static final String IV = "abcdefgh";
public static String encrypt(String secretKey, String value ) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey.getBytes(), ALGORITHM);
Cipher cipher = Cipher.getInstance(MODE);
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, new IvParameterSpec(IV.getBytes()));
byte[] values = cipher.doFinal(value.getBytes());
return Base64.encodeToString(values, Base64.DEFAULT);
}
public static String decrypt(String secretKey, String value) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
byte[] values = Base64.decode(value, Base64.DEFAULT);
SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey.getBytes(), ALGORITHM);
Cipher cipher = Cipher.getInstance(MODE);
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, new IvParameterSpec(IV.getBytes()));
return new String(cipher.doFinal(values));
}
}