added support for binary files

This commit is contained in:
ston1th 2018-10-12 00:31:42 +02:00
commit ef0e619642
4 changed files with 58 additions and 21 deletions

View file

@ -2,14 +2,20 @@
Hides a string inside the least significant bit (LSB) of all colors of each pixel. Hides a string inside the least significant bit (LSB) of all colors of each pixel.
## Build
```
go build -o stego stego.go
```
## Hide ## Hide
``` ```
./stego -in testdata/lenna.png -out testdata/stego.png -secret "hello world!" ./stego -in testdata/lenna.png -secret testdata/lenna_256.png -out testdata/stego.png
``` ```
## Reveal ## Reveal
``` ```
./stego -in testdata/stego.png ./stego -in testdata/stego.png -out lenna_256.png
``` ```

View file

@ -3,6 +3,7 @@
package main package main
import ( import (
"encoding/binary"
"errors" "errors"
"flag" "flag"
"fmt" "fmt"
@ -11,23 +12,49 @@ import (
_ "image/gif" _ "image/gif"
_ "image/jpeg" _ "image/jpeg"
"image/png" "image/png"
"io/ioutil"
"os" "os"
) )
const offset = 4
func encodeLen(l int) []byte {
b := make([]byte, offset)
binary.LittleEndian.PutUint32(b, uint32(l))
return b
}
func getLen(p image.Image) int {
z := make([]byte, offset)
for i := 0; i < offset; i++ {
pix := color.NRGBAModel.Convert(p.At(i, 0)).(color.NRGBA)
z[i] = (pix.R << 6)
z[i] |= (pix.G << 6) >> 2
z[i] |= (pix.B << 6) >> 4
z[i] |= (pix.A << 6) >> 6
}
return int(binary.LittleEndian.Uint32(z))
}
func unseal(p image.Image) (b []byte) { func unseal(p image.Image) (b []byte) {
rect := p.Bounds() rect := p.Bounds()
l := getLen(p)
c := 0
for i := 0; i < rect.Max.Y; i++ { for i := 0; i < rect.Max.Y; i++ {
for j := 0; j < rect.Max.X; j++ { for j := 0; j < rect.Max.X; j++ {
if i == 0 && j == 0 {
j = offset
}
pix := color.NRGBAModel.Convert(p.At(j, i)).(color.NRGBA) pix := color.NRGBAModel.Convert(p.At(j, i)).(color.NRGBA)
z := (pix.R << 6) z := (pix.R << 6)
z |= (pix.G << 6) >> 2 z |= (pix.G << 6) >> 2
z |= (pix.B << 6) >> 4 z |= (pix.B << 6) >> 4
z |= (pix.A << 6) >> 6 z |= (pix.A << 6) >> 6
if z == byte(0) { if c == l {
b = append(b, '\n')
return return
} }
b = append(b, z) b = append(b, z)
c++
} }
} }
return return
@ -37,28 +64,22 @@ func seal(p image.Image, s []byte) (image.Image, error) {
rect := p.Bounds() rect := p.Bounds()
n := image.NewNRGBA(rect) n := image.NewNRGBA(rect)
c := 0 c := 0
max := (rect.Max.Y * rect.Max.X) - 1 arr := append(encodeLen(len(s)), s...)
if len(s) > max { l := len(arr)
max := (rect.Max.Y * rect.Max.X)
if l > max {
return nil, errors.New("not enough space in image") return nil, errors.New("not enough space in image")
} }
for i := 0; i < rect.Max.Y; i++ { for i := 0; i < rect.Max.Y; i++ {
for j := 0; j < rect.Max.X; j++ { for j := 0; j < rect.Max.X; j++ {
pix := color.NRGBAModel.Convert(p.At(j, i)).(color.NRGBA) pix := color.NRGBAModel.Convert(p.At(j, i)).(color.NRGBA)
if c < len(s) { if c < l {
r := (pix.R &^ 3) | (s[c] >> 6) r := (pix.R &^ 3) | (arr[c] >> 6)
g := (pix.G &^ 3) | (s[c]<<2)>>6 g := (pix.G &^ 3) | (arr[c]<<2)>>6
b := (pix.B &^ 3) | (s[c]<<4)>>6 b := (pix.B &^ 3) | (arr[c]<<4)>>6
a := (pix.A &^ 3) | (s[c]<<6)>>6 a := (pix.A &^ 3) | (arr[c]<<6)>>6
n.Set(j, i, color.NRGBA{r, g, b, a}) n.Set(j, i, color.NRGBA{r, g, b, a})
c++ c++
} else if c == len(s) {
n.Set(j, i, color.NRGBA{
pix.R &^ 3,
pix.G &^ 3,
pix.B &^ 3,
pix.A &^ 3,
})
c++
} else { } else {
n.Set(j, i, pix) n.Set(j, i, pix)
} }
@ -81,7 +102,7 @@ func errf(err error) {
func main() { func main() {
flag.StringVar(&inFile, "in", "-", "input file (default: stdin)") flag.StringVar(&inFile, "in", "-", "input file (default: stdin)")
flag.StringVar(&outFile, "out", "-", "output file, always png (default: stdout)") flag.StringVar(&outFile, "out", "-", "output file, always png (default: stdout)")
flag.StringVar(&secret, "secret", "", "secret to hide") flag.StringVar(&secret, "secret", "", "secret file to hide")
flag.Parse() flag.Parse()
var ( var (
err error err error
@ -94,12 +115,22 @@ func main() {
errf(err) errf(err)
} }
} }
if outFile != "-" {
out, err = os.OpenFile(outFile, os.O_RDWR|os.O_CREATE, 0644)
if err != nil {
errf(err)
}
}
p, _, err := image.Decode(in) p, _, err := image.Decode(in)
if err != nil { if err != nil {
errf(err) errf(err)
} }
if secret != "" { if secret != "" {
n, err := seal(p, []byte(secret)) b, err := ioutil.ReadFile(secret)
if err != nil {
errf(err)
}
n, err := seal(p, b)
if err != nil { if err != nil {
errf(err) errf(err)
} }

BIN
testdata/lenna_256.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 135 KiB

BIN
testdata/stego.png vendored

Binary file not shown.

Before

Width:  |  Height:  |  Size: 560 KiB

After

Width:  |  Height:  |  Size: 590 KiB

Before After
Before After