I have below NodeJS code for decryption and it is working perfectly fine but when I am trying to convert the same code in Java at that time I am getting below error.
Given final block not properly padded. Such issues can arise if a bad key is used during decryption
Node JS code snippet:
let textParts = text.split(':');
let iv = Buffer.from(textParts.shift(), 'hex');
let encryptedText = Buffer.from(textParts.join(':'), 'hex');
let decrypted = decipher.update(encryptedText);
let decipher = crypto.createDecipheriv(
'aes-256-cbc',
Buffer.from(ENCRYPTION_KEY),
iv,
);
decrypted = Buffer.concat([decrypted, decipher.final()]);
return decrypted.toString();
Java code snippet:
try {
IvParameterSpec iv = new IvParameterSpec(initVector.getBytes(StandardCharsets.UTF_8));
SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);
byte[] original = cipher.doFinal(Base64.decodeBase64(encyptedData));
return new String(original);
} catch (Exception ex) {
ex.printStackTrace();
}
Encryption Key is same for both Node JS and Java code.
Thanks in advance.
If your initial vector is 32 bytes then you need to decrypt as below.
public String decrypt(String encryptedData) {
try {
String data[] = encryptedData.split(":");
IvParameterSpec iv = new IvParameterSpec(getBytes(data[0]));
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
SecretKeySpec skeySpec = new SecretKeySpec(YOUR_KEY.getBytes(), "AES");
cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);
byte[] decryptedData = cipher.doFinal(getBytes(data[1]));
return new String(decryptedData);
} catch (Exception e) {
throw new RuntimeException("Error occured while decrypting data", e);
}
}
public byte[] getBytes(String s) {
String tmp;
byte[] b = new byte[s.length() / 2];
int i;
for (i = 0; i < s.length() / 2; i++) {
tmp = s.substring(i * 2, i * 2 + 2);
b[i] = (byte)(Integer.parseInt(tmp, 16) & 0xff);
}
return b;
}
it seems the problem is with size of the variabel in java when you decode.
Check this links maybe those give you some hints :
1- ejava-base64-encode-and-decode
2- given-final-block-not-properly-padded
Related
I have an Android application (Built over JAVA) to be converted to Flutter. There is an encryption function and a decryption function in JAVA which I am looking to convert to DART.
However, it seems like something is missing in the conversion and therefore, it is not encrypting starting few characters in the string and therefore, when decrypting back, it does not bring the correct data back.
Below is the JAVA code in use.
public static String encrypt(Context ctx, String requestString) {
String encryptString = "";
try {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
byte[] keyBytes = new byte[16];
byte[] b = 'SOME16CHARSTRING'.getBytes("UTF-8");
int len = b.length;
if (len > keyBytes.length)
len = keyBytes.length;
System.out.println("Length - " + len);
System.arraycopy(b, 0, keyBytes, 0, len);
SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");
IvParameterSpec ivSpec = new IvParameterSpec(keyBytes);
cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);
byte[] encrypted = cipher.doFinal(requestString.getBytes("UTF-8"));
encryptString = Base64.encodeToString(encrypted, Base64.NO_WRAP);
} catch (Exception e) {
GlobalMethods.SendErrorReport(ctx, e);
e.printStackTrace();
}
return encryptString;
}
And the converted DART code is as below.
String encryptAES(String plainTextString) {
try {
final key = Key.fromUtf8('SOME16CHARSTRING');
final iv = IV.fromLength(16);
final encrypter = Encrypter(AES(key, mode: encrypt.AESMode.cbc, padding: "PKCS7"));
final encrypted = encrypter.encrypt(plainTextString, iv: iv);
final decrypted = encrypter.decrypt(encrypted, iv: iv);
return encrypted.base64;
} catch (e) {
print("Error while encoding String : $e");
return null;
}
}
Anything which I can correct here ?
Thanks in Advance.
I have encrypted the string in php. Decrypted successfully from php and node.js. In addition, it must be decrypted by java.
Help me an example of decrypting from java?
PHP Encrypt code
/* encrypt */
$encryption_method = 'aes-256-cbc';
$secretHash = "d95acd54c6a821ff32c52825b931c194";
$iv_size = openssl_cipher_iv_length($encryption_method);
$iv = openssl_random_pseudo_bytes($iv_size);
//encrypt
$encryptedMessage = openssl_encrypt($new_token, $encryption_method, $secretHash, 0, $iv);
//Concatenate iv with data
$ciphertext = bin2hex($iv).$encryptedMessage;
/* decrypt the cipher */
$iv_size = openssl_cipher_iv_length($encryptionMethod);
$iv = hex2bin(substr($encryptedMessageWithIv, 0, $iv_size * 2));
$decryptedMessage = openssl_decrypt(substr($encryptedMessageWithIv, $iv_size * 2), $encryptionMethod, $secretHash, 0, $iv);
Below is the encryption and decryption process for a string using AES algorithm.
private static final String key = "aesEncryptionKey";
private static final String initVector = "encryptionIntVec";
public static String encrypt(String value) {
try {
IvParameterSpec iv = new IvParameterSpec(initVector.getBytes("UTF-8"));
SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
byte[] encrypted = cipher.doFinal(value.getBytes());
return Base64.encodeBase64String(encrypted);
} catch (Exception ex) {
ex.printStackTrace();
}
return null;
}
public static String decrypt(String encrypted) {
try {
IvParameterSpec iv = new IvParameterSpec(initVector.getBytes("UTF-8"));
SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);
byte[] original = cipher.doFinal(Base64.decodeBase64(encrypted));
return new String(original);
} catch (Exception ex) {
ex.printStackTrace();
}
return null;
}
In case init vector is not known, try using below code segment.
public byte[] decrypt(String encryptedString) throws DataLengthException, InvalidCipherTextException {
byte[] input = encryptedString.getBytes("UTF-8");
CBCBlockCipher cbcBlockCipher = new CBCBlockCipher(new AESEngine());
SecureRandom random = new SecureRandom();;
KeyParameter key = new KeyParameter("$secretHash".getBytes());// your key string
BlockCipherPadding blockCipherPadding = new PKCS7Padding();;
PaddedBufferedBlockCipher pbbc = new PaddedBufferedBlockCipher(cbcBlockCipher, blockCipherPadding);
int blockSize = cbcBlockCipher.getBlockSize(); // Make sure this block size is same as that used while encrypting the string.
int inputOffset = 0;
int inputLength = input.length;
int outputOffset = 0;
byte[] initializationVector = new byte[blockSize];
System.arraycopy(input, 0, initializationVector, 0, blockSize);
inputOffset += blockSize;
inputLength -= blockSize;
pbbc.init(encrypt, new ParametersWithIV(key, initializationVector));
byte[] output = new byte[pbbc.getOutputSize(inputLength) + outputOffset];
int outputLength = outputOffset + pbbc.processBytes(input, inputOffset, inputLength, output, outputOffset);
outputLength += pbbc.doFinal(output, outputLength);
return Arrays.copyOf(output, outputLength);
}
Just in case it helps someone in the future: encryption with AES/CBC/PKCS5PADDING along with the generation of a dynamic IV that is appended to the final ciphertext in Java can be done through the following code:
Encryption (JAVA)
public String encryptPlainText(String plainText) {
String cipherText = "";
try {
String keyString = "examplesecretkeyexamplesecretkey";
//Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy
Security.setProperty("crypto.policy", "unlimited");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
SecretKeySpec keyspec = new SecretKeySpec(keyString.getBytes(), "AES");
byte[] v = new byte[16];
new SecureRandom().nextBytes(v);
IvParameterSpec iv = new IvParameterSpec(v);
cipher.init(Cipher.ENCRYPT_MODE, keyspec, iv);
byte[] cipherTextByteArray = cipher.doFinal(plainText.getBytes());
//appending iv to ciphertext without any additional libraries to handle the concatenation of the two byte arrays
byte[] ivWithCipherTextByteArray = new byte[v.length + cipherTextByteArray.length];
System.arraycopy(v, 0, ivWithCipherTextByteArray, 0, v.length);
System.arraycopy(cipherTextByteArray, 0, ivWithCipherTextByteArray, v.length, cipherTextByteArray.length);
cipherText = new String(Base64.getEncoder().encode(ivWithCipherTextByteArray));
} catch (Exception e) {
LOG.info("Exception", e);
}
return cipherText;
}
Decryption of the cipherText obtained with the code above can be implemented in the following way:
Decryption (JAVA)
public static String decryptCipherText(String cipherText) {
String plainText="";
try {
String keyString = "examplesecretkeyexamplesecretkey";
Security.setProperty("crypto.policy", "unlimited");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
SecretKeySpec keyspec = new SecretKeySpec(keyString.getBytes(), "AES");
byte[] cipherTextByteArray = Base64.getDecoder().decode(cipherText);
//initialize the IvParameterSpec with the first 16 bytes of the cipherText
IvParameterSpec iv = new IvParameterSpec(Arrays.copyOfRange(cipherTextByteArray, 0, 16));
//cipherText to decrypt is now the original one with the first 16 bytes removed (the IV used above)
cipherTextByteArray = Arrays.copyOfRange(cipherTextByteArray, 16, cipherTextByteArray.length);
cipher.init(Cipher.DECRYPT_MODE, keyspec, iv);
plainText = new String(cipher.doFinal(cipherTextByteArray));
} catch (Exception e) {
LOG.info("Exception", e);
}
return plainText;
}
Hi I have java code which decrypt the ciphertext encrypted using CryptoJS library(AES).
Now i wanted to write the javacode which will encrypt the plaintext again.
Please find the below code.
try {
String secret = "René Über";
String cipherText="U2FsdGVkX1+tsmZvCEFa/iGeSA0K7gvgs9KXeZKwbCDNCs2zPo+BXjvKYLrJutMK+hxTwl/hyaQLOaD7LLIRo2I5fyeRMPnroo6k8N9uwKk=";
byte[] cipherData = Base64.decode(cipherText, Base64.DEFAULT);
byte[] saltData = Arrays.copyOfRange(cipherData, 8, 16);
MessageDigest md5 = MessageDigest.getInstance("MD5");
final byte[][] keyAndIV = GenerateKeyAndIV(32, 16, 1, saltData, secret.getBytes("utf-8"), md5);
SecretKeySpec key = new SecretKeySpec(keyAndIV[0], "AES");
IvParameterSpec iv = new IvParameterSpec(keyAndIV[1]);
byte[] encrypted = Arrays.copyOfRange(cipherData, 16, cipherData.length);
Cipher aesCBC = Cipher.getInstance("AES/CBC/PKCS5Padding");
aesCBC.init(Cipher.DECRYPT_MODE, key, iv);
byte[] decryptedData = aesCBC.doFinal(encrypted);
String decryptedText = new String(decryptedData,"utf-8");
System.out.println("Decrypted "+decryptedText);
//Here I get right plain text as
//System.out: Decrypted The quick brown fox jumps over the lazy dog.
Cipher abc=Cipher.getInstance("AES/CBC/PKCS5Padding");
abc.init(Cipher.ENCRYPT_MODE,key,iv);
byte[] encryptedData=abc.doFinal(decryptedData);
String str=Base64.encodeToString(encryptedData,Base64.DEFAULT);
System.out.println("encrypted "+str);
//Here i want the encrypted text as
// encrypted U2FsdGVkX1+tsmZvCEFa/iGeSA0K7gvgs9KXeZKwbCDNCs2zPo+BXjvKYLrJutMK+hxTwl/hy//aQLOaD7LLIRo2I5fyeRMPnroo6k8N9uwKk=
//but i receive
//System.out: encrypted IZ5IDQruC+Cz0pd5krBsIM0KzbM+j4FeO8pgusm60wr6HFPCX+HJpAs5oPssshGjYjl/J5Ew+//eui
}catch (Exception e)
{}
When I decrypt the code I get correct Plain Text but when I again encrypt the plain text I didnt get the encrypted text as previous.
Please Help.
GenerateKeyAndIV function code:-
public static byte[][] GenerateKeyAndIV(int keyLength, int ivLength, int iterations, byte[] salt, byte[] password, MessageDigest md) {
int digestLength = md.getDigestLength();
int requiredLength = (keyLength + ivLength + digestLength - 1) / digestLength * digestLength;
byte[] generatedData = new byte[requiredLength];
int generatedLength = 0;
try {
md.reset();
// Repeat process until sufficient data has been generated
while (generatedLength < keyLength + ivLength) {
// Digest data (last digest if available, password data, salt if available)
if (generatedLength > 0)
md.update(generatedData, generatedLength - digestLength, digestLength);
md.update(password);
if (salt != null)
md.update(salt, 0, 8);
md.digest(generatedData, generatedLength, digestLength);
// additional rounds
for (int i = 1; i < iterations; i++) {
md.update(generatedData, generatedLength, digestLength);
md.digest(generatedData, generatedLength, digestLength);
}
generatedLength += digestLength;
}
// Copy key and IV into separate byte arrays
byte[][] result = new byte[2][];
result[0] = Arrays.copyOfRange(generatedData, 0, keyLength);
if (ivLength > 0)
result[1] = Arrays.copyOfRange(generatedData, keyLength, keyLength + ivLength);
return result;
} catch (DigestException e) {
throw new RuntimeException(e);
} finally {
// Clean out temporary data
Arrays.fill(generatedData, (byte)0);
}
}
Your ciphertext has "Salted__<8 byte salt>" at the beginning, which you skip when decrypting. You need to prefix the same in your encryption mode if you want to create OpenSSL compatible ciphertext.
Your encryption code ciphertext seems correct when you view it in a base64 to hex decoder, e.g. the one provided here. However, because each character only contains 64 bits and since the bytes have shifted 16 places (which is not divisible by 3), it just seams that your entire ciphertext is incorrect, while it is just missing 16 bytes at the front.
Here posting my working code for android I have used crypto for decryption on the server. Below code is using AES Algorithm
private static final String key = "aesExamplekey";
private static final String initVector = "exampleintvec";
public static String encrypt(String value) {
try {
IvParameterSpec iv = new IvParameterSpec(initVector.getBytes("UTF-8"));
SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
byte[] encrypted = cipher.doFinal(value.getBytes());
// byte[] finalCiphertext = new byte[encrypted.length+2*16];
return Base64.encodeToString(encrypted, Base64.NO_WRAP);
} catch (Exception ex) {
ex.printStackTrace();
}
return null;
}`
Server side code asp.net
public string DecryptStringAES(string cipherText)
{
// var keybytes = Encoding.UTF8.GetBytes("7061737323313233");
// var iv = Encoding.UTF8.GetBytes("7061737323313233");
var keybytes = Encoding.UTF8.GetBytes("aesExamplekey");
var iv = Encoding.UTF8.GetBytes("exampleintvec");
var encrypted = Convert.FromBase64String(cipherText);
var decriptedFromJavascript = DecryptStringFromBytes(encrypted, keybytes, iv);
return string.Format(decriptedFromJavascript);
}
I am doing some simple encryption/decryption coding, and I am having a problem, which I cannot figure out by myself.
I have a ciphertext which is hex encoded. The ciphertext is AES with a block length of 128bits and a key length of 256bits. The cipher block mode is CBC. IV is the first block of the cipher text.
The Exception Message is Illegal Key Size.
Here is my decrypt() function:
public static byte[] decrypt() throws Exception
{
try{
byte[] ciphertextBytes = convertToBytes("cb12f5ca1bae224ad44fdff6e66f9a53e25f1000183ba5568958430c11c6eafc62c04de8bf27e0ac7104b598fb492142");
byte[] keyBytes = convertToBytes("CFDC65CB003DD50FF5D6D826D62CF9CA6C64489D60CB02D18C1B58C636F8220D");
byte[] ivBytes = convertToBytes("cb12f5ca1bae224a");
SecretKey aesKey = new SecretKeySpec(keyBytes, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
cipher.init(Cipher.DECRYPT_MODE, aesKey, new IvParameterSpec(ivBytes));
byte[] result = cipher.doFinal(ciphertextBytes);
return result;
}
catch(Exception e)
{
System.out.println(e.getMessage());
}
return null;
}
And I have those functions to do the conversion String/ByteArray
//convert ByteArray to Hex String
public static String convertToHex(byte[] byteArray)
{
StringBuilder sb = new StringBuilder();
for (byte b : byteArray)
{
sb.append(String.format("%02X", b));
}
return sb.toString();
}
//convert String to ByteArray
private static byte[] convertToBytes(String input) {
int length = input.length();
byte[] output = new byte[length / 2];
for (int i = 0; i < length; i += 2) {
output[i / 2] = (byte) ((digit(input.charAt(i), 16) << 4) | digit(input.charAt(i+1), 16));
}
return output;
}
Maybe you can help me.
Thank you very much!
You might have hit the key-size limit in Oracle JRE. From the linked document:
If stronger algorithms are needed (for example, AES with 256-bit keys), the JCE Unlimited Strength Jurisdiction Policy Files must be obtained and installed in the JDK/JRE.
It is the user's responsibility to verify that this action is permissible under local regulations.
I have the below method:
public String decrypt(String strToBeDecrypted) {
try {
strToBeDecrypted = URLDecoder.decode(strToBeDecrypted, "UTF-8");
DESKeySpec desKeySpec = new DESKeySpec(key);
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
SecretKey skey = keyFactory.generateSecret(desKeySpec);
IvParameterSpec ivSpec = new IvParameterSpec(iv);
cipher.init(Cipher.DECRYPT_MODE, skey, ivSpec);
byte[] keyByteArray = new BASE64Decoder().decodeBuffer(strToBeDecrypted);
byte[] original = cipher.doFinal(keyByteArray);
return new String(original, "UTF-8");
} catch (Exception e) {
logger.error(ExceptionUtil.getDetailedMessage(e));
}
return "";
}
This is throwing
"name=javax.crypto.IllegalBlockSizeException;message=Input length must be multiple of 8 when decrypting with padded cipher;"
at the below line:
byte[] original = cipher.doFinal(keyByteArray);
Can someone please tell me whats the problem here?
The input length it's referring to is the length of your ciphertext (strToBeDecrypted), which it expects to be a multiple of the block size. It is implied that by default the library is expecting your input to be padded.
That means either you either need to set the padding to 'none' when decrypting (as that was the 'padding' used when encrypting) or you've corrupted the ciphertext somehow.
Try changing "DES" to "DES/ECB/NoPadding". I don't know what the default cipher mode is for your implementation, but it's typically "ECB" or "CBC". If neither of those two work then you're corrupting your ciphertext somewhere along the line.
Please use this. It works for me.
public String decrypt(String message) throws Exception {
final MessageDigest md = MessageDigest.getInstance("md5");
final byte[] digestOfPassword = md.digest("HG58YZ3CR9"
.getBytes("utf-8"));
final byte[] keyBytes = Arrays.copyOf(digestOfPassword, 24);
for (int j = 0, k = 16; j < 8;) {
keyBytes[k++] = keyBytes[j++];
}
final SecretKey key = new SecretKeySpec(keyBytes, "DESede");
final IvParameterSpec iv = new IvParameterSpec(new byte[8]);
final Cipher decipher = Cipher.getInstance("DESede/CBC/PKCS5Padding");
decipher.init(Cipher.DECRYPT_MODE, key, iv);
final byte[] encData = new sun.misc.BASE64Decoder().decodeBuffer(message);
final byte[] plainText = decipher.doFinal(encData);
return new String(plainText, "UTF-8");
}