40 lines
1.7 KiB
Go
40 lines
1.7 KiB
Go
package stego
|
||
|
||
import "image"
|
||
|
||
// ExtractLSB проходит пиксели построчно (слева направо, сверху вниз) и
|
||
// вытаскивает по одному биту (bit) из выбранного канала на пиксель,
|
||
// упаковывая их в байты (8 пикселей на байт), пока не наберётся maxBytes
|
||
// байт или не кончится изображение — что раньше.
|
||
//
|
||
// Это самая наивная, но и самая частая в CTF-задачах схема: линейная
|
||
// LSB-стеганография без перемешивания порядка пикселей и без ключа.
|
||
// Более хитрые схемы (с рассеиванием по PRNG-последовательности, с
|
||
// несколькими битами разных каналов одновременно, с посимвольным
|
||
// прыжком через фиксированный интервал пикселей и т.п.) этим не
|
||
// читаются — придётся разбирать руками, этот пакет вытаскивает только
|
||
// самый частый частный случай.
|
||
func ExtractLSB(img *image.RGBA, ch Channel, bit int, maxBytes int) []byte {
|
||
bounds := img.Bounds()
|
||
out := make([]byte, 0, maxBytes)
|
||
|
||
var cur byte
|
||
var count int
|
||
for y := bounds.Min.Y; y < bounds.Max.Y; y++ {
|
||
for x := bounds.Min.X; x < bounds.Max.X; x++ {
|
||
if len(out) >= maxBytes {
|
||
return out
|
||
}
|
||
v := channelValue(img.RGBAAt(x, y), ch)
|
||
b := (v >> uint(bit)) & 1
|
||
cur = (cur << 1) | b
|
||
count++
|
||
if count == 8 {
|
||
out = append(out, cur)
|
||
cur = 0
|
||
count = 0
|
||
}
|
||
}
|
||
}
|
||
return out
|
||
}
|