I am having a problem in storing exact size of encrypted message inside an image.
What I want to do is that I want to encrypt a message with AES cipher and then I want to hide each byte of message in a random pixel by replacing only one component(either red or green or blue component) of pixel with the message byte.
I have done that but I am unable to store with the same size of ciphertext.
First I have done encryption of message with the help of a key using AES/CBC/PKCS5Padding using Java Cryptographic Extension.
byte[] cipherText = encrypt(message, keyBytes);
Then I had to convert cipherText to UTF-8 byte array and then store inside image. If not I will not be able to decrypt it later. If I don't encode properly, I cannot decrypt it after extraction. The problem here is that the size of messageBytes > size of cipherText. It takes more space than the encrypted message i.e cipherText. Example: if cipherText is 32 bytes, I get 148 bytes of messageBytes.
But I want to store the byte array of size cipherText and be able to extract it later.
String encryptedMessage = Arrays.toString(cipherText);
byte[] messageBytes = encryptedMessage.getBytes(StandardCharsets.UTF_8);
Now 148 bytes are stored in the image. Then I have stored each byte inside one of the component(r or g or b) of random pixel.
for(int i=0; i<messageBytes.length; i++) {
storeInsidePixel(image, messageBytes[i], secureRandom)
}
In the extraction part, I retrieved the messageBytes back and converted to encryptedMessage to get the hidden cipherText.
String encryptedMessage = new String(byteArray, StandardCharsets.UTF_8);
String newString = encryptedMessage.substring(1, encryptedMessage.length()-1);
String[] stringArray = newString.split(", ");
byte[] cipherText = new byte[stringArray.length];
for(int i=0; i<stringArray.length; i++) {
cipherText[i] = (byte) (Integer.parseInt(stringArray[i]));
}
Then I decrypted it using the same cipher and key.
String output = decrypt(cipherText, keyBytes);
I want to store the byte array of size cipherText and be able to extract it with same size and decrypt it later.
If I don't encode to utf-8 and store it, I don't get the same output because if the cipherText stored in image is 1040 bytes and later extract it, I will get the same byte values but the size of byte array is just 205 bytes and decryption fails.
Is there any to store exactly 1040 bytes of cipherText in image and extract the same 1040 bytes of cipherText and be able to decrypt it? Is there any way to get it like that?
No, here is where you go wrong. Your
cipherTextshould be binary already (as shown bybyte[] cipherText = encrypt(message, keyBytes);) , and image formats are binary as well. So you should never have to encode it again. Just directly usecipherText.Yeah, well, duh. If you do
Arrays.toStringthen you will get a textual representation of the array, including separators and whatnot, all which you can do without.We cannot see why you get a smaller value back here, but this is what needs to be solved - and it should not be solved by encoding / decoding. Feel free to post a follow-up question with a minimal reproducible example.
There are two problems here: length indication -> you need some way to indicate the size of the ciphertext. Furthermore, if you use the same key for multiple messages then you would need to store the IV as well.
For detecting the size: you can e.g. prefix a 16 bit (
short) length indicator if your ciphertext doesn't exceed 65536 bytes. Or, for CBC, you could use it to count the number of blocks as the unpadding will then reveal the exact size. This would let you store 16 times larger ciphertext.With a 2 byte size indicator and 16 byte IV you'd grow your ciphertext by 18 bytes. Since your ciphertext is already up to 16 bytes larger than the plaintext this may be a small enough size increase for you to handle.