GIF์˜ ์Šคํ…Œ๊ฐ€๋…ธ๊ทธ๋ž˜ํ”ผ

์†Œ๊ฐœ

์— ์˜ค์‹  ๊ฒƒ์„ ํ™˜์˜ํ•ฉ๋‹ˆ๋‹ค.
์–ผ๋งˆ ์ „ ์ œ๊ฐ€ ๋Œ€ํ•™์—์„œ ๊ณต๋ถ€ํ•  ๋•Œ "์ •๋ณด ๋ณด์•ˆ์˜ ์†Œํ”„ํŠธ์›จ์–ด ๋ฐฉ๋ฒ•"์ด๋ผ๋Š” ๋ถ„์•ผ์˜ ๊ต๊ณผ ๊ณผ์ •์ด ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. ๊ณผ์ œ๋ฅผ ์ˆ˜ํ–‰ํ•˜๋ ค๋ฉด GIF ํŒŒ์ผ์— ๋ฉ”์‹œ์ง€๋ฅผ ์‚ฝ์ž…ํ•˜๋Š” ํ”„๋กœ๊ทธ๋žจ์„ ๋งŒ๋“ค์–ด์•ผ ํ–ˆ์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” ์ž๋ฐ”๋กœ ํ•˜๊ธฐ๋กœ ๊ฒฐ์ •ํ–ˆ๋‹ค.

์ด ๊ธฐ์‚ฌ์—์„œ๋Š” ๋ช‡ ๊ฐ€์ง€ ์ด๋ก ์  ์š”์ ๊ณผ ์ด ์ž‘์€ ํ”„๋กœ๊ทธ๋žจ์ด ์–ด๋–ป๊ฒŒ ๋งŒ๋“ค์–ด์กŒ๋Š”์ง€ ์„ค๋ช…ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ด๋ก ์ ์ธ ๋ถ€๋ถ„

GIF ํ˜•์‹

GIF(Graphics Interchange Format - ์ด๋ฏธ์ง€ ๊ตํ™˜ ํ˜•์‹)๋Š” ๊ทธ๋ž˜ํ”ฝ ์ด๋ฏธ์ง€๋ฅผ ์ €์žฅํ•˜๋Š” ํ˜•์‹์œผ๋กœ, ์ตœ๋Œ€ 256์ƒ‰ ํ˜•์‹์œผ๋กœ ์••์ถ•๋œ ๋ฐ์ดํ„ฐ๋ฅผ ํ’ˆ์งˆ ์ €ํ•˜ ์—†์ด ์ €์žฅํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ํ˜•์‹์€ ๋„คํŠธ์›Œํฌ๋ฅผ ํ†ตํ•ด ๋ž˜์Šคํ„ฐ ์ด๋ฏธ์ง€๋ฅผ ์ „์†กํ•˜๊ธฐ ์œ„ํ•ด CompuServe๊ฐ€ 1987๋…„(GIF87a)์— ๊ฐœ๋ฐœํ–ˆ์Šต๋‹ˆ๋‹ค. 1989๋…„์—๋Š” ํ˜•์‹์ด ์ˆ˜์ •๋˜์—ˆ๊ณ (GIF89a) ํˆฌ๋ช…๋„ ๋ฐ ์• ๋‹ˆ๋ฉ”์ด์…˜์— ๋Œ€ํ•œ ์ง€์›์ด ์ถ”๊ฐ€๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

GIF ํŒŒ์ผ์€ ๋ธ”๋ก ๊ตฌ์กฐ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๋ธ”๋ก์€ ํ•ญ์ƒ ๊ณ ์ •๋œ ๊ธธ์ด๋ฅผ ๊ฐ€์ง€๋ฏ€๋กœ(๋˜๋Š” ์ผ๋ถ€ ํ”Œ๋ž˜๊ทธ์— ๋”ฐ๋ผ ๋‹ค๋ฆ„) ๊ฐ ๋ธ”๋ก์˜ ์œ„์น˜๋ฅผ โ€‹โ€‹์‹ค์ˆ˜ํ•˜๋Š” ๊ฒƒ์€ ๊ฑฐ์˜ ๋ถˆ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. GIF89a ํ˜•์‹์˜ ๊ฐ€์žฅ ๋‹จ์ˆœํ•œ ๋น„์• ๋‹ˆ๋ฉ”์ด์…˜ GIF ์ด๋ฏธ์ง€์˜ ๊ตฌ์กฐ:

GIF์˜ ์Šคํ…Œ๊ฐ€๋…ธ๊ทธ๋ž˜ํ”ผ

๊ตฌ์กฐ์˜ ๋ชจ๋“  ๋ธ”๋ก ์ค‘์—์„œ ์ด ๊ฒฝ์šฐ ์šฐ๋ฆฌ๋Š” ์ „์—ญ ํŒ”๋ ˆํŠธ ๋ธ”๋ก๊ณผ ํŒ”๋ ˆํŠธ๋ฅผ ๋‹ด๋‹นํ•˜๋Š” ๋งค๊ฐœ๋ณ€์ˆ˜์— ๊ด€์‹ฌ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

  • CT โ€” ๊ธ€๋กœ๋ฒŒ ํŒ”๋ ˆํŠธ์˜ ์กด์žฌ. ์ด ํ”Œ๋ž˜๊ทธ๊ฐ€ ์„ค์ •๋˜๋ฉด ์ „์—ญ ํŒ”๋ ˆํŠธ๋Š” ๋…ผ๋ฆฌ ํ™”๋ฉด ํ•ธ๋“ค ๋ฐ”๋กœ ๋’ค์—์„œ ์‹œ์ž‘๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  • Size โ€” ๊ทธ๋ฆผ์˜ ํŒ”๋ ˆํŠธ ํฌ๊ธฐ ๋ฐ ์ƒ‰์ƒ ์ˆ˜. ์ด ๋งค๊ฐœ๋ณ€์ˆ˜์˜ ๊ฐ’:

ํฌ๊ธฐ
์ƒ‰์ƒ ์ˆ˜
ํŒ”๋ ˆํŠธ ํฌ๊ธฐ, ๋ฐ”์ดํŠธ

7
256
768

6
128
384

5
64
192

4
32
96

3
16
48

2
8
24

1
4
12

0
2
6

์•”ํ˜ธํ™” ๋ฐฉ๋ฒ•

์ด๋ฏธ์ง€ ํŒŒ์ผ์˜ ๋ฉ”์‹œ์ง€๋ฅผ ์•”ํ˜ธํ™”ํ•˜๋Š” ๋ฐ๋Š” ๋‹ค์Œ ๋ฐฉ๋ฒ•์ด ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

  • LSB(์ตœํ•˜์œ„ ๋น„ํŠธ) ๋ฐฉ์‹
  • ํŒ”๋ ˆํŠธ ์ถ”๊ฐ€ ๋ฐฉ๋ฒ•

LSB ๋ฐฉ์‹ - ์Šคํ…Œ๊ฐ€๋…ธ๊ทธ๋ž˜ํ”ผ์˜ ์ผ๋ฐ˜์ ์ธ ๋ฐฉ๋ฒ•. ์ด๋Š” ์ปจํ…Œ์ด๋„ˆ์˜ ๋งˆ์ง€๋ง‰ ์ค‘์š”ํ•œ ๋น„ํŠธ(์šฐ๋ฆฌ์˜ ๊ฒฝ์šฐ ์ „์—ญ ํŒ”๋ ˆํŠธ ๋ฐ”์ดํŠธ)๋ฅผ ์ˆจ๊ฒจ์ง„ ๋ฉ”์‹œ์ง€์˜ ๋น„ํŠธ๋กœ ๋ฐ”๊พธ๋Š” ๊ฒƒ์œผ๋กœ ๊ตฌ์„ฑ๋ฉ๋‹ˆ๋‹ค.

ํ”„๋กœ๊ทธ๋žจ์€ ์ด ๋ฐฉ๋ฒ•์˜ ์ผ๋ถ€๋กœ ์ „์—ญ ํŒ”๋ ˆํŠธ ๋ฐ”์ดํŠธ์˜ ๋งˆ์ง€๋ง‰ ๋‘ ๋น„ํŠธ๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ์ƒ‰์ƒ ํŒ”๋ ˆํŠธ๊ฐ€ ๋นจ๊ฐ„์ƒ‰, ํŒŒ๋ž€์ƒ‰, ๋…น์ƒ‰์˜ 24๋ฐ”์ดํŠธ์ธ 3๋น„ํŠธ ์ด๋ฏธ์ง€์˜ ๊ฒฝ์šฐ ๋ฉ”์‹œ์ง€๋ฅผ ์‚ฝ์ž…ํ•œ ํ›„ ๊ฐ ์ƒ‰์ƒ ๊ตฌ์„ฑ ์š”์†Œ๊ฐ€ ์ตœ๋Œ€ 255/XNUMX ๊ทธ๋ผ๋ฐ์ด์…˜๋งŒํผ ๋ณ€๊ฒฝ๋œ๋‹ค๋Š” ์˜๋ฏธ์ž…๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๋ณ€ํ™”๋Š” ์ฒซ์งธ, ์ธ๊ฐ„์˜ ๋ˆˆ์— ๋ณด์ด์ง€ ์•Š๊ฑฐ๋‚˜ ์•Œ์•„์ฐจ๋ฆฌ๊ธฐ ์–ด๋ ค์šธ ๊ฒƒ์ด๋ฉฐ, ๋‘˜์งธ, ํ’ˆ์งˆ์ด ๋‚ฎ์€ ์ •๋ณด ์ถœ๋ ฅ ์žฅ์น˜์—์„œ๋Š” ๋ณด์ด์ง€ ์•Š์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ •๋ณด์˜ ์–‘์€ ์ด๋ฏธ์ง€ ํŒ”๋ ˆํŠธ์˜ ํฌ๊ธฐ์— ๋”ฐ๋ผ ์ง์ ‘์ ์œผ๋กœ ๋‹ฌ๋ผ์ง‘๋‹ˆ๋‹ค. ํŒ”๋ ˆํŠธ์˜ ์ตœ๋Œ€ ํฌ๊ธฐ๋Š” 256์ƒ‰์ด๊ณ  ๋‘ ๊ฐœ์˜ ๋ฉ”์‹œ์ง€ ๋น„ํŠธ๊ฐ€ ๊ฐ ์ƒ‰์ƒ์˜ ๊ตฌ์„ฑ ์š”์†Œ์— ๊ธฐ๋ก๋˜๋ฉด ์ตœ๋Œ€ ๋ฉ”์‹œ์ง€ ๊ธธ์ด(์ด๋ฏธ์ง€์˜ ์ตœ๋Œ€ ํŒ”๋ ˆํŠธ ํฌํ•จ)๋Š” 192๋ฐ”์ดํŠธ์ž…๋‹ˆ๋‹ค. ๋ฉ”์‹œ์ง€๊ฐ€ ์ด๋ฏธ์ง€์— ์‚ฝ์ž…๋˜๋ฉด ํŒŒ์ผ ํฌ๊ธฐ๋Š” ๋ณ€๊ฒฝ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

ํŒ”๋ ˆํŠธ ํ™•์žฅ ๋ฐฉ๋ฒ•, ์ด๋Š” GIF ๊ตฌ์กฐ์—์„œ๋งŒ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค. ํŒ”๋ ˆํŠธ๊ฐ€ ์ž‘์€ ์ด๋ฏธ์ง€์— ๊ฐ€์žฅ ํšจ๊ณผ์ ์ž…๋‹ˆ๋‹ค. ๊ทธ ๋ณธ์งˆ์€ ํŒ”๋ ˆํŠธ์˜ ํฌ๊ธฐ๋ฅผ ๋Š˜๋ ค ์ปฌ๋Ÿฌ ๋ฐ”์ดํŠธ ๋Œ€์‹  ํ•„์š”ํ•œ ๋ฐ”์ดํŠธ๋ฅผ ์“ธ ์ˆ˜ ์žˆ๋Š” ์ถ”๊ฐ€ ๊ณต๊ฐ„์„ ์ œ๊ณตํ•œ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ํŒ”๋ ˆํŠธ์˜ ์ตœ์†Œ ํฌ๊ธฐ๊ฐ€ 2๊ฐ€์ง€ ์ƒ‰์ƒ(6๋ฐ”์ดํŠธ)์ด๋ผ๊ณ  ๊ฐ€์ •ํ•˜๋ฉด ํฌํ•จ๋œ ๋ฉ”์‹œ์ง€์˜ ์ตœ๋Œ€ ํฌ๊ธฐ๋Š” 256 ร— 3โ€“6 = 762๋ฐ”์ดํŠธ๊ฐ€ ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‹จ์ ์€ ์•”ํ˜ธํ™” ๋ณด์•ˆ์ด ๋‚ฎ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋ฉ”์‹œ์ง€์— ์ถ”๊ฐ€ ์•”ํ˜ธํ™”๊ฐ€ ์ ์šฉ๋˜์ง€ ์•Š์€ ๊ฒฝ์šฐ ํ…์ŠคํŠธ ํŽธ์ง‘๊ธฐ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํฌํ•จ๋œ ๋ฉ”์‹œ์ง€๋ฅผ ์ฝ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์‹ค์šฉ์ ์ธ ๋ถ€๋ถ„

ํ”„๋กœ๊ทธ๋žจ ์„ค๊ณ„

์•”ํ˜ธํ™” ๋ฐ ์•”ํ˜ธ ํ•ด๋… ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ๊ตฌํ˜„ํ•˜๋Š” ๋ฐ ํ•„์š”ํ•œ ๋ชจ๋“  ๋„๊ตฌ๊ฐ€ ํŒจํ‚ค์ง€์— ํฌํ•จ๋ฉ๋‹ˆ๋‹ค. com.tsarik.steganography. ์ด ํŒจํ‚ค์ง€์—๋Š” ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ ํฌํ•จ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. Encryptor ๋ฐฉ๋ฒ•์œผ๋กœ encrypt ะธ decrypt, ์ˆ˜์—… Binary, ๋น„ํŠธ ๋ฐฐ์—ด ๋ฐ ์˜ˆ์™ธ ํด๋ž˜์Šค๋กœ ์ž‘์—…ํ•  ์ˆ˜ ์žˆ๋Š” ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. UnableToEncryptException ะธ UnableToDecryptException, ์ธํ„ฐํŽ˜์ด์Šค ๋ฉ”์†Œ๋“œ์— ์‚ฌ์šฉํ•ด์•ผ ํ•จ Encryptor ์ธ์ฝ”๋”ฉ ๋ฐ ๋””์ฝ”๋”ฉ ์˜ค๋ฅ˜๊ฐ€ ๊ฐ๊ฐ ๋ฐœ์ƒํ•œ ๊ฒฝ์šฐ.

์ฃผ์š” ํ”„๋กœ๊ทธ๋žจ ํŒจํ‚ค์ง€ com.tsarik.programs.gifed ์ •์  ๋ฉ”์„œ๋“œ๊ฐ€ ์žˆ๋Š” ์‹คํ–‰ ๊ฐ€๋Šฅํ•œ ํ”„๋กœ๊ทธ๋žจ ํด๋ž˜์Šค๊ฐ€ ํฌํ•จ๋ฉ๋‹ˆ๋‹ค. main, ํ”„๋กœ๊ทธ๋žจ์„ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ”„๋กœ๊ทธ๋žจ ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ์ €์žฅํ•˜๋Š” ํด๋ž˜์Šค; ๋‹ค๋ฅธ ํด๋ž˜์Šค์™€ ํŒจํ‚ค์ง€.

์•Œ๊ณ ๋ฆฌ์ฆ˜ ์ž์ฒด์˜ ๊ตฌํ˜„์€ ํŒจํ‚ค์ง€์— ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค. com.tsarik.programs.gifed.gif ํด๋ž˜์Šค GIFEncryptorByLSBMethod ะธ GIFEncryptorByPaletteExtensionMethod. ์ด ๋‘ ํด๋ž˜์Šค ๋ชจ๋‘ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค. Encryptor.

GIF ํ˜•์‹์˜ ๊ตฌ์กฐ๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ์ด๋ฏธ์ง€ ํŒ”๋ ˆํŠธ์— ๋ฉ”์‹œ์ง€๋ฅผ ์‚ฝ์ž…ํ•˜๊ธฐ ์œ„ํ•œ ์ผ๋ฐ˜ ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

GIF์˜ ์Šคํ…Œ๊ฐ€๋…ธ๊ทธ๋ž˜ํ”ผ

์ด๋ฏธ์ง€์— ๋ฉ”์‹œ์ง€๊ฐ€ ์žˆ๋Š”์ง€ ํ™•์ธํ•˜๋ ค๋ฉด ๋ฉ”์‹œ์ง€ ์‹œ์ž‘ ๋ถ€๋ถ„์— ํŠน์ • ๋น„ํŠธ ์‹œํ€€์Šค๋ฅผ ์ถ”๊ฐ€ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋ฉด ๋””์ฝ”๋”๊ฐ€ ๋จผ์ € ์ด๋ฅผ ์ฝ๊ณ  ์ •ํ™•์„ฑ์„ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค. ์ผ์น˜ํ•˜์ง€ ์•Š์œผ๋ฉด ์ด๋ฏธ์ง€์— ์ˆจ๊ฒจ์ง„ ๋ฉ”์‹œ์ง€๊ฐ€ ์—†๋Š” ๊ฒƒ์œผ๋กœ ๊ฐ„์ฃผ๋ฉ๋‹ˆ๋‹ค. ๋‹ค์Œ์œผ๋กœ ๋ฉ”์‹œ์ง€ ๊ธธ์ด๋ฅผ ์ง€์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ ๋‹ค์Œ ๋ฉ”์‹œ์ง€ ์ž์ฒด์˜ ํ…์ŠคํŠธ์ž…๋‹ˆ๋‹ค.

์ „์ฒด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ํด๋ž˜์Šค ๋‹ค์ด์–ด๊ทธ๋žจ:

GIF์˜ ์Šคํ…Œ๊ฐ€๋…ธ๊ทธ๋ž˜ํ”ผ

ํ”„๋กœ๊ทธ๋žจ ๊ตฌํ˜„

์ „์ฒด ํ”„๋กœ๊ทธ๋žจ์˜ ๊ตฌํ˜„์€ ์ธํ„ฐํŽ˜์ด์Šค ์•”ํ˜ธํ™” ๊ตฌํ˜„๊ณผ ์•”ํ˜ธ ํ•ด๋… ๋ฐฉ๋ฒ•์˜ ๋‘ ๊ฐ€์ง€ ๊ตฌ์„ฑ ์š”์†Œ๋กœ ๋‚˜๋ˆŒ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. Encryptor, ์ˆ˜์—… ์ค‘ GIFEncryptorByLSBMethod ะธ GIFEncryptorByPaletteExtensionMethod, ์‚ฌ์šฉ์ž ์ธํ„ฐํŽ˜์ด์Šค ๊ตฌํ˜„.

์ˆ˜์—…์„ ๊ณ ๋ คํ•ด๋ณด์„ธ์š” GIFEncryptorByLSBMethod.

GIF์˜ ์Šคํ…Œ๊ฐ€๋…ธ๊ทธ๋ž˜ํ”ผ

๋ถ„์•ผ firstLSBit ะธ secondLSBit ๋ฉ”์‹œ์ง€๊ฐ€ ์ž…๋ ฅ๋˜์–ด์•ผ ํ•˜๊ณ  ๋ฉ”์‹œ์ง€๋ฅผ ์ฝ์–ด์•ผ ํ•˜๋Š” ์ด๋ฏธ์ง€์˜ ๊ฐ ๋ฐ”์ดํŠธ์˜ ๋น„ํŠธ ์ˆ˜๋ฅผ ํฌํ•จํ•ฉ๋‹ˆ๋‹ค. ํ•„๋“œ checkSequence ํฌํ•จ๋œ ๋ฉ”์‹œ์ง€์˜ ์ธ์‹์„ ๋ณด์žฅํ•˜๊ธฐ ์œ„ํ•ด ๊ฒ€์‚ฌ ๋น„ํŠธ ์‹œํ€€์Šค๋ฅผ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค. ์ •์  ๋ฐฉ๋ฒ• getEncryptingFileParameters ์ง€์ •๋œ ํŒŒ์ผ์˜ ๋งค๊ฐœ๋ณ€์ˆ˜์™€ ์ž ์žฌ์ ์ธ ๋ฉ”์‹œ์ง€์˜ ํŠน์„ฑ์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

๋ฐฉ๋ฒ• ์•Œ๊ณ ๋ฆฌ์ฆ˜ encrypt ํด๋ž˜์Šค GIFEncryptorByLSBMethod:

GIF์˜ ์Šคํ…Œ๊ฐ€๋…ธ๊ทธ๋ž˜ํ”ผ

๊ทธ์˜ ์ฝ”๋“œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

@Override
public void encrypt(File in, File out, String text) throws UnableToEncodeException, NullPointerException, IOException {
	if (in == null) {
		throw new NullPointerException("Input file is null");
	}
	if (out == null) {
		throw new NullPointerException("Output file is null");
	}
	if (text == null) {
		throw new NullPointerException("Text is null");
	}
	
	// read bytes from input file
	byte[] bytes = new byte[(int)in.length()];
	InputStream is = new FileInputStream(in);
	is.read(bytes);
	is.close();
	
	// check format
	if (!(new String(bytes, 0, 6)).equals("GIF89a")) {
		throw new UnableToEncodeException("Input file has wrong GIF format");
	}
	
	// read palette size property from first three bits in the 10-th byte from the file
	byte[] b10 = Binary.toBitArray(bytes[10]);
	byte bsize = Binary.toByte(new byte[] {b10[0], b10[1], b10[2]});
	
	// calculate color count and possible message length
	int bOrigColorCount = (int)Math.pow(2, bsize+1);
	int possibleMessageLength = bOrigColorCount*3/4;
	int possibleTextLength = possibleMessageLength-2;// one byte for check and one byte for message length
	
	if (possibleTextLength < text.length()) {
		throw new UnableToEncodeException("Text is too big");
	}
	
	int n = 13;
	
	// write check sequence
	for (int i = 0; i < checkSequence.length/2; i++) {
		byte[] ba = Binary.toBitArray(bytes[n]);
		ba[firstLSBit] = checkSequence[2*i];
		ba[secondLSBit] = checkSequence[2*i+1];
		bytes[n] = Binary.toByte(ba);
		n++;
	}
	
	// write text length
	byte[] cl = Binary.toBitArray((byte)text.length());
	for (int i = 0; i < cl.length/2; i++) {
		byte[] ba = Binary.toBitArray(bytes[n]);
		ba[firstLSBit] = cl[2*i];
		ba[secondLSBit] = cl[2*i+1];
		bytes[n] = Binary.toByte(ba);
		n++;
	}
	
	// write message
	byte[] textBytes = text.getBytes();
	for (int i = 0; i < textBytes.length; i++) {
		byte[] c = Binary.toBitArray(textBytes[i]);
		for (int ci = 0; ci < c.length/2; ci++) {
			byte[] ba = Binary.toBitArray(bytes[n]);
			ba[firstLSBit] = c[2*ci];
			ba[secondLSBit] = c[2*ci+1];
			bytes[n] = Binary.toByte(ba);
			n++;
		}
	}
	
	// write output file
	OutputStream os = new FileOutputStream(out);
	os.write(bytes);
	os.close();
}

๋ฉ”์†Œ๋“œ์˜ ์•Œ๊ณ ๋ฆฌ์ฆ˜ ๋ฐ ์†Œ์Šค ์ฝ”๋“œ decrypt ํด๋ž˜์Šค GIFEncryptorByLSBMethod:

GIF์˜ ์Šคํ…Œ๊ฐ€๋…ธ๊ทธ๋ž˜ํ”ผ

@Override
public String decrypt(File in) throws UnableToDecodeException, NullPointerException, IOException {
	if (in == null) {
		throw new NullPointerException("Input file is null");
	}
	
	// read bytes from input file
	byte[] bytes = new byte[(int)in.length()];
	InputStream is = new FileInputStream(in);
	is.read(bytes);
	is.close();
	
	// check format
	if (!(new String(bytes, 0, 6)).equals("GIF89a")) {
		throw new UnableToDecodeException("Input file has wrong GIF format");
	}
	
	// read palette size property from first three bits in the 10-th byte from the file
	byte[] b10 = Binary.toBitArray(bytes[10]);
	byte bsize = Binary.toByte(new byte[] {b10[0], b10[1], b10[2]});
	
	// calculate color count and possible message length
	int bOrigColorCount = (int)Math.pow(2, bsize+1);
	int possibleMessageLength = bOrigColorCount*3/4;
	int possibleTextLength = possibleMessageLength-2;	// one byte for check and one byte for message length
	
	int n = 13;
	
	// read check sequence
	byte[] csBits = new byte[checkSequence.length];
	for (int i = 0; i < 4; i++) {
		byte[] ba = Binary.toBitArray(bytes[n]);
		csBits[2*i] = ba[firstLSBit];
		csBits[2*i+1] = ba[secondLSBit];
		n++;
	}
	byte cs = Binary.toByte(csBits);
	
	if (cs != Binary.toByte(checkSequence)) {
		throw new UnableToDecodeException("There is no encrypted message in the image (Check sequence is incorrect)");
	}
	
	// read text length
	byte[] cl = new byte[8];
	for (int i = 0; i < 4; i++) {
		byte[] ba = Binary.toBitArray(bytes[n]);
		cl[2*i] = ba[firstLSBit];
		cl[2*i+1] = ba[secondLSBit];
		n++;
	}
	byte textLength = Binary.toByte(cl);
	
	if (textLength < 0) {
		throw new UnableToDecodeException("Decoded text length is less than 0");
	}
	if (possibleTextLength < textLength) {
		throw new UnableToDecodeException("There is no messages (Decoded message length (" + textLength + ") is less than Possible message length (" + possibleTextLength + "))");
	}
	
	// read text bits and make text bytes
	byte[] bt = new byte[textLength];
	for (int i = 0; i < bt.length; i++) {
		byte[] bc = new byte[8];
		for (int bci = 0; bci < bc.length/2; bci++) {
			byte[] ba = Binary.toBitArray(bytes[n]);
			bc[2*bci] = ba[firstLSBit];
			bc[2*bci+1] = ba[secondLSBit];
			n++;
		}
		bt[i] = Binary.toByte(bc);
	}
	
	return new String(bt);
}

ํด๋ž˜์Šค ๊ตฌํ˜„ GIFEncryptorByPaletteExtensionMethod ๋น„์Šทํ•  ๋ฟ ์ •๋ณด๋ฅผ ์ €์žฅ/์ฝ๋Š” ๋ฐฉ๋ฒ•๋งŒ ๋‹ค๋ฆ…๋‹ˆ๋‹ค.

ํด๋ž˜์Šค MainFrame ๋ž˜ํผ ๋ฉ”์„œ๋“œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์„ค๋ช…๋ฉ๋‹ˆ๋‹ค. encryptImage(Encryptor encryptor) ะธ decryptImage(Encryptor encryptor), ์ธํ„ฐํŽ˜์ด์Šค ๋ฉ”์†Œ๋“œ์˜ ๊ฒฐ๊ณผ ์ฒ˜๋ฆฌ Encryptor ์‚ฌ์šฉ์ž์™€์˜ ์ƒํ˜ธ ์ž‘์šฉ(์˜ˆ: ํŒŒ์ผ ์„ ํƒ ๋Œ€ํ™” ์ƒ์ž ์—ด๊ธฐ, ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€ ํ‘œ์‹œ ๋“ฑ) ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•๋“ค: openImage(), ์‚ฌ์šฉ์ž๊ฐ€ ์ด๋ฏธ์ง€๋ฅผ ์„ ํƒํ•  ์ˆ˜ ์žˆ๋„๋ก ํ—ˆ์šฉ, exit(), ์‘์šฉํ”„๋กœ๊ทธ๋žจ์„ ์ข…๋ฃŒํ•ฉ๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๋ฉ”์„œ๋“œ๋Š” ๋‹ค์Œ์—์„œ ํ˜ธ์ถœ๋ฉ๋‹ˆ๋‹ค. Action์˜ ํ•ด๋‹น ๋ฉ”๋‰ด ํ•ญ๋ชฉ์ž…๋‹ˆ๋‹ค. ์ด ํด๋ž˜์Šค๋Š” ์ถ”๊ฐ€๋กœ ๋ณด์กฐ ๋ฉ”์„œ๋“œ๋ฅผ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค. createComponents() - ์–‘์‹ ๊ตฌ์„ฑ ์š”์†Œ ์ƒ์„ฑ, loadImageFile(File f) โ€” ํŒŒ์ผ์—์„œ ํŠน์ˆ˜ ๊ตฌ์„ฑ ์š”์†Œ๋กœ ์ด๋ฏธ์ง€๋ฅผ ๋กœ๋“œํ•ฉ๋‹ˆ๋‹ค. ํด๋ž˜์Šค ๊ตฌํ˜„ GIFEncryptorByPaletteExtensionMethod ํด๋ž˜์Šค ๊ตฌํ˜„๊ณผ ์œ ์‚ฌ GIFEncryptorByLSBMethod, ์ฃผ์š” ์ฐจ์ด์ ์€ ํŒ”๋ ˆํŠธ์—์„œ ๋ฉ”์‹œ์ง€ ๋ฐ”์ดํŠธ๋ฅผ ์“ฐ๊ณ  ์ฝ๋Š” ๋ฐฉ์‹์— ์žˆ์Šต๋‹ˆ๋‹ค.

ํ”„๋กœ๊ทธ๋žจ ์šด์˜

LBS๋ฐฉ์‹

๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ด๋ฏธ์ง€๊ฐ€ ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

GIF์˜ ์Šคํ…Œ๊ฐ€๋…ธ๊ทธ๋ž˜ํ”ผ

์ด ์ด๋ฏธ์ง€์—์„œ ํŒ”๋ ˆํŠธ๋Š” 256๊ฐ€์ง€ ์ƒ‰์ƒ์œผ๋กœ ๊ตฌ์„ฑ๋ฉ๋‹ˆ๋‹ค(๊ทธ๋ฆผํŒ ์ €์žฅ). ์ฒ˜์Œ ๋„ค ๊ฐ€์ง€ ์ƒ‰์ƒ์€ ํฐ์ƒ‰, ๊ฒ€์ •์ƒ‰, ๋นจ๊ฐ„์ƒ‰, ๋…น์ƒ‰์ž…๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ์ƒ‰์ƒ์€ ๊ฒ€์ •์ƒ‰์ž…๋‹ˆ๋‹ค. ์ „์—ญ ํŒ”๋ ˆํŠธ ๋น„ํŠธ ์‹œํ€€์Šค๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

11111111 11111111 11111111 00000000 00000000 00000000 11111111 00000000 00000000 00000000 11111111 00000000...

GIF์˜ ์Šคํ…Œ๊ฐ€๋…ธ๊ทธ๋ž˜ํ”ผ

๋ฉ”์‹œ์ง€๊ฐ€ ํฌํ•จ๋˜๋ฉด ๋ฐ‘์ค„์ด ๊ทธ์–ด์ง„ ๋น„ํŠธ๊ฐ€ ๋ฉ”์‹œ์ง€์˜ ๋น„ํŠธ๋กœ ๋Œ€์ฒด๋ฉ๋‹ˆ๋‹ค. ๊ฒฐ๊ณผ ์ด๋ฏธ์ง€๋Š” ์›๋ณธ๊ณผ ๊ฑฐ์˜ ๋‹ค๋ฅด์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๋…์ฐฝ์  ์ธ
๋ฉ”์‹œ์ง€๊ฐ€ ํฌํ•จ๋œ ์ด๋ฏธ์ง€

GIF์˜ ์Šคํ…Œ๊ฐ€๋…ธ๊ทธ๋ž˜ํ”ผ
GIF์˜ ์Šคํ…Œ๊ฐ€๋…ธ๊ทธ๋ž˜ํ”ผ

ํŒ”๋ ˆํŠธ ํ™•์žฅ ๋ฐฉ๋ฒ•

์ด ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ•˜์—ฌ ๋ฉ”์‹œ์ง€๊ฐ€ ํฌํ•จ๋œ ์ด๋ฏธ์ง€๋ฅผ ์—ด๋ฉด ๋‹ค์Œ ๊ทธ๋ฆผ์ด ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค.

GIF์˜ ์Šคํ…Œ๊ฐ€๋…ธ๊ทธ๋ž˜ํ”ผ

์ด ๋ฐฉ๋ฒ•์€ ๋ณธ๊ฒฉ์ ์ธ ์ŠคํŒŒ์ด ํ™œ๋™์—๋Š” ์ž‘๋™ํ•˜์ง€ ์•Š์œผ๋ฉฐ ๋ฉ”์‹œ์ง€์— ๋Œ€ํ•œ ์ถ”๊ฐ€ ์•”ํ˜ธํ™”๊ฐ€ ํ•„์š”ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์€ ๋ถ„๋ช…ํ•ฉ๋‹ˆ๋‹ค.

์• ๋‹ˆ๋ฉ”์ด์…˜ ์ด๋ฏธ์ง€์˜ ์•”ํ˜ธํ™”/์•”ํ˜ธ ํ•ด๋…์€ ์ผ๋ฐ˜ ์ •์  ์ด๋ฏธ์ง€์™€ ๋™์ผํ•˜๊ฒŒ ์ž‘๋™ํ•˜์ง€๋งŒ ์• ๋‹ˆ๋ฉ”์ด์…˜์ด ์†์ƒ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์‚ฌ์šฉ๋œ ์†Œ์Šค:

๋‹ค์šด๋กœ๋“œ :

์ถœ์ฒ˜ : habr.com

์ฝ”๋ฉ˜ํŠธ๋ฅผ ์ถ”๊ฐ€