I am trying to implement AES/GCM/NoPadding encryption and decryption in JAVA .. the key used is a shared key from the public key of the receiver and the private key of the sender (ECDH).. encryption works well (with and without iv). However, I am unable to decrypt...
I get the exception: javax.crypto.BadPaddingException: mac check in GCM failed
public static String encryptString(SecretKey key, String plainText) throws NoSuchProviderException, NoSuchAlgorithmException, NoSuchPaddingException, UnsupportedEncodingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
//IvParameterSpec ivSpec = new IvParameterSpec(iv);
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding", "BC");//AES/ECB/PKCS5Padding //"AES/GCM/NoPadding", "BC"
byte[] plainTextBytes = plainText.getBytes("UTF-8");
byte[] cipherText;
//cipher.init(Cipher.ENCRYPT_MODE, key, ivSpec);
cipher.init(Cipher.ENCRYPT_MODE, key);
return new String(Base64.getEncoder().encode(cipher.doFinal(plainTextBytes)));
}
public static String decryptString(SecretKey key, String
cipherText) throws NoSuchProviderException,
NoSuchAlgorithmException, NoSuchPaddingException,
InvalidKeyException, InvalidAlgorithmParameterException,
IllegalBlockSizeException, BadPaddingException,
UnsupportedEncodingException, ShortBufferException {
Key decryptionKey = new SecretKeySpec(key.getEncoded(),
key.getAlgorithm());
IvParameterSpec ivSpec = new IvParameterSpec(ivString.getBytes("UTF-8"));
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding", "BC");//AES/GCM/NoPadding", "BC");
cipher.init(Cipher.DECRYPT_MODE, decryptionKey, ivSpec);
return new String (Base64.getEncoder().encode(cipher.doFinal(Base64.getDecoder().decode(cipherText.getBytes()))));
}
You must use exactly the same IV for encryption and decryption of the same ciphertext and it must be different for each encryption that produces different ciphertexts. The IV is not secret, so you can send it along with the ciphertext. Usually, it is simply prepended to the ciphertext and sliced off before decryption.
You need to supply an instance of GCMParameterSpec (which includes the IV) for both of the Cipher.init calls. As has already been pointed out, the IV has to be the same for both encryption and decryption, and must be unique.
Related
I'm trying to encrypt and decrypt some texts using Cipher with the "AES/CBC/PKCS5Padding" algorithm but if I restart the application the text that was encrypt can't be decrypted.
I'm encrypting the text, transforming the encrypted bytes in base64 text, storing it and retrieving it when necessary, so transforming the base64 text in bytes and trying to decrypt to take the original text.
The code I'm using is:
private static SecretKey getKeyFromPassword(String password, String salt)
throws NoSuchAlgorithmException, InvalidKeySpecException {
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
KeySpec spec = new PBEKeySpec(password.toCharArray(), salt.getBytes(UTF_8),
65536, 256);
SecretKey secret = new SecretKeySpec(factory.generateSecret(spec)
.getEncoded(), "AES");
return secret;
}
private static IvParameterSpec generateIv() {
byte[] iv = new byte[16];
new SecureRandom().nextBytes(iv);
return new IvParameterSpec(iv);
}
public static void main(String[] args) throws NoSuchAlgorithmException, InvalidKeySpecException, InvalidAlgorithmParameterException, InvalidKeyException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException {
// string for test
String teste = "teste teste teste teste";
//getting start with Cipher
SecretKey secretKey = getKeyFromPassword("pass", "salt");
IvParameterSpec ivParameterSpec = generateIv();
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
//encrypting
cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivParameterSpec);
byte[] cipherText = new byte[0];
cipherText = cipher.doFinal(teste.getBytes(UTF_8));
// encrypt to base64 text
String criptado = Base64.getEncoder().encodeToString(cipherText);
//decripting
byte[] plainText = new byte[0];
byte[] rawText = Base64.getDecoder().decode(criptado);
cipher.init(Cipher.DECRYPT_MODE, secretKey, ivParameterSpec);
plainText = cipher.doFinal(rawText);
String decriptado = new String(plainText);
The problem is something with the size of the bit key? Like in this topic: java AES/CBC/PKCS5PADDING in php (AES-256-CBC) resulting different result
I took this guide to the code: baeldung.com/java-aes-encryption-decryption
I have this java code for encryption and decryption, which I want to change/convert to Ruby code. I looked up in OpenSSL gem but dint find the "RSA/ECB/OAEPWithSHA-256AndMGF1Padding" combination available for ruby. How do I implement it?
public class EncryptDecryptService {
public String encryptRequestObject(RequestObject requestObject) throws UnsupportedEncodingException, FileNotFoundException, CertificateException, InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException {
PublicKey publicKey = getPublicKey(requestObject.getKeyFilename());
byte[] message = requestObject.getString().getBytes("UTF-8");
byte[] secret = encrypt(publicKey, message);
return Base64.encodeBase64String(secret);
}
public String decryptRequestObject(RequestObject requestObject) throws UnrecoverableKeyException, KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException, InvalidKeyException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException {
PrivateKey privateKey = getPrivateKey(requestObject.getKeyFilename(), requestObject.getKeyPassword());
byte[] cipherText = Base64.decodeBase64(requestObject.getString());
byte[] decrypted = decrypt(privateKey, cipherText);
return new String(decrypted, "UTF-8");
}
private PublicKey getPublicKey(String filename) throws FileNotFoundException, CertificateException {
FileInputStream fin = new FileInputStream(filename);
CertificateFactory factory = CertificateFactory.getInstance("X.509");
X509Certificate certificate = (X509Certificate) factory.generateCertificate(fin);
PublicKey publicKey = certificate.getPublicKey();
return publicKey;
}
private PrivateKey getPrivateKey(String filename, String password) throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException, UnrecoverableKeyException {
FileInputStream fin = new FileInputStream(filename);
KeyStore ks = KeyStore.getInstance("pkcs12");
ks.load(fin, password.toCharArray());
String str = ks.aliases().nextElement();
PrivateKey privateKey = (PrivateKey) ks.getKey(str, password.toCharArray());
return privateKey;
}
private byte[] encrypt(PublicKey key, byte[] plainText) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding");
cipher.init(Cipher.ENCRYPT_MODE, key);
return cipher.doFinal(plainText);
}
private byte[] decrypt(PrivateKey key, byte[] cipherText) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding");
cipher.init(Cipher.DECRYPT_MODE, key);
return cipher.doFinal(cipherText);
}
}
OAEP uses several parameters, including two digests, one for OAEP (i.e. for hashing the OAEP label) and one for the mask generation function (MGF1), see RFC8017, sec. 7.1.
The identifier RSA/ECB/OAEPWithSHA-256AndMGF1Padding is ambiguous and depends on the provider. For example the SunJCE provider uses SHA-256 as OAEP digest and SHA-1 as MGF1 digest, the BouncyCastle provider uses SHA-256 for both digests.
The following is an example of the encryption with the Java code and the decryption with the Ruby code (the opposite direction is analog).
On the Java side the SunJCE provider is used WLOG and the digests involved are determined:
String pubKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDNvs/qUMjkfq2E9o0qn03+KJE7" +
"ASczEbn6q+kkthNBdmTsskikWsykpDPnLWhAVkmjz4alQyqw+mHYP9xhx8qUC4A3" +
"tXY0ObxANUUKhUvR7zNj4vk4t8F2nP3erWvaG8J+sN3Ubr40ZYIYLS6UHYRFrqRD" +
"CDhUtyjwERlz8KhLyQIDAQAB";
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(Base64.getDecoder().decode(pubKey));
RSAPublicKey publicKey = (RSAPublicKey) keyFactory.generatePublic(keySpec);
byte[] plaintext = "The quick brown fox jumps over the lazy dog".getBytes(StandardCharsets.UTF_8);
byte[] ciphertext = encrypt(publicKey, plaintext);
System.out.println("Ciphertext: " + Base64.getEncoder().encodeToString(ciphertext));
with
private static byte[] encrypt(PublicKey key, byte[] plainText) throws Exception {
Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding");
cipher.init(Cipher.ENCRYPT_MODE, key);
OAEPParameterSpec oaepParameterSpec = cipher.getParameters().getParameterSpec(OAEPParameterSpec.class);
MGF1ParameterSpec mgf1ParameterSpec = (MGF1ParameterSpec)oaepParameterSpec.getMGFParameters();
System.out.println("Provider : " + cipher.getProvider().getName());
System.out.println("OAEP-Hash : " + oaepParameterSpec.getDigestAlgorithm());
System.out.println("MGF1-Hash : " + mgf1ParameterSpec.getDigestAlgorithm());
return cipher.doFinal(plainText);
}
which corresponds to the posted encrypt() method (except for the additional output). The code produces (e.g.) the following output:
Provider : SunJCE
OAEP-Hash : SHA-256
MGF1-Hash : SHA-1
Ciphertext: WlozD9ojNRQafip41dpuuhBMe7ruH2FBWnMhbAaSuAtPDpHOUyKaAm6mO15BbvL3eTXyqfEQx29dYPJEbUr5T/WXs846PQN6g7Yv25EXGVbPCzc4aIbms76C1jP92wXNEGWMnu624Fq5W9MVXX75mfaY0Fjvrh5k/TFuO4AIxMk=
For completeness it should be mentioned that an explicit specification of the parameters is also possible with:
Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPPadding");
OAEPParameterSpec oaepParameterSpec = new OAEPParameterSpec("SHA-256", "MGF1", new MGF1ParameterSpec("SHA-1"), PSource.PSpecified.DEFAULT);
cipher.init(Cipher.ENCRYPT_MODE, key, oaepParameterSpec);
whereby this explicit specification is the more robust alternative because of the ambivalence described above.
After the digests have been determined (either because the provider is known or explicitly with the above output) a Ruby implementation can be made.
A possible OAEP implementation for Ruby is openssl-oaep.
With this, the Ruby code for decryption can be implemented as follows:
require 'openssl'
require 'openssl/oaep'
require 'base64'
private_key =
'-----BEGIN PRIVATE KEY-----
MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBAM2+z+pQyOR+rYT2
jSqfTf4okTsBJzMRufqr6SS2E0F2ZOyySKRazKSkM+ctaEBWSaPPhqVDKrD6Ydg/
3GHHypQLgDe1djQ5vEA1RQqFS9HvM2Pi+Ti3wXac/d6ta9obwn6w3dRuvjRlghgt
LpQdhEWupEMIOFS3KPARGXPwqEvJAgMBAAECgYADxGqqL7B9/pPOy3TqQuB6tuNx
4SOGm9x76onqUisoF7LhYqJR4Be/LAKHSR2PkATpKvOcMw6lDvCbtQ+j+rSK2PkN
4iDi1RYqbLUbZBS8vhrgU0CPlmgSSp1NBsqMK9265CaJox3frxmBK1yuf22RboIK
pqOzcluuA4aqLegmwQJBAP0+gM/tePzx+53DrxpYQvlfi9UJo7KeqIFL8TjMziKt
EaRGeOZ6UX/r6CQHojYKnNti7pjAwonsdwCTcv1yy7sCQQDP+/ww49VFHErON/MO
w5iYCsrM5Lx+Yc2JAjetCDpkMrRT92cgQ0nxR5+jNeh+gE2AmB9iKlNxsHJoRaPQ
lBRLAkEAl9hiZEp/wStXM8GhvKovfldMAPFGtlNrthtTCDvFXgVoDpgy5f9x3sIU
74WkPcMfSmyHpA/wlcKzmCTRTicHAQJBALUjq7MQ2tAEIgqUo/W52I6i55mnpZsU
pyOqcL8cqW5W0sNGd+SbdizTym8lJkX2jIlw8/RVFLOxjxLNhCzGqx0CQQDeUMnw
7KGP3F7BnbsXCp64YDdihzSO5X/Mfwxw6+S/pyKZ0/X4uwt24kZuoDnFzGWJYlea
sDQC6enIru+ne5es
-----END PRIVATE KEY-----'
key = OpenSSL::PKey::RSA.new(private_key)
label = ''
md_oaep = OpenSSL::Digest::SHA256
md_mgf1 = OpenSSL::Digest::SHA1
cipher_text_B64 = 'WlozD9ojNRQafip41dpuuhBMe7ruH2FBWnMhbAaSuAtPDpHOUyKaAm6mO15BbvL3eTXyqfEQx29dYPJEbUr5T/WXs846PQN6g7Yv25EXGVbPCzc4aIbms76C1jP92wXNEGWMnu624Fq5W9MVXX75mfaY0Fjvrh5k/TFuO4AIxMk='
cipher_text = Base64.decode64(cipher_text_B64)
plain_text = key.private_decrypt_oaep(cipher_text, label, md_oaep, md_mgf1)
print(plain_text) # The quick brown fox jumps over the lazy dog
with the original plaintext as output.
I wrote a simple Encryption and Decryption helper class for my android app to encrypt and store Strings securely.
It consists of a single static public method to encrypt, then it calls a private static method to decrypt the encrypted message and returns it. I wrote the method this way to check if the message is intact after encryption/decryption.
I wrote a simple JUnit test with a String and called AssertEquals on the String before and after sending it to the Crypto encryption method.
I get this following errors from running the test:
javax.crypto.AEADBadTagException: Tag mismatch!
The error stack:
at com.sun.crypto.provider.GaloisCounterMode.decryptFinal(GaloisCounterMode.java:571)
at com.sun.crypto.provider.CipherCore.finalNoPadding(CipherCore.java:1046)
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:983)
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:845)
at com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:446)
at javax.crypto.Cipher.doFinal(Cipher.java:2165)
at util.Crypto.decrypt(Crypto.java:94)
at util.Crypto.encrypt(Crypto.java:64)
at com.example.ali.meappley.CryptoTest.encryptAndDecryptTest(CryptoTest.java:29)
I'm new to cryptography, but I read different stackoverflow replies and couldn't find anything of help. Some users suggested calling cipher.update(someByteArray) before calling cipher.doFinal(someByteArray) but I couldnt manage to get it working. Any suggestions?
This is my helper class
public class Crypto {
//public methods
//public static encrypt method
public static String encrypt(String messageToEncrypt, #Nullable byte[] associatedData) throws NoSuchPaddingException,
NoSuchAlgorithmException,
InvalidAlgorithmParameterException,
InvalidKeyException,
BadPaddingException,
IllegalBlockSizeException {
byte[] plainBytes = messageToEncrypt.getBytes();
/////////////////////////////////////////////////////////////////
SecureRandom secureRandom = new SecureRandom();
byte[] key = new byte[16];
secureRandom.nextBytes(key);
SecretKey secretKey = new SecretKeySpec(key, "AES");
byte[] iv = new byte[12]; //NEVER REUSE THIS IV WITH SAME KEY
secureRandom.nextBytes(iv);
final Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
GCMParameterSpec parameterSpec = new GCMParameterSpec(128, iv); //128 bit auth tag length
cipher.init(Cipher.ENCRYPT_MODE, secretKey, parameterSpec);
if (associatedData != null) {
cipher.updateAAD(associatedData);
}
byte[] cipherText = cipher.doFinal(plainBytes);
ByteBuffer byteBuffer = ByteBuffer.allocate(4 + iv.length + cipherText.length);
byteBuffer.putInt(iv.length);
byteBuffer.put(iv);
byteBuffer.put(cipherText);
byte[] cipherMessage = byteBuffer.array();
Arrays.fill(key,(byte) 0); //overwrite the content of key with zeros
///////////////////////////////////////////////////////////////////
byte[] decrypted = decrypt(cipherMessage, null, key);
return decrypted.toString();
}
//public static decrypt method
private static byte[] decrypt(byte[] cipherMessage, #Nullable byte[] associatedData, byte[] key) throws NoSuchPaddingException,
NoSuchAlgorithmException,
InvalidAlgorithmParameterException,
InvalidKeyException,
BadPaddingException,
IllegalBlockSizeException {
ByteBuffer byteBuffer = ByteBuffer.wrap(cipherMessage);
int ivLength = byteBuffer.getInt();
if(ivLength < 12 || ivLength >= 16) { // check input parameter
throw new IllegalArgumentException("invalid iv length");
}
byte[] iv = new byte[ivLength];
byteBuffer.get(iv);
byte[] cipherText = new byte[byteBuffer.remaining()];
byteBuffer.get(cipherText);
final Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key, "AES"), new GCMParameterSpec(128, iv));
if (associatedData != null) {
cipher.updateAAD(associatedData);
}
cipher.update(cipherText);
byte[] plainText= cipher.doFinal(cipherText);
return plainText;
}
There are a few issues with your code:
1) In your encrypt-method remove the following line (or shift it behind the decrypt-call).
Arrays.fill(key, (byte) 0); // overwrite the content of key with zeros
Otherwise the key for encryption and decryption differ.
2) In your encrypt-method also pass the associatedData in your decrypt-call i.e. replace
byte[] decrypted = decrypt(cipherMessage, null, key);
with
byte[] decrypted = decrypt(cipherMessage, associatedData, key);
The associatedData passed for encryption and decryption have to match for validity. For the purpose of the associatedData see e.g. https://crypto.stackexchange.com/questions/6711/how-to-use-gcm-mode-and-associated-data-properly
3) In your decrypt-method remove the line
cipher.update(cipherText);
For the purpose of the update-method see e.g. What does cipher.update do in java?
All three issues give rise to an AEADBadTagException.
4) I suspect for testing purposes your encrypt-method returns decrypted.toString() which however only gives you the object's class and hashcode. It would make more sense to return e.g. new String(decrypted).
I'm searching a known encryption algorithm that would let me encrypt data with a key and if the data is decrypted with another key would give me data that is different from the first one. It's string data. I tried AES but the problem is that the result of decryption using a wrong key gives a lot of invalid symbols so the resulting String is differentiable from a result given with a good key.
Is there a work around to this?
I did this so far:
private static final String truc = "f41a3ff27aab7d5c";
public static String encryptPass(String pass,String key) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, UnsupportedEncodingException, InvalidAlgorithmParameterException {
MessageDigest md = MessageDigest.getInstance("SHA-256");
md.update(key.getBytes("UTF-8"));
byte[] digest = md.digest();
BCrypt bcrypt = new BCrypt();
SecretKey keyL = new SecretKeySpec(digest, "AES");
Cipher AesCipher = Cipher.getInstance("AES/CTR/NoPadding");
AesCipher.init(Cipher.ENCRYPT_MODE, keyL, new IvParameterSpec(truc.getBytes()));
byte[] encVal = AesCipher.doFinal(pass.getBytes());
pass = Base64.encodeToString(encVal, Base64.DEFAULT);
Log.i("ADA", "encoded pass: " + pass);
return pass;
}
public static String decryptPass(String encPass , String key) throws NoSuchAlgorithmException, UnsupportedEncodingException, NoSuchPaddingException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, InvalidAlgorithmParameterException {
MessageDigest md = MessageDigest.getInstance("SHA-256");
md.update(key.getBytes("UTF-8"));
byte[] digest = md.digest();
SecretKey keyL = new SecretKeySpec(digest, "AES");
Cipher AesCipher = Cipher.getInstance("AES/CTR/NoPadding");
AesCipher.init(Cipher.DECRYPT_MODE, keyL, new IvParameterSpec(truc.getBytes()));
byte[] decodedValue = Base64.decode(encPass, Base64.DEFAULT);
byte[] decValue = AesCipher.doFinal(decodedValue);
String decryptedValue = new String(decValue);
Log.i("ADA", "decrpyted pass: " + decryptedValue);
return decryptedValue;
}
After reading the answer of MaybeWeCouldStartAVar, last paragraph I used "AES/CTR/NoPadding".
When I'm saying a well formed String I'm expecting mostly ASCII chars 32 to 125.
Is there something out there that would respond to my needs, or should I just roll my own encryption algorithm (I heard it's not advised but if it's my only option well..)?
I'm not trying to restrict access to any data. Data is fully visible by anyone who would use the app but unless they have the right key they should see erroneous data (that don't obviously look erroneous).
The idea is to restrain brute force.
I am not an expert on this so I need to defer to an expert. Is the following example a reasonably secure way to encrypt and decrypt a message (of an unknown length) for transmission a potentially insecure network (i.e. Email, HTTP requests, or other means). By "reasonably secure" I mean, would prevent a casual, or semi determined third party from reading the message.
Encrypt a message with a random AES key, and protect AES key by encrypting it with a public key.
public static String encrypt(String data, PublicKey publicKey) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
// Create AES secret key
Cipher aes = Cipher.getInstance("AES");
KeyGenerator kgen = KeyGenerator.getInstance("AES");
kgen.init(256);
SecretKey key = kgen.generateKey();
SecretKeySpec aeskeySpec = new SecretKeySpec(key.getEncoded(), "AES");
// Encrypt data with AES Secret key
aes.init(Cipher.ENCRYPT_MODE, aeskeySpec);
byte[] dataEncoded = aes.doFinal(data.getBytes());
// Encrypt the secret AES key with the public key
Cipher rsa = Cipher.getInstance("RSA");
rsa.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] aesKeyEncoded = rsa.doFinal(key.getEncoded());
// Output both secret AES key and data
return
Base64.getEncoder().encodeToString(aesKeyEncoded) + "~" +
Base64.getEncoder().encodeToString(dataEncoded);
}
Decrypt the AES secret key, and then decrypt the message:
public static String decrypt(String data, PrivateKey privateKey) throws InvalidKeyException, NoSuchPaddingException, NoSuchAlgorithmException, BadPaddingException, IllegalBlockSizeException {
String[] parts = data.split("~");
// Decrypt AES secret key
byte[] encodedSecretKey = Base64.getDecoder().decode(parts[0]);
Cipher rsa = Cipher.getInstance("RSA");
rsa.init(Cipher.DECRYPT_MODE, privateKey);
byte[] decodedSecretKey = rsa.doFinal(encodedSecretKey);
SecretKeySpec key = new SecretKeySpec(decodedSecretKey, "AES");
// Decrypt message
Cipher aes = Cipher.getInstance("AES");
aes.init(Cipher.DECRYPT_MODE, key);
byte[] decodedData = aes.doFinal(Base64.getDecoder().decode(parts[1]));
return new String(decodedData);
}
Using the above methods:
public static void main(String args[]) throws NoSuchAlgorithmException, BadPaddingException, NoSuchPaddingException, IllegalBlockSizeException, InvalidKeyException {
// Generate public/private key
KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");
generator.initialize(2048, new SecureRandom());
KeyPair kp = generator.generateKeyPair();
System.out.println(" Public key = " + Base64.getEncoder().encodeToString(kp.getPublic().getEncoded()));
System.out.println("Private key = " + Base64.getEncoder().encodeToString(kp.getPrivate().getEncoded()));
String mytext = "test message with some test data.";
String e = encrypt(mytext, kp.getPublic());
String d = decrypt(e, kp.getPrivate());
System.out.println(" text = " + mytext);
System.out.println("Decoded text = " + d);
}
As long as you can trust the RSA public key the general idea is OK. If you just send the public key to the other side, then it is not.
You also need to protect your ciphertext by adding integrity and authenticity. You can easily do this by switching to AES / GCM mode (which is only available in Java 8, or using Bouncy Castle). Currently you are using the unsafe AES / ECB mode of encryption.
You should try and use RSA with OAEP padding, instead of PKCS#1 v1.5 padding. In general, you should not rely on default character encodings (getBytes()) or cipher modes.
So in the end: no, that's not secure. Try and use TLS is you want to avoid the many pitfalls.