Encrypt data with RSA public key in Java and decrypt in Crypto++ - java

I'm trying to encrypt data with RSA public key in Java and decrypt it in Crypto++. It results in an error:
"RSA/EME-PKCS1-v1_5: ciphertext length of 24 doesn't match the required length of 128 for this key"
What am I doing wrong?
Java:
String cipher = Encryption.encryptStrRSA(txt, pubKeyk);
public static String encryptStrRSA(String str, PublicKey pubKey)
throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException,
IllegalBlockSizeException, BadPaddingException, NoSuchProviderException {
Cipher cipher = Cipher.getInstance("RSA/NONE/PKCS1Padding", "BC");
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
byte[] encryptedAesKey = cipher.doFinal(str.getBytes());
String cipherStr = new String(encryptedAesKey);
System.out.println(cipherStr);
return cipherStr;
}
public static PublicKey strToPublicKey(String key64) throws GeneralSecurityException {
byte[] data = Base64.getDecoder().decode(key64);
X509EncodedKeySpec spec = new X509EncodedKeySpec(data);
KeyFactory fact = KeyFactory.getInstance("RSA");
return fact.generatePublic(spec);
}
public static String publicKeyToStr(PublicKey publ) throws GeneralSecurityException {
KeyFactory fact = KeyFactory.getInstance("RSA");
X509EncodedKeySpec spec = fact.getKeySpec(publ, X509EncodedKeySpec.class);
return Base64.getEncoder().encode(spec.getEncoded()).toString();
}
Crypto++:
using namespace CryptoPP;
RSAES_PKCS1v15_Decryptor priv(privString);
StringSource( cipher, cipherSize, true, new
Base64Decoder( new PK_DecryptorFilter(randPool, priv, new StringSink(sdata))));

It is dangerous to use String instances for keeping binary data -- you should use byte[] instead.
Additionally, in the java code there is no Base64 wrapping of the resulting ciphertext, but in the C++ code it is being unwrapped from Base64.
Modified your code to return byte[] and encode the result using Base64:
public static byte[] encryptRSA(String str, PublicKey pubKey) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, NoSuchProviderException {
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding", "BC");
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
return cipher.doFinal(str.getBytes());
}
String cipher = Base64.getEncoder().encodeToString(Encryption.encryptRSA("0123456789ABCDEF", pubKeyk));
Then you can decrypt in Crypto++ the same way you did.
Good luck!

Related

How to decrypt JSON data in android from node js

I try to decrypt to json response in Android from node js server and it does not decrypt it correctly. But it decrypted correctly a string or JSONArray. When i decrypt json object in node js from android, it decrypts correctly. Can you help me to understand what is wrong?
Node js
function encryptDataTestWork(text, masterkey) {
// body...
// random initialization vector
const iv = crypto.randomBytes(16);
// random salt
const salt = crypto.randomBytes(64);
// derive encryption key: 32 byte key length
// in assumption the masterkey is a cryptographic and NOT a password there is no need for
// a large number of iterations. It may can replaced by HKDF
// the value of 2145 is randomly chosen!
const key = crypto.pbkdf2Sync(masterkey, salt, 2145, 32, 'sha512');
// AES 256 GCM Mode
const cipher = crypto.createCipheriv('aes-256-gcm', key, iv);
// encrypt the given text
const encrypted = Buffer.concat([
cipher.update(text, 'utf8'),
cipher.final()
]);
// extract the auth tag
const tag = cipher.getAuthTag();
// generate output
return Buffer.concat([salt, iv, tag, encrypted]).toString('base64');
};
let item = JSON.stringify({name:'Selemani',lastName:'Jimmy'});
let generatedKey = 'SEXFgk1kQ3BcDzrH';
let encryptedMobile = encryptDataTestWork(item, generatedKey);
console.log('data->[encrypted] -> '+encryptedMobile);
res.send({tag: 'success', data: encryptedMobile, key: generatedKey});
And Android code
private final static int GCM_TAG_LENGTH = 16;
public static String decryptHelper(String algorithm, byte[] cipherText, byte[] tag,SecretKey key,
GCMParameterSpec gcmParameterSpec) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
Cipher cipher = Cipher.getInstance(algorithm);
cipher.init(Cipher.DECRYPT_MODE, key, gcmParameterSpec);
cipher.update(cipherText);
byte[] plainText = cipher.doFinal(tag);
return new String(plainText, StandardCharsets.UTF_8);
}
public static String decrypt(String encData, String masterKey) throws NoSuchPaddingException, InvalidKeyException, NoSuchAlgorithmException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException, InvalidKeySpecException {
byte[] cipherText;
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
cipherText = Base64.getDecoder().decode(encData.getBytes(StandardCharsets.UTF_8));
}else{
cipherText = android.util.Base64.decode(encData.getBytes(StandardCharsets.UTF_8), android.util.Base64.DEFAULT);
}
byte[] salt = Arrays.copyOfRange(cipherText, 0, 64);
byte[] iv = Arrays.copyOfRange(cipherText, 64, 80);
byte[] tag = Arrays.copyOfRange(cipherText, 80, 96);
byte[] ciphertext = Arrays.copyOfRange(cipherText, 96, cipherText.length);
SecretKey key = getKeyFromPassword(masterKey, salt);
return decryptHelper("AES/GCM/NoPadding", ciphertext, tag, key, new GCMParameterSpec(GCM_TAG_LENGTH * 8, iv));
}
Here is what i see in logs
Data Response: {"tag":"success","data":"yMiFnU7JNhCtFY1buCO5kGgj8rOm3L+iAr9JxBwziMiPes4mHctcvX+V2crOncOQeLKikGo+RY82mOrKu4DWhhmejdI+/UDHWYqs2k54w4SDED8IeJzZ+1kM5mgB+WMMWI6zb5+9r6TAb6ThBFoE6Ot3dajtvVUe6LwGGiUugViNCGtu","key":"SEXFgk1kQ3BcDzrH"}
2022-04-30 12:29:46.298 28249-28281/com.hello.app E/HttpConnexion: n(JSON_OBJECT=key): SEXFgk1kQ3BcDzrH
2022-04-30 12:29:46.337 28249-28281/com.hello.app E/HttpConnexion: Decrypted: "lastName":"Jimmy"}// decrypted text i get. It should be {name:'Selemani',lastName:'Jimmy'}
2022-04-30 12:29:46.338 28249-28281/com.hello.app W/System.err: org.json.JSONException: Value lastName of type java.lang.String cannot be converted to JSONObject
If i send a string like "Hello World", it correctly decrypts.
I did what #Topaco said and it worked!
public static String decryptHelper(String algorithm, byte[] cipherText, byte[] tag,SecretKey key,
GCMParameterSpec gcmParameterSpec) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, IOException {
Cipher cipher = Cipher.getInstance(algorithm);
cipher.init(Cipher.DECRYPT_MODE, key, gcmParameterSpec);
byte[] plain = cipher.update(cipherText);
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
outputStream.write(plain);
byte[] plainText = cipher.doFinal(tag);
outputStream.write(plainText);
return new String(outputStream.toByteArray(), StandardCharsets.UTF_8);
}
Thank you! #Topaco You saved me!

bad base64 error during decrypting on AES

I'm trying to encrypt and decrypt some text using AES algorithm like :
private static final String ALGORITHM = "AES";
private static final String MODE = "AES/CBC/PKCS7Padding";
public String encrypt(String value, String key) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(), ALGORITHM);
Cipher cipher = Cipher.getInstance(MODE);
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, new IvParameterSpec(key.getBytes()));
byte[] values = cipher.doFinal(value.getBytes());
return Base64.encodeToString(values, Base64.URL_SAFE);
}
public String decrypt(String value, String key) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
byte[] values = Base64.decode(value, Base64.DEFAULT);
SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(), ALGORITHM);
Cipher cipher = Cipher.getInstance(MODE);
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, new IvParameterSpec(key.getBytes()));
return new String(cipher.doFinal(values));
}
The encrypting code works perfectly fine but when I'm trying to decrypt the encrypted text it returns a bad base64 error.
What I tried to do before:
I already tried to change Base64.DEFAULT to Base64.URL_SAFE but it gave me the same error.
Also, I tried to replace "/" and "+" with "_" and "-" and it doesn't work either.
Heres the value I'm encrypted and trying to decrypt:
Ssg2w+dv7es7/wWAeAcoAOSVnYKsoLlefbmS8tYr+jc=
Thanks for helping...

Password based AES Encryption and Decryption - BadPaddingException

everyone.
I am trying to encrypt and decrypt a string with an AES symmetric key, generated with a password. My current code for generating this follows below:
public class AESUtils {
public static SecretKey getKeyFromPassword(String password, String salt)
throws NoSuchAlgorithmException, InvalidKeySpecException {
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
KeySpec spec = new PBEKeySpec(password.toCharArray(), salt.getBytes(), 65536, 256);
return new SecretKeySpec(factory.generateSecret(spec)
.getEncoded(), "AES");
}
public static IvParameterSpec generateIv() {
byte[] iv = new byte[16];
new SecureRandom().nextBytes(iv);
return new IvParameterSpec(iv);
}
public static String encryptPasswordBased(String plainText, SecretKey key, IvParameterSpec iv)
throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException,
InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, key, iv);
return Base64.getEncoder().encodeToString(cipher.doFinal(plainText.getBytes()));
}
public static String decryptPasswordBased(String cipherText, SecretKey key, IvParameterSpec iv)
throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException,
InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, key, iv);
return new String(cipher.doFinal(Base64.getDecoder().decode(cipherText)));
}
}
The code to generate the encrypted string:
AESUtils.encryptPasswordBased(string_content_plain, AESUtils.getKeyFromPassword("password", "salt"), AESUtils.generateIv());
The code to generate the decrypted string:
AESUtils.decryptPasswordBased(string_content_encrypted, AESUtils.getKeyFromPassword("password", "salt"), AESUtils.generateIv());
The encryptPasswordBased works fine, but when I use the decryptPasswordBased, it always raises javax.crypto.BadPaddingException with the message: Given final block not properly padded. Such issues can arise if a bad key is used during decryption.
What can I do? The generated key is always the same. I have compared it with both byte arrays.
Thanks
As #Topaco said, the solution was to use the same IV when decrypting the content. The generation of a new one would make it impossible to decrypt.

AES vs PBEWithSHA256And256BitAES

I need to encrypt some data with a password. It has to be a variation of AES with a 256bit key.
I searched a while on the web and came up with this two alogrithms. Now I do not know, which one to choose, cause I do not know, which one is 'saver'.
The first one is the PBEWithSHA256And256BitAES-CBC-BC:
public static byte[] encrypt(String plainText, char[] password, byte[] salt) throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException, NoSuchProviderException {
PBEParameterSpec pbeParamSpec = new PBEParameterSpec(salt, 2048);
PBEKeySpec pbeKeySpec = new PBEKeySpec(password);
SecretKeyFactory keyFac = SecretKeyFactory.getInstance("PBEWithSHA256And256BitAES-CBC-BC", "BC");
SecretKey pbeKey = keyFac.generateSecret(pbeKeySpec);
Cipher encryptionCipher = Cipher.getInstance("PBEWithSHA256And256BitAES-CBC-BC", "BC");
encryptionCipher.init(Cipher.ENCRYPT_MODE, pbeKey, pbeParamSpec);
return encryptionCipher.doFinal(plainText.getBytes());
}
The other one generates the Key with PBEWithSHA256And256BitAES-CBC-BC, but encrypts with AES:
public static byte[] encrypt(String plainText, char[] password, byte[] salt) throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException, NoSuchProviderException {
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBEWithSHA256And256BitAES-CBC-BC", "BC");
KeySpec spec = new PBEKeySpec(password, salt, 2048, 256);
SecretKey key = new SecretKeySpec(factory.generateSecret(spec).getEncoded(), "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, key);
return cipher.doFinal(plainText.getBytes());
}
So, which one - and why - is the more secure one? And what is the difference between them?
You should certainly specify a mode of operation for your block cipher. That's the "CBC" part of cipher in the BC implementation. Otherwise, you will default to ECB mode, which has simple codebook replay attack possible! So, long story short - don't use the bottom code snip, prefer the top one.
It could be fixed up to operate similar to how the BC implementation does by specifying mode of operation and other parameters - but honestly just use the BC if you don't know about this stuff - they've done the work and those providers are ready to use as you want "out of the box".

AES Encryption Java -> PHP -> Java

In my Android app I am communicating with a web service the data sent and responded are encrypted with AES encryption.
So what I do is the following. I'm sending a base64 encoded AES encrypted JSON String to share.php
Share.php will then decrypt this string and insert it into the database. After that the PHP will encrypt en encode the response.
My Android application then needs to decode en decrypt this message.
But the decryption of the PHP response is not going very well.
This is my AES.java:
public class AES {
private final String characterEncoding = "UTF-8";
private final String cipherTransformation = "AES/ECB/PKCS5Padding";
private final String aesEncryptionAlgorithm = "AES";
public byte[] decrypt(byte[] cipherText, byte[] key, byte [] initialVector) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException
{
Cipher cipher = Cipher.getInstance(cipherTransformation);
SecretKeySpec secretKeySpecy = new SecretKeySpec(key, aesEncryptionAlgorithm);
//IvParameterSpec ivParameterSpec = new IvParameterSpec(initialVector);
//cipher.init(Cipher.DECRYPT_MODE, secretKeySpecy, ivParameterSpec);
cipher.init(Cipher.DECRYPT_MODE, secretKeySpecy);
System.out.println("Do final: "+cipherText);
cipherText = cipher.doFinal(cipherText);
return cipherText;
}
public byte[] encrypt(byte[] plainText, byte[] key, byte [] initialVector) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException
{
Cipher cipher = Cipher.getInstance(cipherTransformation);
SecretKeySpec secretKeySpec = new SecretKeySpec(key, aesEncryptionAlgorithm);
//IvParameterSpec ivParameterSpec = new IvParameterSpec(initialVector);
//cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
plainText = cipher.doFinal(plainText);
return plainText;
}
private byte[] getKeyBytes(String key) throws UnsupportedEncodingException{
byte[] keyBytes= new byte[16];
byte[] parameterKeyBytes= key.getBytes(characterEncoding);
System.arraycopy(parameterKeyBytes, 0, keyBytes, 0, Math.min(parameterKeyBytes.length, keyBytes.length));
return keyBytes;
}
/// <summary>
/// Encrypts plaintext using AES 128bit key and a Chain Block Cipher and returns a base64 encoded string
/// </summary>
/// <param name="plainText">Plain text to encrypt</param>
/// <param name="key">Secret key</param>
/// <returns>Base64 encoded string</returns>
public String encrypt(String plainText, String key) throws UnsupportedEncodingException, InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException{
byte[] plainTextbytes = plainText.getBytes(characterEncoding);
byte[] keyBytes = getKeyBytes(key);
//return Base64.encodeToString(encrypt(plainTextbytes,keyBytes, keyBytes), Base64.DEFAULT);
return Base64.encodeToString(encrypt(plainTextbytes,keyBytes, new byte[0]), Base64.DEFAULT);
}
/// <summary>
/// Decrypts a base64 encoded string using the given key (AES 128bit key and a Chain Block Cipher)
/// </summary>
/// <param name="encryptedText">Base64 Encoded String</param>
/// <param name="key">Secret Key</param>
/// <returns>Decrypted String</returns>
public String decrypt(String encryptedText, String key) throws KeyException, GeneralSecurityException, GeneralSecurityException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException, IOException{
byte[] cipheredBytes = Base64.decode(encryptedText, Base64.DEFAULT);
byte[] keyBytes = getKeyBytes(key);
//return new String(decrypt(cipheredBytes, keyBytes, keyBytes), characterEncoding);
return new String(decrypt(cipheredBytes, keyBytes, new byte[0]), characterEncoding);
}
}
And this is the code to encode en encrypt the response in PHP:
function mc_encrypt($encrypt, $mc_key) {
$iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_ECB), MCRYPT_RAND);
$passcrypt = trim(mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $mc_key, trim($encrypt), MCRYPT_MODE_ECB, $iv));
$encode = base64_encode($passcrypt);
return $encode;
}
function mc_decrypt($decrypt, $mc_key) {
$decoded = base64_decode($decrypt);
$iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_ECB), MCRYPT_RAND);
$decrypted = trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $mc_key, trim($decoded), MCRYPT_MODE_ECB, $iv));
return $decrypted;
}
I'm guessing that the settings of the PHP encryption do not match the settings for the Java part. Can
I'm getting the following error:
03-12 13:44:09.661: W/System.err(15717): javax.crypto.BadPaddingException: pad block corrupted
I suggest you take a look at http://phpaes.com/. It's a free AES encryption library implemented purely in PHP; it's fast and very very simple to use.
At the very least, it allows you get one step closer to isolating the true source of the issue.
This might not be the answer you're looking for - but is there a specific reason you're manually encrypting this data instead of using SSL/HTTPS?
In most cases HTTPS will be easier to implement and more secure than manually implementing a symmetric cipher.

Categories