I tried GCM encryption using OpenSSL library in VC++. I am getting the encrypted data, but the data is not matching with the output data as in JAVA and C#. I used same parameter credentials.
Here is the code I am using:
int encrypt(unsigned char *plaintext, int plaintext_len, unsigned char *aad,int aad_len, unsigned char *key, unsigned char *iv,unsigned char *ciphertext, unsigned char *tag)
{
EVP_CIPHER_CTX *ctx;
int len;
int ciphertext_len;
/* Create and initialise the context */
if (!(ctx = EVP_CIPHER_CTX_new())) handleErrors();
/* Initialise the encryption operation. */
if (1 != EVP_EncryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL))
handleErrors();
/* Set IV length if default 12 bytes (96 bits) is not appropriate */
if (1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, 16, NULL))
handleErrors();
/* Initialise key and IV */
if (1 != EVP_EncryptInit_ex(ctx, NULL, NULL, key, iv)) handleErrors();
/* Provide any AAD data. This can be called zero or more times as
* required
*/
if (1 != EVP_EncryptUpdate(ctx, NULL, &len, aad, aad_len))
handleErrors();
/* Provide the message to be encrypted, and obtain the encrypted output.
* EVP_EncryptUpdate can be called multiple times if necessary
*/
if (1 != EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len))
handleErrors();
ciphertext_len = len;
/* Finalise the encryption. Normally ciphertext bytes may be written at
* this stage, but this does not occur in GCM mode
*/
if (1 != EVP_EncryptFinal_ex(ctx, ciphertext + len, &len)) handleErrors();
ciphertext_len += len;
/* Get the tag */
if (1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, 16, tag))
handleErrors();
/* Clean up */
EVP_CIPHER_CTX_free(ctx);
return ciphertext_len;
}
The C# Code we are using
public byte[] GCM_Encryption(byte[] plainText)
{
byte[] authenticationTag;
byte[] Nonce;
byte[] AAD;
byte[] ciphertext;
string _nonce = Cur_DnT.Substring(Cur_DnT.Length - 12);
string _AAD = Cur_DnT.Substring(Cur_DnT.Length - 16);
Nonce = new byte[] { 0x2d, 0x32, 0x35, 0x54, 0x31, 0x35, 0x3a, 0x31, 0x35, 0x3a, 0x32, 0x39 };//Encoding.UTF8.GetBytes(_nonce);
AAD = new byte[] { 0x37, 0x2d, 0x30, 0x35, 0x2d, 0x32, 0x35, 0x54, 0x31, 0x35, 0x3a, 0x31, 0x35, 0x3a, 0x32, 0x39 };//Encoding.UTF8.GetBytes(_AAD);
using (AuthenticatedAesCng aes = new AuthenticatedAesCng())
{
aes.Key = new byte[] { 0xF9, 0x28, 0x01, 0x98, 0xBB, 0xC9, 0x43, 0xF8, 0x85, 0x6D, 0xA8, 0x36, 0x0F, 0x07, 0x37, 0x92, 0x7C, 0x49, 0x45, 0x29, 0x6C, 0xAF, 0xD5, 0x30, 0x1B, 0x92, 0x0E, 0x32, 0xAA, 0x20, 0xA2, 0x33 };//SKey;
aes.IV = Nonce;
aes.CngMode = CngChainingMode.Gcm;
// This data is required to verify the authentication tag, but will not go into the
// ciphertext
aes.AuthenticatedData = AAD;
// Do the encryption
using (MemoryStream ms = new MemoryStream())
using (IAuthenticatedCryptoTransform encryptor = aes.CreateAuthenticatedEncryptor())
using (CryptoStream cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
{
// Encrypt the plaintext
byte[] plaintext = plainText;
cs.Write(plaintext, 0, plaintext.Length);
// Complete the encryption operation, and generate the authentication tag
cs.FlushFinalBlock();
// Get the generated ciphertext and authentication tag
ciphertext = ms.ToArray();
authenticationTag = encryptor.GetTag();
}
}
string ddf = BitConverter.ToString(ciphertext);
return ciphertext.Concat(authenticationTag).ToArray();
}
Related
I'm using Triple DES for my encryption/decryption purpose but somehow it gives me above exception and I tried other approaches as well mentioned in the related answers, but I'm stuck. I'm new to cryptography and corresponding java libs.
private static byte[] Key = new byte[] {
0x42, 0x45, 0x49, 0x30, 0x12, 0x22, 0x35, 0x48, 0x33, 0x24, 0x28, 0x51,
0x48, 0x24, 0x30, 0x21, 0x44, 0x31, 0x14, 0x19, 0x45, 0x34, 0x47, 0x25 };
Cipher c;
public EncryptionHelper() throws Exception {
// byte[] key_hash = (Key).toString().getBytes("UTF-8");
// key_hash = Arrays.copyOf(key_hash, 32);
SecretKey key = new SecretKeySpec(Key, 0, Key.length, "DESede");
c = Cipher.getInstance("DESede/ECB/PKCS5Padding");
c.init(Cipher.ENCRYPT_MODE, key);
}
public String Encrypt(String S) throws Exception {
byte[] base64EncryptedText = S.getBytes("UTF-8");
byte EncryptedText[] = c.doFinal(base64EncryptedText, 0, base64EncryptedText.length);
return new String(EncryptedText);
}
public String Decrypt(String S) throws Exception {
Cipher c2 = null;
// byte[] key_hash = (Key).toString().getBytes("UTF-8");
// key_hash = Arrays.copyOf(key_hash, 24);
SecretKey key = new SecretKeySpec(Key,0, Key.length, "DESede");
c2 = Cipher.getInstance("DESede/ECB/PKCS5Padding");
c2.init(Cipher.DECRYPT_MODE, key);
byte[] base64EncryptedText = Base64.getEncoder().encode(S.getBytes());
byte[] textDecrypted = c2.doFinal(base64EncryptedText, 0, base64EncryptedText.length);
return new String(textDecrypted, "UTF-8");
}
EDIT:
Finally worked through the solution, I was just misplacing the components, specified the core logic as well.
public class EncryptionHelper {
private static byte[] Key = new byte[] {
0x42, 0x45, 0x49, 0x30, 0x12, 0x22, 0x35, 0x48, 0x33, 0x24, 0x28, 0x51,
0x48, 0x24, 0x30, 0x21, 0x44, 0x31, 0x14, 0x19, 0x45, 0x34, 0x47, 0x25 };
static Cipher c;
public EncryptionHelper() throws Exception {
// byte[] key_hash = (Key).toString().getBytes("UTF-8");
// key_hash = Arrays.copyOf(key_hash, 32);
SecretKey key = new SecretKeySpec(Key, 0, Key.length, "DESede");
c = Cipher.getInstance("DESede/ECB/PKCS5Padding");
c.init(Cipher.ENCRYPT_MODE, key);
}
public static String Encrypt(String S) throws Exception {
byte[] base64EncryptedText = S.getBytes("UTF-8");
byte EncryptedText[] = c.doFinal(base64EncryptedText, 0, base64EncryptedText.length);
return new String(Base64.getEncoder().encode(EncryptedText));
}
// LOGIC:
// for encryption: string -> utf-8 byte array,
// encrypt and return a base 64 encoded string
// for decryption: String -> base64 -> decode base 64 array,
// decrypt and return utf-8 string
public static String Decrypt(String S) throws Exception {
Cipher c2 = null;
// byte[] key_hash = (Key).toString().getBytes("UTF-8");
// key_hash = Arrays.copyOf(key_hash, 24);
SecretKey key = new SecretKeySpec(Key, "DESede");
c2 = Cipher.getInstance("DESede/ECB/PKCS5Padding");
c2.init(Cipher.DECRYPT_MODE, key);
byte[] base64EncryptedText = Base64.getDecoder().decode(S.getBytes());
byte[] textDecrypted = c2.doFinal(base64EncryptedText, 0, base64EncryptedText.length);
return new String(textDecrypted, "UTF-8");
}
Despite the names on your variables you have failed to base64-encode the result of encryption in your Encrypt method. Therefore, when you convert it to String you get garbage, and when you base64 decode that garbage in your Decrypt method you get garbage2.
You are base64-decoding and then decrypting, but you are not encrypting and then base64-encoding.
Today following a guide I tried to encrypt and after decrypt a string.
Unluckily, I've gotten an InvalidKeyException, I googled up that and found out that for encrypt a string that have more than 128 bits (16 bytes -> 16 characters)
I need the JCE, so I got into the oracle website, downloaded it and putted it on my java build path, under the folder /lib/security.
Still no luck, i still keep getting this error, with this code:
import java.security.Security;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
public class EncryptTests {
public static void main(String[] args) throws Exception {
byte[] input = "www.java2s.com".getBytes();
byte[] keyBytes = new byte[] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17 };
SecretKeySpec key = new SecretKeySpec(keyBytes, "AES");
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
System.out.println(new String(input));
// encryption pass
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] cipherText = new byte[cipher.getOutputSize(input.length)];
int ctLength = cipher.update(input, 0, input.length, cipherText, 0);
ctLength += cipher.doFinal(cipherText, ctLength);
System.out.println(new String(cipherText));
System.out.println(ctLength);
// decryption pass
cipher.init(Cipher.DECRYPT_MODE, key);
byte[] plainText = new byte[cipher.getOutputSize(ctLength)];
int ptLength = cipher.update(cipherText, 0, ctLength, plainText, 0);
ptLength += cipher.doFinal(plainText, ptLength);
System.out.println(new String(plainText));
System.out.println(ptLength);
}
}
This is the console output:
www.java2s.com Exception in thread "main" java.security.InvalidKeyException: Illegal key size or default
parameters at javax.crypto.Cipher.checkCryptoPerm(Cipher.java:1026)
at javax.crypto.Cipher.implInit(Cipher.java:801) at
javax.crypto.Cipher.chooseProvider(Cipher.java:864) at
javax.crypto.Cipher.init(Cipher.java:1249) at
javax.crypto.Cipher.init(Cipher.java:1186) at
EncryptTests.main(EncryptTests.java:23)
Any fix? :)
Following Google's advice here and using their code as a guide. I've tried using their encrypted hyperlocal string to test the decryption method that I wrote (most of it from Google though as my own attempts at writing such a method caused me much headache).
I'm getting Signature Mismatch for some reason even though I'm providing the proper integrity and encryption keys and I'm using the byte array that they provided in their example decryption (lower down Google's RTB decrypt hyperlocal page).
I have the code here:
package anon.bidder.adx;
import java.io.ByteArrayOutputStream;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Hex;
import org.apache.log4j.Logger;
public class AdxBidRequestDecryptor {
private static final int INITIALIZATION_VECTOR_SIZE = 16;
private static final int SIGNATURE_SIZE = 4;
private static final int BLOCK_SIZE = 20;
public static class DecrypterException extends Exception {
public DecrypterException(String message) {
super(message);
}
}
public static byte[] hexStringToByteArray(String s) {
int len = s.length();
byte[] data = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
+ Character.digit(s.charAt(i+1), 16));
}
return data;
}
public static void main(String args[]){
byte[] ciphertext = hexStringToByteArray("E2014EA201246E6F6E636520736F7572636501414243C0ADF6B9B6AC17DA218FB50331EDB376701309CAAA01246E6F6E636520736F7572636501414243C09ED4ECF2DB7143A9341FDEFD125D96844E25C3C202466E6F6E636520736F7572636502414243517C16BAFADCFAB841DE3A8C617B2F20A1FB7F9EA3A3600256D68151C093C793B0116DB3D0B8BE9709304134EC9235A026844F276797");
byte[] encryptionKey = {(byte)0x02, (byte)0xEE, (byte)0xa8, (byte)0x3c, (byte)0x6c, (byte)0x12, (byte)0x11, (byte)0xe1, (byte)0x0b,
(byte) 0x9f, (byte) 0x88, (byte) 0x96, (byte) 0x6c, (byte) 0xee, (byte) 0xc3, (byte) 0x49, (byte) 0x08, (byte) 0xeb, (byte) 0x94, (byte) 0x6f, (byte) 0x7e,
(byte) 0xd6, (byte) 0xe4, (byte) 0x41, (byte) 0xaf, (byte) 0x42, (byte) 0xb3, (byte) 0xc0, (byte) 0xf3, (byte) 0x21, (byte) 0x81, (byte) 0x40};
byte[] integrityKey = {(byte) 0xbf, (byte) 0xFF, (byte) 0xec, (byte) 0x55, (byte) (byte) 0xc3, (byte) 0x01, (byte) 0x30, (byte) 0xc1, (byte) 0xd8,
(byte) 0xcd, (byte) 0x18, (byte) 0x62, (byte) 0xed, (byte) 0x2a, (byte) 0x4c, (byte) 0xd2, (byte) 0xc7, (byte) 0x6a, (byte) 0xc3, (byte) 0x3b, (byte) 0xc0,
(byte) 0xc4, (byte) 0xce, (byte) 0x8a, (byte) 0x3d, (byte) 0x3b, (byte) 0xbd, (byte) 0x3a, (byte) 0xd5, (byte) 0x68, (byte) 0x77, (byte) 0x92};
try {
byte[] plain = decrypt(ciphertext, new SecretKeySpec(encryptionKey,"HmacSHA1"),new SecretKeySpec(integrityKey,"HmacSHA1"));
} catch (DecrypterException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static byte[] decrypt(byte[] ciphertext,
SecretKey encryptionKey,
SecretKey integrityKey)
throws DecrypterException {
try {
// Step 1. find the length of initialization vector and clear text.
final int plaintext_length =
ciphertext.length - INITIALIZATION_VECTOR_SIZE - SIGNATURE_SIZE;
if (plaintext_length < 0) {
throw new RuntimeException("The plain text length can't be negative.");
}
byte[] iv = Arrays.copyOf(ciphertext, INITIALIZATION_VECTOR_SIZE);
// Step 2. recover clear text
final Mac hmacer = Mac.getInstance("HmacSHA1");
final int ciphertext_end = INITIALIZATION_VECTOR_SIZE + plaintext_length;
final byte[] plaintext = new byte[plaintext_length];
boolean add_iv_counter_byte = true;
for (int ciphertext_begin = INITIALIZATION_VECTOR_SIZE, plaintext_begin = 0;
ciphertext_begin < ciphertext_end;) {
hmacer.reset();
hmacer.init(encryptionKey);
final byte[] pad = hmacer.doFinal(iv);
int i = 0;
while (i < BLOCK_SIZE && ciphertext_begin != ciphertext_end) {
plaintext[plaintext_begin++] =
(byte)(ciphertext[ciphertext_begin++] ^ pad[i++]);
}
if (!add_iv_counter_byte) {
final int index = iv.length - 1;
add_iv_counter_byte = ++iv[index] == 0;
}
if (add_iv_counter_byte) {
add_iv_counter_byte = false;
iv = Arrays.copyOf(iv, iv.length + 1);
}
}
// Step 3. Compute integrity hash. The input to the HMAC is clear_text
// followed by initialization vector, which is stored in the 1st section
// or ciphertext.
hmacer.reset();
hmacer.init(integrityKey);
hmacer.update(plaintext);
hmacer.update(Arrays.copyOf(ciphertext, INITIALIZATION_VECTOR_SIZE));
final byte[] computedSignature = Arrays.copyOf(hmacer.doFinal(), SIGNATURE_SIZE);
final byte[] signature = Arrays.copyOfRange(
ciphertext, ciphertext_end, ciphertext_end + SIGNATURE_SIZE);
if (!Arrays.equals(signature, computedSignature)) {
throw new DecrypterException("Signature mismatch.");
}
return plaintext;
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("HmacSHA1 not supported.", e);
} catch (InvalidKeyException e) {
throw new RuntimeException("Key is invalid for this purpose.", e);
}
}
}
The example in the documentation appears to be broken. The test encrypted data embedded in the example archive at the end of java/Decrypter.java conveniently uses the same encryption and integrity keys, and provides us with known encrypted and plaintext data (all bytes are 0xfe).
When I patch your test main with the archive data it passes the signature test and your plaintext result is correct. When I patch Google's program with the data from the documentation page, it fails to match the signature. I believe your code is working but your test data is bad.
I wrote the following code for text file encryption and decryption.
The encryption process works fine but I cannot decrypt the created file. For some reason, even though I use the same password, with the same length and same paddings, the decryption output is an encoded file different from the original one...
In other attempts I failed while running encryption and decryption in separated runs. But now they are both running one after another (even though they are using different key-spec, is that the reason? if so - how can I bypass it?)
public static void main(String[] args) throws Exception {
encrypt("samplePassword", new FileInputStream("file.txt"), new FileOutputStream("enc-file.txt"));
decrypt("samplePassword", new FileInputStream("enc-file.txt"), new FileOutputStream("file-from-enc.txt"));
}
public static void encrypt(String password, InputStream is, OutputStream os) throws Exception {
SecretKeySpec keySpec = new SecretKeySpec(password(password), "TripleDES");
Cipher cipher = Cipher.getInstance("TripleDES");
cipher.init(Cipher.ENCRYPT_MODE, keySpec);
byte[] buf = new byte[8096];
os = new CipherOutputStream(os, cipher);
int numRead = 0;
while ((numRead = is.read(buf)) >= 0) {
os.write(buf, 0, numRead);
}
os.close();
}
public static void decrypt(String password, InputStream is, OutputStream os) throws Exception {
SecretKeySpec keySpec = new SecretKeySpec(password(password), "TripleDES");
Cipher cipher = Cipher.getInstance("TripleDES");
cipher.init(Cipher.ENCRYPT_MODE, keySpec);
byte[] buf = new byte[8096];
CipherInputStream cis = new CipherInputStream(is, cipher);
int numRead = 0;
while ((numRead = cis.read(buf)) >= 0) {
os.write(buf, 0, numRead);
}
cis.close();
is.close();
os.close();
}
private static byte[] password(String password) {
byte[] baseBytes = { (byte) 0x38, (byte) 0x5C, (byte) 0x8, (byte) 0x4C, (byte) 0x75, (byte) 0x77, (byte) 0x5B, (byte) 0x43,
(byte) 0x1C, (byte) 0x1B, (byte) 0x38, (byte) 0x6A, (byte) 0x5, (byte) 0x0E, (byte) 0x47, (byte) 0x3F, (byte) 0x31,
(byte) 0xF, (byte) 0xC, (byte) 0x76, (byte) 0x53, (byte) 0x67, (byte) 0x32, (byte) 0x42 };
byte[] bytes = password.getBytes();
int i = bytes.length;
bytes = Arrays.copyOf(bytes, 24);
if(i < 24){
for(;i<24; i++){
bytes[i] = baseBytes[i];
}
}
return bytes;
}
can any one give me a hint?
On a first look,
cipher.init(Cipher.ENCRYPT_MODE, keySpec);
should probably be
cipher.init(Cipher.DECRYPT_MODE, keySpec);
in the decrypt method.
Have a look at the documentation.
I have the following code.
byte[] input = etInput.getText().toString().getBytes();
byte[] keyBytes = new byte[] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17 };
SecretKeySpec key = new SecretKeySpec(keyBytes, "AES");
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding", "BC");
// encryption pass
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] cipherText = new byte[cipher.getOutputSize(input.length)];
int ctLength = cipher.update(input, 0, input.length, cipherText, 0);
ctLength += cipher.doFinal(cipherText, ctLength);
cipher.init(Cipher.DECRYPT_MODE, key);
byte[] plainText = new byte[cipher.getOutputSize(ctLength)];
int ptLength = cipher.update(cipherText, 0, ctLength, plainText, 0);
String strLength = new String(cipherText,"US-ASCII");
byte[] byteCiphterText = strLength.getBytes("US-ASCII");
Log.e("Decrypt", Integer.toString(byteCiphterText.length));
etOutput.setText(new String(cipherText,"US-ASCII"));
cipherText = etOutput.getText().toString().getBytes("US-ASCII");
Log.e("Decrypt", Integer.toString(cipherText.length));
ptLength += cipher.doFinal(plainText, ptLength);
Log.e("Decrypt", new String(plainText));
Log.e("Decrypt", Integer.toString(ptLength));
It works perfectly.
But once I convert it to the class. It always hit the error in this line.
ptLength += cipher.doFinal(plainText, ptLength);
Error:Pad block corrupted
I have checked and both code are exactly the same. Even the value passed in conversion string to byte all is no different from the code above. Any idea what's wrong with the code?
public String Encrypt(String strPlainText) throws Exception, NoSuchProviderException,
NoSuchPaddingException {
byte[] input = strPlainText.getBytes();
byte[] keyBytes = new byte[] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17 };
SecretKeySpec key = new SecretKeySpec(keyBytes, "AES");
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding", "BC");
// encryption pass
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] cipherText = new byte[cipher.getOutputSize(input.length)];
int ctLength = cipher.update(input, 0, input.length, cipherText, 0);
ctLength += cipher.doFinal(cipherText, ctLength);
return new String(cipherText, "US-ASCII");
}
public String Decrypt(String strCipherText) throws Exception,
NoSuchProviderException, NoSuchPaddingException {
byte[] cipherText = strCipherText.getBytes("US-ASCII");
int ctLength = cipherText.length;
byte[] keyBytes = new byte[] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17 };
SecretKeySpec key = new SecretKeySpec(keyBytes, "AES");
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding", "BC");
// decryption pass
cipher.init(Cipher.DECRYPT_MODE, key);
byte[] plainText = new byte[cipher.getOutputSize(ctLength)];
int ptLength = cipher.update(cipherText, 0, ctLength, plainText, 0);
ptLength += cipher.doFinal(plainText, ptLength);
return new String(plainText);
}
As Yann Ramin said, using String is a failure for cipher in/output. This is binary data that
can contain 0x00
can contain values that are not defined or mapped to strange places in the encoding used
Use plain byte[] as in your first example or go for hex encoding or base64 encoding the byte[].
// this is a quick example - dont use sun.misc inproduction
// - go for some open source implementation
String encryptedString = new sun.misc.BASE64Encoder.encodeBuffer(encryptedBytes);
This string can be safely transported and mapped back to bytes.
EDIT
Perhaps safest way to deal with the length issue is to always use streaming implementation (IMHO):
Example
static public byte[] decrypt(Cipher cipher, SecretKey key, byte[]... bytes)
throws GeneralSecurityException, IOException {
cipher.init(Cipher.DECRYPT_MODE, key);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
for (int i = 0; i < bytes.length; i++) {
bos.write(cipher.update(bytes[i]));
}
bos.write(cipher.doFinal());
return bos.toByteArray();
}
You have specified PKCS7 Padding. Is your padding preserved when stored in your String object? Is your string object a 1:1 match with the bytes output by the cipher? In general, String is inappropriate for passing binary data, such as a cipher output.
In your case cipher uses padding, that means in other words input data will be padded/rounded into blocks with some predefined size (which depends on padding algorithm). Let's say you have supplied 500 bytes to encrypt, padding block size is 16 bytes, so encrypted data will have size of 512 bytes (32 blocks) - 12 bytes will be padded.
In your code you're expecting encrypted array of the same size as input array, which causes exception. You need to recalculate output array size keeping in mind padding.