簡體   English   中英

從Java中的圖像讀取加密的字節

[英]Reading encrypted bytes from an image in java

我必須將文本嵌入加密的圖像中(Stegnography)。 我在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()從文件讀取了此加密字節。寫入圖像之前的加密byte []和讀取圖像之后的byte []是完全不同

所以這就是發生的事情。 假定尺寸為WxH的原始圖像。 由於每個像素3個字節,因此圖像orgnlimagebytes具有S = 3*W*H字節。

現在,您使用AES加密此圖像,這將導致16字節固定塊大小 如果S不能被16整除,它將被填充成16。 如果可被16整除,則將添加另一個16字節的塊。 這里的要點是,將加密的字節數組, encryptedbytes ,具有比更大尺寸orgnlimagebytes 稱為S'

現在,您使用toImage方法toImage字節數組中創建一個BufferedImage。 您創建了一個encryptedbytes的緩沖區,將其轉換為柵格,等等,等等。 您最終得到的圖像大小為WxH 但是,發生的情況是BufferedImage對象引用了具有S'元素的緩沖區。 您僅使用前S元素來構造圖像的像素,但是仍然可以從緩沖區訪問其余元素。 因此,當您再次將BufferedImage轉換為字節數組encryptedbytes2 ,您會得到所有S'個元素。

該圖像只有WxH RGB像素,因此,如果您嘗試將其保存到圖像文件中,則僅此而已。 您不會保存緩沖區引用中的任何其他字節。 因此,當您保存並加載圖像並將其轉換為字節數組expectedbytes3 ,您將獲得預期的字節數,應為S


這解釋了保存到文件之前和之后加密字節數組的意外不一致。 但是,除了加密方法之外,為什么還要加密封面圖像? 如果在將消息隱藏在圖像中之前對其進行了加密,以確保額外的安全性,這將很有意義,以防有人設法同時檢測和提取消息。 加密封面圖像的像素值意味着徹底改變它們,這會帶來明顯的變化。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM