Четене на криптирани байтове от изображение в java

Трябва да вградя текст в криптирано изображение (стенография). Търсих в Google и намерих кодове за вграждане на текст в изображение. Но първо трябва да криптирам изображението и да вградя текст в това криптирано изображение. Моите опити са следните.

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package tbn;

import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Transparency;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.ComponentColorModel;
import java.awt.image.DataBuffer;
import java.awt.image.DataBufferByte;
import java.awt.image.Raster;
import java.awt.image.WritableRaster;
import java.io.File;
import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.imageio.ImageIO;

/**
 *
 * @author user
 */
public class DbtClass {

    public static void main(String[] args) {
        try {
            BufferedImage orgnlimage = ImageIO.read(new File("parrruuuuu.png"));
            orgnlimage = user_space(orgnlimage);
            byte[] orgnlimagebytes = get_byte_data(orgnlimage);
            byte[] encryptedbytes = encrypt(orgnlimagebytes, "abc");
            BufferedImage encryptedimage = toImage(encryptedbytes, orgnlimage.getWidth(), orgnlimage.getHeight());
            ImageIO.write(encryptedimage, "png", new File("encrypted.png"));

            /////////////////////////////////////////////////////////////////////
            /////////////////////////////////////////////////////////////////////

            byte[] encryptedbytes2 = get_byte_data(encryptedimage);
            System.out.println("encryptedbytes before writing: "+encryptedbytes2.length);

            BufferedImage encryptedimage3 = ImageIO.read(new File("encrypted.png"));
            byte[] encryptedbyte3 = get_byte_data(encryptedimage3);
            System.out.println("encryptedbytes after writing: "+encryptedbyte3.length);


        } catch (IOException ex) {
            Logger.getLogger(DbtClass.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public static BufferedImage user_space(BufferedImage image) {
        //create new_img with the attributes of image
        BufferedImage new_img = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_3BYTE_BGR);
        Graphics2D graphics = new_img.createGraphics();
        graphics.drawRenderedImage(image, null);
        graphics.dispose(); //release all allocated memory for this image
        return new_img;
    }

    public static byte[] get_byte_data(BufferedImage image) {
        WritableRaster raster = image.getRaster();
        DataBufferByte buffer = (DataBufferByte) raster.getDataBuffer();
        return buffer.getData();
    }

    public static byte[] encrypt(byte[] orgnlbytes, String key) {
        byte[] encbytes = null;
        try {
            Cipher cipher = Cipher.getInstance("AES");
            KeyGenerator keyGen = KeyGenerator.getInstance("AES");
            SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
            // cryptograph. secure random 
            random.setSeed(key.getBytes());

            keyGen.init(128, random);
            // for example
            SecretKey secretKey = keyGen.generateKey();
            cipher.init(Cipher.ENCRYPT_MODE, secretKey);
            encbytes = cipher.doFinal(orgnlbytes);
        } catch (NoSuchAlgorithmException ex) {
            Logger.getLogger(DbtClass.class.getName()).log(Level.SEVERE, null, ex);
        } catch (NoSuchPaddingException ex) {
            Logger.getLogger(DbtClass.class.getName()).log(Level.SEVERE, null, ex);
        } catch (InvalidKeyException ex) {
            Logger.getLogger(DbtClass.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IllegalBlockSizeException ex) {
            Logger.getLogger(DbtClass.class.getName()).log(Level.SEVERE, null, ex);
        } catch (BadPaddingException ex) {
            Logger.getLogger(DbtClass.class.getName()).log(Level.SEVERE, null, ex);
        }
        return encbytes;
    }

    public static BufferedImage toImage(byte[] imagebytes, int width, int height) {
        DataBuffer buffer = new DataBufferByte(imagebytes, imagebytes.length);
        WritableRaster raster = Raster.createInterleavedRaster(buffer, width, height, 3 * width, 3, new int[]{2, 1, 0}, (Point) null);
        ColorModel cm = new ComponentColorModel(ColorModel.getRGBdefault().getColorSpace(), false, true, Transparency.OPAQUE, DataBuffer.TYPE_BYTE);
        return new BufferedImage(cm, raster, true, null);
    }
}

Тук ми беше написано шифрованото изображение с помощта на растерен клас и ImageIO.write(). След това прочетете тези шифровани байтове от файла с помощта на ImageIO.read(). Шифрованият байт [] преди запис на изображението и байтът [] след прочитане на изображението са тотално различно


person TBN    schedule 07.02.2015    source източник
comment
Но преди да запиша изображение във файл, от BufferedImage получих допълнителни 16 байта, които споменахте. Така че мисля, че проблемът може да е в ImageIO.write() или в ImageIO.read() така или иначе, благодаря ви за коментара @Reti43   -  person TBN    schedule 07.02.2015
comment
Стеганографията е изкуство или практика за скриване на файл, съобщение, изображение или видео в друг файл, съобщение, изображение или видео. Ако смятате, че трябва да шифровате изображението, за да извършите стеганография, тогава сте напълно извън пътя.   -  person Maarten Bodewes    schedule 07.02.2015
comment
Първо ли вградихте съобщението в носителя и след това ли шифровахте носителя? Защо изобщо бихте шифровали изображението на носителя? И какво имате предвид под изображението не може да бъде идентифицирано от байтове?   -  person Reti43    schedule 07.02.2015
comment
Байтовете на шифрованото изображение преди запис и байтовете след четене не са еднакви.@Reti43   -  person TBN    schedule 07.02.2015


Отговори (1)


И така, ето какво се случва. Да приемем оригинално изображение с размер WxH. Тъй като имате 3 байта на пиксел, вашето изображение, orgnlimagebytes, има S = 3*W*H байта.

Сега шифровате това изображение с AES, което води до фиксиран размер на блока от 16 байта. Ако S не се дели на 16, то ще бъде подплатено, за да е така. Ако се дели на 16, ще бъде добавен друг блок от 16 байта. Въпросът тук е, че шифрованият масив от байтове, encryptedbytes, има по-голям размер от orgnlimagebytes. Наречете това S'.

Сега използвате метода toImage, за да създадете BufferedImage от този байтов масив. Създаваш буфер от encryptedbytes, превръщаш го в растер и бла, бла, бла. В крайна сметка получавате изображение с размер WxH. Това, което се случва обаче, е, че обектът BufferedImage има препратка към буфера, който има S' елемента. Използвате само първите S елемента, за да конструирате пикселите на изображението, но все още имате достъп до останалите елементи от буфера. Така че, когато отново превърнете BufferedImage в масив от байтове, encryptedbytes2, получавате всичките S' брой елементи обратно.

Изображението има само WxH RGB пиксела, така че ако се опитате да го запишете във файл с изображение, това е всичко, което ще запазите. Няма да запазите нито един от допълнителните байтове от референтния буфер. Така че, когато запазите и заредите изображението и го конвертирате в байтов масив, expectedbytes3, получавате очаквания брой байтове, който трябва да бъде S.


Това обяснява неочакваната несъответствие на шифрования масив от байтове преди и след записване във файл. Въпреки това, освен метода на криптиране, защо шифровате дори изображението на корицата? Би имало смисъл, ако шифровате съобщението, преди да го скриете в изображението за допълнителна сигурност, в случай че някой успее да открие и извлече съобщението. Шифроването на стойностите на пикселите на изображението на корицата означава драстична промяна в тях, което въвежда очевидни промени.

person Reti43    schedule 07.02.2015
comment
stackoverflow.com/questions/28396404/ - person TBN; 08.02.2015
comment
Документът е много труден за разбиране поради лошото качество на писмения език, но в нито един момент не се говори за AES криптиране. - person Reti43; 08.02.2015