Reconstruct private key - java

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

BadPaddingException: pad block corrupted | BouncyCastle

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);
}
}

RSA Encryption disparity between Android and Java environments

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("=", ",");
}

RSAPrivateKey returns RuntimeException

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;
}

RSA encryption fail on older Android device (4.0.3 in this case)

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();
}
}

How to use Cipher on this Method to decrypt a String?

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));
}
}

Categories