[Steganography] Kỹ thuật che dấu thông tin - Phần 2
Bài viết này tôi chia sẻ về cách cài đặt thuật toán LSB Steganography mà tôi đã trình bày tại Phần 1
Một số lý thuyết cần chú ý trước khi chúng ta bắt đầu:
- Một bức ảnh sẽ có chiều rộng là W, chiều cao là H nên số điểm ảnh (pixel) là W x H, chúng ta sẽ có một ma trận các pixel có H dòng và W cột (W x H)
- Mỗi pixel có một giá trị màu RGB (Red – Green – Blue), mỗi giá trị R – G – B có giá trị từ 0 -> 255 tương ứng với một Byte trong lưu trữ, suy ra có tất cả 2563 tổ hợp màu khác nhau có thể được tạo ra.
Ví dụ: Màu đỏ R có giá trị RGB là (255, 0, 0); Xanh lá cây G (0,255,0); màu vàng Yello (255,255,0);….
- Mỗi Byte gồm 8 Bit, Bit có chỉ số nhỏ nhất gọi là LSB (Least Significant Bit).
Ví dụ: Giá trị 147 chuyển sang nhị phân là 10010011 sẽc có LSB là 1. Giá trị 200 chuyển sang nhị phân là 11001000 sẽ có LSB là 0
Ý tưởng của thuật toán này là sẽ thay thế các bit LSB của từng byte trong giá trị RGB của từng Pixel. Sỡ dĩ chúng ta chỉ thay thế các bit LSB là vì sau khi thay đổi các giá trị trong RBG chỉ dao động 1 đơn vị, dùng mắt thường sẽ khó phát hiện ra sự thay đổi của bức ảnh, giúp đạt được mục đích ẩn dấu.
Ok, giờ chúng ta bắt đầu với thuật toán, mọi người xem sơ đồ sau:
(Nguồn: internet) |
Quá trình Encode để giấu thông điệp vào bức ảnh:
- Đầu tiên chúng ta chuyển đoạn thông điệp bí mật sang dạng nhị phân (Text bits).
- Duyệt các pixel trong bức ảnh (Original Image), đọc các giá trị R – G - B của từng pixel một.
- Thay LSB của từng giá trị R – G – B với một Bit trong chuỗi thông điệp bí mật. Lưu bức ảnh sau khi đã thay đổi lại thành một tập tin mới (Modified Image)
Quá trình Decode để đọc được thông điệp tại phía người nhận:
- Duyệt từng pixel của bức ảnh nhận được (Modified Image).
- Đọc giá trị R – G – B của từng pixel, lấy các LSB của từng giá trị R – G – B, ta được một chuỗi nhị phân của thông điệp gốc.
- Chuyển chuỗi nhị phân sang mã ASCII đọc được.
Cài đặt code bằng Java
Một số thư viện, lớp và hàm hỗ trợ của Java ta sẽ sử dụng
+Lớp javax.imageio.ImageIO: Hỗ trợ các phương phức đọc ghi các tập tin hình ảnh.
+Lớp java.awt.image.BufferedImage: Dữ liệu từ ảnh sẽ được đưa vào một đối tượng kiểu BufferedImage, mọi thay đổi về dữ liệu của tập tin hình ảnh sẽ được thực hiện trên đối tượng này.
+Hàm getRGB(x, y) của đối tượng BufferedImage giúp lấy giá trị RBG của một pixel tại tọa độ (x,y). Hàm này trả về một số nguyên 4 byte
+Hàm setRGB(x, y, value) của đối tượng BufferedImage giúp đặt lại giá trị RBG cho một pixel tại tọa độ (x,y).
Giả sử Pixel tại (100,100) có giá trị màu là (215,162,10) BufferedImage buff = ImageIO.read(new File(“input.png”)); int rgb = buff.getRGB(100,100); Ta phân tích biến rgb trả về như bên dưới
Dữ liệu cần ẩn: “Secret” <=> 101001111001011100011111001011001011110100
Ví dụ ẩn 3 bit đầu tiên là 101 vào ảnh:
Source Code:
Để việc lấy ra các bit LSB đã Encode trước đó một cách đơn giản ta có thể sử dụng các thư viện hỗ trợ sau:
Source Code:
Phần trên tôi đã giải thích chi tiết cách cài đặt thuật toán LSB Steganography, các bạn có thể dựa vào đó viết một chương trình Encode và Decode cho riêng mình, một số chi tiết lập trình hỗ trợ cho thuật toán như việc chuyển đổi chuỗi SECRET sang nhị phân, xác định điểm ngắt trong phương thức Encode và Decode để chèn và dịch ra chuỗi một cách hợp lý, phần này tùy mỗi người nghĩ ra một cách khác nhau. Riêng tôi sẽ chia sẻ Source Code của mình trong Link đính kèm, các bạn có thể tham khảo.
Trong Source Code có 2 Class:
Tải sourcode tại đây
LSB Steganography chỉ là một thuật toán đơn giản trong mảng Steganography Image, vẫn còn một số vấn đề với thuật toán này, tôi chỉ mới tìm hiểu và gặp các vấn đề này khi hiện thực thuật toán, hiên tại vẫn chưa có thời gian tìm cách giải quyết:
Đến đây hi vọng các bạn sẽ có cái nhìn chung về Steganography, trong chuỗi bài viết này có sai xót gì mọi người góp ý hoặc có phương pháp nào mình thấy hay có thể chia sẻ để cùng thảo luận tại đây.
Hẹn gặp lại ở bài kế tiếp! :)
+Lớp javax.imageio.ImageIO: Hỗ trợ các phương phức đọc ghi các tập tin hình ảnh.
+Lớp java.awt.image.BufferedImage: Dữ liệu từ ảnh sẽ được đưa vào một đối tượng kiểu BufferedImage, mọi thay đổi về dữ liệu của tập tin hình ảnh sẽ được thực hiện trên đối tượng này.
+Hàm getRGB(x, y) của đối tượng BufferedImage giúp lấy giá trị RBG của một pixel tại tọa độ (x,y). Hàm này trả về một số nguyên 4 byte
+Hàm setRGB(x, y, value) của đối tượng BufferedImage giúp đặt lại giá trị RBG cho một pixel tại tọa độ (x,y).
ENCODE
Giả sử Pixel tại (100,100) có giá trị màu là (215,162,10) BufferedImage buff = ImageIO.read(new File(“input.png”)); int rgb = buff.getRGB(100,100); Ta phân tích biến rgb trả về như bên dưới
Byte | Byte | Byte | Byte |
Alpha | Red | Green | Blue |
XXX | 215 | 162 | 10 |
XXX | 11010111 | 10100010 | 00001010 |
Dữ liệu cần ẩn: “Secret” <=> 101001111001011100011111001011001011110100
Ví dụ ẩn 3 bit đầu tiên là 101 vào ảnh:
XXX | 11010111 | 10100010 | 00001010 | RGB của Pixel trên ảnh gốc |
OR | AND | OR | Phép toán | |
XXX | 00000001 | 11111110 | 00000001 | BitMask để thay đổi LSB |
XXX | 0x01 | 0xFE | 0x01 | Dạng hexa |
= | = | = | ||
XXX | 11010111 | 10100010 | 00001011 | RGB đã thay đổi |
XXX | 215 | 162 | 11 |
Source Code:
int rgb = buff.getRGB(x, y); //Giá trị RGB hiện tại //Chỉnh sửa giá trị R if(binHidden[i++] == '0')rgb = rgb & 0xFFFEFFFF); else rgb = (rgb | 0x00010000); //Chỉnh sửa giá trị G if(binHidden[i++] == '0')rgb = rgb & 0xFFFFFEFF); else rgb = (rgb | 0x00000100); //Chỉnh sửa giá trị B if(binHidden[i++] == '0')rgb = rgb & 0xFFFFFFFE); else rgb = (rgb | 0x00000001); buff.setRGB(x, y, rgb); //Cập nhật lại RGB cho pixel này
DECODE
Để việc lấy ra các bit LSB đã Encode trước đó một cách đơn giản ta có thể sử dụng các thư viện hỗ trợ sau:
- Lớp java.awt.Color hỗ trợ làm việc với giá trị màu dễ dàng hơn từ một giá trị RGB kiểu integer lấy được từ phương thức getRGB(x, y)
- Phương thức toBinaryString(int value) của lớp Integer để lấy chuỗi nhị phân của biến value
Source Code:
int rgb = buff.getRGB(100,100); //Lấy một RGB(215, 162, 11) Color c = new Color(rgb); //Tạo đối tượng Color từ một giá trị RGB int R = c.getRed(); // Trả về 215 int G = c.getGreen(); // Trả về 162 int B = c.getBlue(); // Trả về 11 String rString = Integer.toBinaryString(R); // Trả về 11010111 String gString = Integer.toBinaryString(G); // Trả về 10100010 String bString = Integer.toBinaryString(B); // Trả về 00001011Từ đây ta sẽ lấy được giá trị ẩn ban đầu là “101”
Phần trên tôi đã giải thích chi tiết cách cài đặt thuật toán LSB Steganography, các bạn có thể dựa vào đó viết một chương trình Encode và Decode cho riêng mình, một số chi tiết lập trình hỗ trợ cho thuật toán như việc chuyển đổi chuỗi SECRET sang nhị phân, xác định điểm ngắt trong phương thức Encode và Decode để chèn và dịch ra chuỗi một cách hợp lý, phần này tùy mỗi người nghĩ ra một cách khác nhau. Riêng tôi sẽ chia sẻ Source Code của mình trong Link đính kèm, các bạn có thể tham khảo.
Trong Source Code có 2 Class:
- UITSteg.java chứa code cung cấp các phương thức Encode/Decode và các phương thức hỗ trợ
- UITStegGui.java: Cài đặt giao diện đồ họa cho chương trình
Tải sourcode tại đây
LSB Steganography chỉ là một thuật toán đơn giản trong mảng Steganography Image, vẫn còn một số vấn đề với thuật toán này, tôi chỉ mới tìm hiểu và gặp các vấn đề này khi hiện thực thuật toán, hiên tại vẫn chưa có thời gian tìm cách giải quyết:
- Việc kiểm soát dung lượng tập tin hình ảnh sau khi thực hiện Encode: Các tập tin hình ảnh nguồn có các định dạng khác nhau (BMP, PNG, JPG,...), việc đọc dữ liệu vào một Buffered Image sẽ gỡ bỏ các chuẩn nén từ trước của hình ảnh, đặt biệt là JPG/JPEG nên sau khi Encode, tập tin tạo ra sẽ gặp một số vấn đề về dung lượng, nếu muốn tập tin không thay đổi dung lượng và không bị mất mát dữ liệu ta phải tìm hiểu thật kỹ về các chuẩn PNG, JPEG,...
- Xác định số bit LSB sẽ thay đổi hợp lý: Không có quy định về số bit sẽ thay đổi nhưng việc thay đổi nhiều hơn 1 bit LSB sẽ tăng khả năng phát hiện ra sự thay đổi bằng mắt thường, vì việc này tác động trực tiếp đến giá trị màu của các điểm ảnh.
Đến đây hi vọng các bạn sẽ có cái nhìn chung về Steganography, trong chuỗi bài viết này có sai xót gì mọi người góp ý hoặc có phương pháp nào mình thấy hay có thể chia sẻ để cùng thảo luận tại đây.
Hẹn gặp lại ở bài kế tiếp! :)
hóng viết tiếp :3
Trả lờiXóaM vào tới đây rồi hả :3 Viết blog note lại kinh nghiệm cho anh em xem với m :D
XóaCó code với thuật toán SES ko bạn ơi.? Làm BTL mà bí quá
Trả lờiXóaa cho e hỏi là nếu mỗi lần mình thay thế 2,3 hoặc 4bit lsb thì làm ntn ạ e cảm ơn
Trả lờiXóaGiấu ảnh trong ảnh thì sao a?
Trả lờiXóa