Merasa seperti agen rahasia: Pesan tersembunyi dalam gambar dengan steganografi ️🕵️‍♀️

James Bond, Ethan Hunt, Napoleon Solo – agen rahasia yang bekerja dalam penyamaran, mengirim pesan rahasia ke majikan mereka dan agen lainnya. Jujur saja, agen rahasia itu keren. Setidaknya di film dan buku. Mereka mendapatkan gadget yang luar biasa, memburu penjahat, mengunjungi klub mewah dengan pakaian mewah. Dan pada akhirnya, mereka menyelamatkan dunia. Ketika saya masih kecil, saya ingin sekali menjadi agen rahasia.

Dalam posting ini, saya akan menunjukkan teknik yang mungkin digunakan oleh agen rahasia untuk menyembunyikan gambar di dalam gambar lain: Steganografi.

Tapi pertama-tama: Apa sih steganografi itu?

Steganografi bisa menjadi sesuatu yang ditemukan oleh insinyur terkenal Q dari MI6 dalam film "James Bond", tetapi sebenarnya jauh lebih tua! Menyembunyikan pesan atau gambar dari mata yang seharusnya tidak melihatnya adalah hal yang sudah ada sejak zaman kuno.

Menurut Wikipedia, pada 440 SM, Herodotus, seorang penulis Yunani kuno, pernah mencukur kepala salah satu pelayannya yang paling setia untuk menulis pesan di kepala botak mereka dan mengirim pelayan itu ke penerima begitu rambut mereka tumbuh kembali.

Kami tidak akan mencukur siapa pun hari ini, apalagi menyembunyikan pesan di kepala satu sama lain. Sebagai gantinya, kami menyembunyikan gambar di gambar lain.

Untuk melakukan ini, kami menyingkirkan bagian yang tidak penting dari warna satu gambar dan menggantinya dengan bagian penting dari warna gambar lain.

Tunggu apa? Signifikan, tidak signifikan?

Untuk memahami apa artinya, pertama-tama kita perlu mengetahui cara kerja warna, misalnya, di PNG. Pengembang web mungkin akrab dengan notasi hex warna, seperti #f60053 , atau #16ee8a . Warna heksagonal terdiri dari empat bagian berbeda:

  • A # sebagai awalan
  • Dua digit hex untuk merah
  • Dua digit heksagonal untuk hijau
  • Dua digit heksagonal untuk warna biru

Karena nilainya bisa dari 00 ke FF untuk setiap warna, ini berarti dari 0 ke 255 dalam desimal. Dalam biner, itu akan berubah dari 00000000 ke 11111111 .

Biner bekerja sangat mirip dengan desimal: Semakin kiri satu digit, semakin tinggi nilainya. Oleh karena itu, "makna" dari sedikit meningkat, semakin ke kiri.

Sebagai contoh: 11111111 hampir dua kali lebih besar dari 01111111 , 11111110 di sisi lain hanya sedikit lebih kecil. Mata manusia kemungkinan besar tidak akan melihat perbedaan antara #FFFFFF dan #FEFEFE . Ini akan melihat perbedaan antara #FFFFFF dan #7F7F7F .

Mari sembunyikan gambar dengan JS

Mari kita sembunyikan gambar stok ini:

Gambar stok komputer dengan beberapa keluaran CLI

pada gambar kucing ini:

Kucing oranye berbulu orange

Saya akan menulis skrip Node kecil untuk menyembunyikan gambar di tempat lain. Ini berarti skrip saya perlu mengambil tiga argumen:

  • gambar utama
  • Gambar tersembunyi
  • Tempat tujuan

Mari kita buat kode ini terlebih dahulu:

 const args = process . argv . slice ( 2 ) const mainImagePath = args [ 0 ] const hiddenImagePath = args [ 1 ] const targetImagePath = args [ 2 ] // Usage: // node hide-image.js ./cat.png ./hidden.png ./target.png

Sejauh ini bagus. Sekarang saya akan menginstal ukuran gambar untuk mendapatkan ukuran gambar utama dan kanvas untuk simpul untuk memeriksa gambar dan menghasilkan gambar baru.

Pertama, mari kita cari tahu dimensi gambar utama dan gambar rahasia dan buat kanvas untuk keduanya. Saya juga akan membuat kanvas untuk gambar keluaran:

 const imageSize = require ( ' image-size ' ) const { createCanvas , loadImage } = require ( ' canvas ' ) const args = process . argv . slice ( 2 ) const mainImagePath = args [ 0 ] const hiddenImagePath = args [ 1 ] const targetImagePath = args [ 2 ] const sizeMain = imageSize ( mainImagePath ) const sizeHidden = imageSize ( hiddenImagePath ) const canvasMain = createCanvas ( sizeMain . width , sizeMain . height ) const canvasHidden = createCanvas ( sizeHidden . width , sizeHidden . height ) const canvasTarget = createCanvas ( sizeMain . width , sizeMain . height ) const contextMain = canvasMain . getContext ( ' 2d ' ) const contextHidden = canvasHidden . getContext ( ' 2d ' ) const contextTarget = canvasTarget . getContext ( ' 2d ' )

Selanjutnya, saya perlu memuat kedua gambar ke kanvas masing-masing. Karena metode ini mengembalikan janji, saya meletakkan sisa kode dalam ekspresi fungsi yang segera dipanggil yang memungkinkan untuk async/menunggu:

 ;( async () => { const mainImage = await loadImage ( mainImagePath ) contextMain . drawImage ( mainImage , 0 , 0 , sizeMain . width , sizeMain . height ) const hiddenImage = await loadImage ( hiddenImagePath ) contextHidden . drawImage ( hiddenImage , 0 , 0 , sizeHidden . width , sizeHidden . height ) })()

Selanjutnya, saya mengulangi setiap piksel gambar dan mendapatkan nilai warnanya:

 for ( let x = 0 ; x < sizeHidden . width ; x ++ ) { for ( let y = 0 ; y < sizeHidden . height ; y ++ ) { const colorMain = Array . from ( contextMain . getImageData ( x , y , 1 , 1 ). data ) const colorHidden = Array . from ( contextHidden . getImageData ( x , y , 1 , 1 ). data ) } }

Dengan nilai-nilai ini, sekarang saya dapat menghitung warna "gabungan" dari setiap piksel yang akan saya gambar ke dalam gambar target.

Menghitung warna baru

Saya mengatakan sesuatu tentang bagian penting sebelumnya. Untuk benar-benar menghitung warna, izinkan saya mengilustrasikan ini sedikit lebih jauh.

Katakanlah, saya ingin menggabungkan bagian merah dari warna A dan B. Saya akan mewakili bit mereka (8bit) sebagai berikut:

 A7 A6 A5 A4 A3 A2 A1 A0 (color A) B7 B6 B5 B4 B3 B2 B1 B0 (color B)

Untuk menyembunyikan warna B pada warna A, saya mengganti yang pertama (paling kanan), katakanlah, 3 bit A dengan bit terakhir (paling kiri) B. Pola bit yang dihasilkan akan terlihat seperti ini:

 A7 A6 A5 A4 A3 B7 B6 B5

Artinya, saya kehilangan beberapa informasi dari kedua warna tersebut, tetapi warna gabungannya tidak akan terlihat jauh berbeda dari warna B itu sendiri.

Mari kita kode ini:

 const combineColors = ( a , b ) => { const aBinary = a . toString ( 2 ). padStart ( 8 , ' 0 ' ) const bBinary = b . toString ( 2 ). padStart ( 8 , ' 0 ' ) return parseInt ( '' + aBinary [ 0 ] + aBinary [ 1 ] + aBinary [ 2 ] + aBinary [ 3 ] + aBinary [ 4 ] + bBinary [ 0 ] + bBinary [ 1 ] + bBinary [ 2 ], 2 ) }

Saya sekarang dapat menggunakan fungsi itu di loop piksel:

 const colorMain = Array . from ( contextMain . getImageData ( x , y , 1 , 1 ). data ) const colorHidden = Array . from ( contextHidden . getImageData ( x , y , 1 , 1 ). data ) const combinedColor = [ combineColors ( colorMain [ 0 ], colorHidden [ 0 ]), combineColors ( colorMain [ 1 ], colorHidden [ 1 ]), combineColors ( colorMain [ 2 ], colorHidden [ 2 ]), ] contextTarget . fillStyle = `rgb( ${ combinedColor [ 0 ]} , ${ combinedColor [ 1 ]} , ${ combinedColor [ 2 ]} )` contextTarget . fillRect ( x , y , 1 , 1 )

Hampir sampai, sekarang saya hanya perlu menyimpan gambar yang dihasilkan:

 const buffer = canvasTarget . toBuffer ( ' image/png ' ) fs . writeFileSync ( targetImagePath , buffer )

Dan inilah hasilnya:

Gambar tersembunyi di gambar kucing dari atas

Tergantung pada pengaturan layar Anda, Anda mungkin melihat pola gambar tersembunyi di bagian atas gambar. Biasanya, Anda akan menggunakan gambar yang lebih mengaburkan gambar tersembunyi.

Dan bagaimana cara mengembalikan gambar yang tersembunyi?

Untuk mengekstrak gambar tersembunyi, yang diperlukan hanyalah membaca 3 bit terakhir dari setiap piksel dan menjadikannya bit paling signifikan lagi:

 const extractColor = c => { const cBinary = c . toString ( 2 ). padStart ( 8 , ' 0 ' ) return parseInt ( '' + cBinary [ 5 ] + cBinary [ 6 ] + cBinary [ 7 ] + ' 00000 ' , 2 ) }

Jika saya melakukan ini untuk setiap piksel, saya mendapatkan gambar asli lagi (ditambah beberapa artefak):

Gambar asli dengan kualitas lebih rendah

Sekarang Anda dapat merasa seperti agen rahasia nyata dengan menyembunyikan gambar dan mengirim pesan tersembunyi ke agen rahasia lainnya!

Saya harap Anda menikmati membaca artikel ini sama seperti saya menikmati menulisnya! Jika demikian, tinggalkan ❤️ atau ! Saya menulis artikel teknologi di waktu luang saya dan suka minum kopi sesekali.

Jika Anda ingin mendukung upaya saya, belikan saya kopi atau ikuti saya di Twitter ! Anda juga dapat mendukung saya secara langsung melalui Paypal !

Belikan aku tombol kopi

June 20, 2021

codeorayo

Ampuh! Ini rahasia mengembangkan aplikasi secara instan, tinggal download dan kembangkan. Gabung sekarang juga! Premium Membership [PRIVATE] https://premium.codeorayo.com

Leave a Reply

Your email address will not be published. Required fields are marked *