한양과학기술고등학교

에듀테크 프로젝트 대시보드

스테가노그래피

암호화(Cryptography)는 "무엇을 담고 있는지 못 읽게" 만들지만, 스테가노그래피(Steganography)는 아예 "무언가 숨겨져 있다는 사실 자체"를 감춥니다. 가장 대표적인 방법은 이미지 픽셀의 최하위 비트(LSB, Least Significant Bit)를 몰래 바꿔치기하는 것입니다. 각 색상 채널(R·G·B)은 0~255 사이 8비트 값인데, 맨 마지막 1비트만 바꿔도 색상 차이는 최대 1/255 — 사람 눈으로는 절대 구별할 수 없습니다.
🖼️ 커버 이미지에 메시지 숨기기 LSB 인코딩
원본 이미지
메시지 삽입 후 (육안 구별 불가)
필요 비트 / 최대 용량 0 / 0 bits
🔬 LSB 평면 시각화 최하위 비트만 추출
삽입 전 LSB 평면
삽입 후 LSB 평면
각 채널의 LSB만 뽑아 0→검정, 1→흰색으로 표시했습니다. 인코딩 전에는 원본 이미지 패턴이 은은히 보이지만, 메시지를 담은 앞부분은 완전히 무작위 노이즈로 바뀝니다 — 이것이 스테가분석(Steganalysis)이 LSB 은닉을 찾아내는 단서 중 하나입니다.
아직 디코딩하지 않았습니다.
📐 인코딩 알고리즘 (JavaScript)
// 1) 메시지를 UTF-8 바이트로, 앞에 4바이트 길이 헤더를 붙인다 const bytes = new TextEncoder().encode(message); const header = int32ToBytes(bytes.length); // 길이 정보 = 몇 바이트를 읽을지 const payload = [...header, ...bytes]; // 2) 바이트 → 비트 스트림으로 펼친다 const bits = payload.flatMap(b => [7,6,5,4,3,2,1,0].map(i => (b >> i) & 1)); // 3) R,G,B 채널을 순서대로 훑으며 각 바이트의 LSB를 비트로 교체 (Alpha 채널은 건드리지 않음) let bitIdx = 0; for (let i = 0; i < pixels.length; i += 4) { for (let c = 0; c < 3; c++) { // R, G, B if (bitIdx >= bits.length) break; pixels[i + c] = (pixels[i + c] & 0b11111110) | bits[bitIdx++]; // LSB 교체 } }
용량 한계: 96×64 픽셀 이미지는 R·G·B 채널만 사용해도 96 × 64 × 3 = 18,432비트(2,304바이트)를 숨길 수 있습니다. 해상도가 클수록, 픽셀당 사용하는 비트 수(2비트, 3비트…)를 늘릴수록 용량은 커지지만 이미지가 눈에 띄게 손상되고 통계적으로도 더 쉽게 들통납니다. 실제 도구(steghide, OpenStego 등)는 LSB를 무작위 순서로 흩뿌리거나 압축·암호화를 함께 적용해 탐지를 더 어렵게 만듭니다.