From 5504b18dbdd502d8e09869d485f340512531aaf1 Mon Sep 17 00:00:00 2001 From: Rafael Passos Date: Fri, 26 Apr 2019 13:06:30 -0300 Subject: [PATCH 1/5] API now recieves the result pointer --- examples/stego.go | 28 +++++++-- steganography.go | 137 ++++++++++++++++++++++++------------------ steganography_test.go | 90 ++++++++++++++++++++------- 3 files changed, 172 insertions(+), 83 deletions(-) diff --git a/examples/stego.go b/examples/stego.go index 982c907..d4b9ca4 100644 --- a/examples/stego.go +++ b/examples/stego.go @@ -2,6 +2,7 @@ package main import ( "bufio" + "bytes" "flag" "fmt" "image" @@ -37,6 +38,21 @@ func init() { flag.Parse() } +// OpenImageFromPath returns a image.Image from a file path. A helper function to deal with decoding the image into a usable format. This method is optional. +func OpenImageFromPath(filename string) (image.Image, error) { + inFile, err := os.Open(filename) + if err != nil { + return nil, err + } + defer inFile.Close() + reader := bufio.NewReader(inFile) + img, _, err := image.Decode(reader) + if err != nil { + return nil, err + } + return img, nil +} + func main() { if encode { message, err := ioutil.ReadFile(messageInputFile) // Read the message from the message file (alternative to os.Open ) @@ -56,8 +72,12 @@ func main() { if err != nil { log.Fatalf("Error opening file %v", err) } - encodedImg := steganography.EncodeString(message, img) // Calls library and Encodes the message into a new buffer - outFile, err := os.Create(pictureOutputFile) // Creates file to write the message into + encodedImg := new(bytes.Buffer) + err = steganography.Encode(encodedImg, img, message) // Calls library and Encodes the message into a new buffer + if err != nil { + log.Fatalf("Error encoding message into file %v", err) + } + outFile, err := os.Create(pictureOutputFile) // Creates file to write the message into if err != nil { log.Fatalf("Error creating file %s: %v", pictureOutputFile, err) } @@ -77,9 +97,9 @@ func main() { log.Fatal("error decoding file", img) } - sizeOfMessage := steganography.GetSizeOfMessageFromImage(img) // Uses the library to check the message size + sizeOfMessage := steganography.GetMessageSizeFromImage(img) // Uses the library to check the message size - msg := steganography.DecodeMessageFromPicture(4, sizeOfMessage, img) // Read the message from the picture file + msg := steganography.Decode(4, sizeOfMessage, img) // Read the message from the picture file // if the user specifies a location to write the message to... if messageOutputFile != "" { diff --git a/steganography.go b/steganography.go index e9cdcd0..f047503 100644 --- a/steganography.go +++ b/steganography.go @@ -2,40 +2,37 @@ package steganography import ( - "bufio" "bytes" + "errors" + "fmt" "image" "image/color" "image/draw" "image/png" - "os" ) -// EncodeString encodes a given string into the input image using least significant bit encryption (LSB steganography) +// EncodeRGBA encodes a given string into the input image using least significant bit encryption (LSB steganography) +// The minnimum image size is 24 pixels for one byte. For each additional byte, it is necessary 3 more pixels. /* Input: + writeBuffer *bytes.Buffer : the destination of the encoded image bytes + pictureInputFile image.RGBA : image data used in encoding message []byte : byte slice of the message to be encoded - pictureInputFile image.Image : image data used in encoding Output: bytes buffer ( io.writter ) to create file, or send data. */ -func EncodeString(message []byte, pictureInputFile image.Image) bytes.Buffer { - w := new(bytes.Buffer) - - rgbIm := imageToRGBA(pictureInputFile) +func EncodeRGBA(writeBuffer *bytes.Buffer, rgbImage *image.RGBA, message []byte) error { - var messageLength uint32 = uint32(len(message)) + var messageLength = uint32(len(message)) - var width int = rgbIm.Bounds().Dx() - var height int = rgbIm.Bounds().Dy() + var width = rgbImage.Bounds().Dx() + var height = rgbImage.Bounds().Dy() var c color.RGBA var bit byte var ok bool //var encodedImage image.Image - - if MaxEncodeSize(rgbIm) < messageLength+4 { - print("Error! The message you are trying to encode is too large.") - return *w + if MaxEncodeSize(rgbImage) < messageLength+4 { + return errors.New("message too large for image") } one, two, three, four := splitToBytes(messageLength) @@ -52,61 +49,79 @@ func EncodeString(message []byte, pictureInputFile image.Image) bytes.Buffer { for x := 0; x < width; x++ { for y := 0; y < height; y++ { - c = rgbIm.RGBAAt(x, y) // get the color at this pixel + c = rgbImage.RGBAAt(x, y) // get the color at this pixel /* RED */ bit, ok = <-ch if !ok { // if we don't have any more bits left in our message - rgbIm.SetRGBA(x, y, c) - png.Encode(w, rgbIm) - return *w + rgbImage.SetRGBA(x, y, c) + png.Encode(writeBuffer, rgbImage) + // return *writeBuffer, nil } setLSB(&c.R, bit) /* GREEN */ bit, ok = <-ch if !ok { - rgbIm.SetRGBA(x, y, c) - png.Encode(w, rgbIm) - return *w + rgbImage.SetRGBA(x, y, c) + png.Encode(writeBuffer, rgbImage) + return nil } setLSB(&c.G, bit) /* BLUE */ bit, ok = <-ch if !ok { - rgbIm.SetRGBA(x, y, c) - png.Encode(w, rgbIm) - return *w + rgbImage.SetRGBA(x, y, c) + png.Encode(writeBuffer, rgbImage) + return nil } setLSB(&c.B, bit) - rgbIm.SetRGBA(x, y, c) + rgbImage.SetRGBA(x, y, c) } } - png.Encode(w, rgbIm) - return *w + err := png.Encode(writeBuffer, rgbImage) + fmt.Println("err") + return err } -// DecodeMessageFromPicture using LSB steganography, decode the message from the picture and return it as a sequence of bytes +// Encode encodes a given string into the input image using least significant bit encryption (LSB steganography) +// The minnimum image size is 23 pixels +// It wraps EncodeRGBA making the conversion from image.Image to image.RGBA +/* + Input: + writeBuffer *bytes.Buffer : the destination of the encoded image bytes + message []byte : byte slice of the message to be encoded + pictureInputFile image.Image : image data used in encoding + Output: + bytes buffer ( io.writter ) to create file, or send data. +*/ +func Encode(writeBuffer *bytes.Buffer, pictureInputFile image.Image, message []byte) error { + + rgbImage := imageToRGBA(pictureInputFile) + + return EncodeRGBA(writeBuffer, rgbImage, message) + +} + +// DecodeRGBA gets messages from pictures using LSB steganography, decode the message from the picture and return it as a sequence of bytes /* Input: startOffset uint32 : number of bytes used to declare size of message msgLen uint32 : size of the message to be decoded - pictureInputFile image.Image : image data used in decoding + pictureInputFile image.RGBA : image data used in decoding Output: message []byte decoded from image */ -func DecodeMessageFromPicture(startOffset uint32, msgLen uint32, pictureInputFile image.Image) (message []byte) { +func DecodeRGBA(startOffset uint32, msgLen uint32, rgbImage *image.RGBA) (message []byte) { var byteIndex uint32 var bitIndex uint32 - rgbIm := imageToRGBA(pictureInputFile) - - width := rgbIm.Bounds().Dx() - height := rgbIm.Bounds().Dy() + width := rgbImage.Bounds().Dx() + height := rgbImage.Bounds().Dy() var c color.RGBA var lsb byte @@ -117,7 +132,7 @@ func DecodeMessageFromPicture(startOffset uint32, msgLen uint32, pictureInputFil for x := 0; x < width; x++ { for y := 0; y < height; y++ { - c = rgbIm.RGBAAt(x, y) // get the color of the pixel + c = rgbImage.RGBAAt(x, y) // get the color of the pixel /* RED */ lsb = getLSB(c.R) // get the least significant bit from the red component of this pixel @@ -172,17 +187,40 @@ func DecodeMessageFromPicture(startOffset uint32, msgLen uint32, pictureInputFil return } +// Decode gets messages from pictures using LSB steganography, decode the message from the picture and return it as a sequence of bytes +// It wraps EncodeRGBA making the conversion from image.Image to image.RGBA +/* + Input: + startOffset uint32 : number of bytes used to declare size of message + msgLen uint32 : size of the message to be decoded + pictureInputFile image.Image : image data used in decoding + Output: + message []byte decoded from image +*/ +func Decode(startOffset uint32, msgLen uint32, pictureInputFile image.Image) (message []byte) { + + rgbImage := imageToRGBA(pictureInputFile) + return DecodeRGBA(startOffset, msgLen, rgbImage) + +} + // MaxEncodeSize given an image will find how many bytes can be stored in that image using least significant bit encoding +// ((width * height * 3) / 8 ) - 4 +// The result must be at least 4, func MaxEncodeSize(img image.Image) uint32 { width := img.Bounds().Dx() height := img.Bounds().Dy() - return uint32(((width * height * 3) / 8)) - 4 + eval := ((width * height * 3) / 8) - 4 + if eval < 4 { + eval = 0 + } + return uint32(eval) } -// GetSizeOfMessageFromImage gets the size of the message from the first four bytes encoded in the image -func GetSizeOfMessageFromImage(pictureInputFile image.Image) (size uint32) { +// GetMessageSizeFromImage gets the size of the message from the first four bytes encoded in the image +func GetMessageSizeFromImage(pictureInputFile image.Image) (size uint32) { - sizeAsByteArray := DecodeMessageFromPicture(0, 4, pictureInputFile) + sizeAsByteArray := Decode(0, 4, pictureInputFile) size = combineToInt(sizeAsByteArray[0], sizeAsByteArray[1], sizeAsByteArray[2], sizeAsByteArray[3]) return } @@ -237,7 +275,7 @@ func getBitFromByte(b byte, indexInByte int) byte { b = b << uint(indexInByte) var mask byte = 0x80 - var bit byte = mask & b + var bit = mask & b if bit == 128 { return 1 @@ -282,22 +320,7 @@ func splitToBytes(x uint32) (one, two, three, four byte) { return } -// OpenImageFromPath returns a image.Image from a file path. A helper function to deal with decoding the image into a usable format. This method is optional. -func OpenImageFromPath(filename string) (image.Image, error) { - inFile, err := os.Open(filename) - if err != nil { - return nil, err - } - defer inFile.Close() - reader := bufio.NewReader(inFile) - img, _, err := image.Decode(reader) - if err != nil { - return nil, err - } - return img, nil -} - -// imageToRGBA convert given image to RGBA image +// imageToRGBA converts image.Image to image.RGBA func imageToRGBA(src image.Image) *image.RGBA { bounds := src.Bounds() diff --git a/steganography_test.go b/steganography_test.go index 21ccdba..c54b94d 100644 --- a/steganography_test.go +++ b/steganography_test.go @@ -4,6 +4,7 @@ import ( "bufio" "bytes" "image" + "image/color" "log" "os" "testing" @@ -14,7 +15,7 @@ var encodedInputFile = "./examples/encoded_stegosaurus.png" var bitmessage = []uint8{84, 104, 101, 113, 117, 97, 100, 114, 117, 112, 101, 100, 97, 108, 83, 116, 101, 103, 111, 115, 97, 117, 114, 117, 115, 105, 115, 111, 110, 101, 111, 102, 116, 104, 101, 109, 111, 115, 116, 101, 97, 115, 105, 108, 121, 105, 100, 101, 110, 116, 105, 102, 105, 97, 98, 108, 101, 100, 105, 110, 111, 115, 97, 117, 114, 103, 101, 110, 101, 114, 97, 44, 100, 117, 101, 116, 111, 116, 104, 101, 100, 105, 115, 116, 105, 110, 99, 116, 105, 118, 101, 100, 111, 117, 98, 108, 101, 114, 111, 119, 111, 102, 107, 105, 116, 101, 45, 115, 104, 97, 112, 101, 100, 112, 108, 97, 116, 101, 115, 114, 105, 115, 105, 110, 103, 118, 101, 114, 116, 105, 99, 97, 108, 108, 121, 97, 108, 111, 110, 103, 116, 104, 101, 114, 111, 117, 110, 100, 101, 100, 98, 97, 99, 107, 97, 110, 100, 116, 104, 101, 116, 119, 111, 112, 97, 105, 114, 115, 111, 102, 108, 111, 110, 103, 115, 112, 105, 107, 101, 115, 101, 120, 116, 101, 110, 100, 105, 110, 103, 104, 111, 114, 105, 122, 111, 110, 116, 97, 108, 108, 121, 110, 101, 97, 114, 116, 104, 101, 101, 110, 100, 111, 102, 116, 104, 101, 116, 97, 105, 108, 46, 65, 108, 116, 104, 111, 117, 103, 104, 108, 97, 114, 103, 101, 105, 110, 100, 105, 118, 105, 100, 117, 97, 108, 115, 99, 111, 117, 108, 100, 103, 114, 111, 119, 117, 112, 116, 111, 57, 109, 40, 50, 57, 46, 53, 102, 116, 41, 105, 110, 108, 101, 110, 103, 116, 104, 91, 52, 93, 97, 110, 100, 53, 46, 51, 116, 111, 55, 109, 101, 116, 114, 105, 99, 116, 111, 110, 115, 40, 53, 46, 56, 116, 111, 55, 46, 55, 115, 104, 111, 114, 116, 116, 111, 110, 115, 41, 105, 110, 119, 101, 105, 103, 104, 116, 44, 91, 53, 93, 91, 54, 93, 116, 104, 101, 118, 97, 114, 105, 111, 117, 115, 115, 112, 101, 99, 105, 101, 115, 111, 102, 83, 116, 101, 103, 111, 115, 97, 117, 114, 117, 115, 119, 101, 114, 101, 100, 119, 97, 114, 102, 101, 100, 98, 121, 99, 111, 110, 116, 101, 109, 112, 111, 114, 97, 114, 105, 101, 115, 44, 116, 104, 101, 103, 105, 97, 110, 116, 115, 97, 117, 114, 111, 112, 111, 100, 115, 46, 83, 111, 109, 101, 102, 111, 114, 109, 111, 102, 97, 114, 109, 111, 114, 97, 112, 112, 101, 97, 114, 115, 116, 111, 104, 97, 118, 101, 98, 101, 101, 110, 110, 101, 99, 101, 115, 115, 97, 114, 121, 44, 97, 115, 83, 116, 101, 103, 111, 115, 97, 117, 114, 117, 115, 115, 112, 101, 99, 105, 101, 115, 99, 111, 101, 120, 105, 115, 116, 101, 100, 119, 105, 116, 104, 108, 97, 114, 103, 101, 112, 114, 101, 100, 97, 116, 111, 114, 121, 116, 104, 101, 114, 111, 112, 111, 100, 100, 105, 110, 111, 115, 97, 117, 114, 115, 44, 115, 117, 99, 104, 97, 115, 65, 108, 108, 111, 115, 97, 117, 114, 117, 115, 97, 110, 100, 67, 101, 114, 97, 116, 111, 115, 97, 117, 114, 117, 115, 46} -func TestEncode(t *testing.T) { +func TestEncodeFromFile(t *testing.T) { inFile, err := os.Open(rawInputFile) if err != nil { @@ -30,18 +31,24 @@ func TestEncode(t *testing.T) { log.Printf("Error decoding. %v", err) t.FailNow() } - encodedImg := EncodeString(bitmessage, img) // Encode the message into the image file + w := new(bytes.Buffer) + err = Encode(w, img, bitmessage) // Encode the message into the image file + if err != nil { + log.Printf("Error Encoding file %v", err) + t.FailNow() + + } outFile, err := os.Create(encodedInputFile) if err != nil { log.Printf("Error creating file %s: %v", encodedInputFile, err) t.FailNow() } - w := bufio.NewWriter(outFile) - w.Write(encodedImg.Bytes()) + w.WriteTo(outFile) + defer outFile.Close() } -func TestDecode(t *testing.T) { +func TestDecodeFromFile(t *testing.T) { inFile, err := os.Open(encodedInputFile) if err != nil { log.Printf("Error opening file %s: %v", encodedInputFile, err) @@ -56,46 +63,85 @@ func TestDecode(t *testing.T) { t.FailNow() } - sizeOfMessage := GetSizeOfMessageFromImage(img) + sizeOfMessage := GetMessageSizeFromImage(img) - msg := DecodeMessageFromPicture(4, sizeOfMessage, img) // Read the message from the picture file - - // otherwise, print the message to STDOUT + msg := Decode(4, sizeOfMessage, img) // Read the message from the picture file if !bytes.Equal(msg, bitmessage) { + log.Println(string(msg)) log.Print("messages dont match") t.FailNow() } } -func TestEncodeDecode(t *testing.T) { - img, err := OpenImageFromPath(rawInputFile) +func TestEncodeDecodeGeneratedSmallImage(t *testing.T) { + // Creating image + width := 30 + height := 1 + + upLeft := image.Point{0, 0} + lowRight := image.Point{width, height} + + newimg := image.NewRGBA(image.Rectangle{upLeft, lowRight}) + + // Set color for each pixel. + for x := 0; x < width; x++ { + for y := 0; y < height; y++ { + newimg.Set(x, y, color.White) + } + } + + w := new(bytes.Buffer) + err := EncodeRGBA(w, newimg, []uint8{84, 84, 84}) // Encode the message into the image file if err != nil { - log.Printf("Error opening or Decoding file %s: %v", rawInputFile, err) + log.Printf("Error Encoding file %v", err) t.FailNow() - } - encodedImg := EncodeString(bitmessage, img) // Encode the message into the image file - img, _, err = image.Decode(bytes.NewReader(encodedImg.Bytes())) + } + decodeImg, _, err := image.Decode(w) if err != nil { - log.Print("Error decoding file") + log.Println("Failed to Decode Image") t.FailNow() } - sizeOfMessage := GetSizeOfMessageFromImage(img) + sizeOfMessage := GetMessageSizeFromImage(decodeImg) - msg := DecodeMessageFromPicture(4, sizeOfMessage, img) // Read the message from the picture file + msg := Decode(4, sizeOfMessage, decodeImg) // Read the message from the picture file - if !bytes.Equal(msg, bitmessage) { + // otherwise, print the message to STDOUT + + if !bytes.Equal(msg, []uint8{84, 84, 84}) { + log.Println(string(msg)) log.Print("messages dont match") t.FailNow() } } +func TestSmalImage(t *testing.T) { + + miniImage := image.Image(image.NewRGBA(image.Rectangle{image.Point{0, 0}, image.Point{18, 1}})) + log.Print(MaxEncodeSize(miniImage)) + if MaxEncodeSize(miniImage) > 0 { + log.Printf("Uncaught small image size") + t.FailNow() + } + + miniImage = image.Image(image.NewRGBA(image.Rectangle{image.Point{0, 0}, image.Point{23, 1}})) + + if MaxEncodeSize(miniImage) != 4 { + log.Printf("Uncaught minimal image size") + t.FailNow() + } +} -func TestEmptyPathHelperFunction(t *testing.T) { - _, err := OpenImageFromPath(" ") +func TestMessageTooLarge(t *testing.T) { + + miniImage := image.Image(image.NewRGBA(image.Rectangle{image.Point{0, 0}, image.Point{24, 1}})) + w := new(bytes.Buffer) + err := Encode(w, miniImage, bitmessage) // Encode the message into the image file if err == nil { - log.Print("Empty path given, err could not be nil.") + log.Printf("Uncaught error: message too large for image") t.FailNow() + } + } From ce58e76ba943644512057dc3ee1fc7f61d689fa4 Mon Sep 17 00:00:00 2001 From: Rafael Passos Date: Fri, 26 Apr 2019 13:06:44 -0300 Subject: [PATCH 2/5] tests for openImageFromPath helper --- examples/stego_test.go | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 examples/stego_test.go diff --git a/examples/stego_test.go b/examples/stego_test.go new file mode 100644 index 0000000..0d0133f --- /dev/null +++ b/examples/stego_test.go @@ -0,0 +1,31 @@ +package main + +import ( + "image" + "log" + "testing" +) + +var rawInputFile = "./stegosaurus.png" +var encodedInputFile = "./encoded_stegosaurus.png" + +func TestOpenImageFromPath(t *testing.T) { + img, err := OpenImageFromPath(rawInputFile) + if err != nil { + log.Printf("Error opening or Decoding file %s: %v", rawInputFile, err) + t.FailNow() + } + if (img.Bounds().Bounds() != image.Rectangle{image.Point{0, 0}, image.Point{1195, 642}}) { + log.Printf("Image has wrong size") + t.FailNow() + + } +} + +func TestEmptyPathHelperFunction(t *testing.T) { + _, err := OpenImageFromPath(" ") + if err == nil { + log.Print("Empty path given, err could not be nil.") + t.FailNow() + } +} From 67b319665d75a56e349b09dcb9a82ed0d35ab07a Mon Sep 17 00:00:00 2001 From: Rafael Passos Date: Fri, 26 Apr 2019 13:22:19 -0300 Subject: [PATCH 3/5] offset of 4 implicit to the exported Decode --- examples/stego.go | 2 +- steganography.go | 26 ++++++++++++++++++++------ steganography_test.go | 4 ++-- 3 files changed, 23 insertions(+), 9 deletions(-) diff --git a/examples/stego.go b/examples/stego.go index d4b9ca4..d669bcf 100644 --- a/examples/stego.go +++ b/examples/stego.go @@ -99,7 +99,7 @@ func main() { sizeOfMessage := steganography.GetMessageSizeFromImage(img) // Uses the library to check the message size - msg := steganography.Decode(4, sizeOfMessage, img) // Read the message from the picture file + msg := steganography.Decode(sizeOfMessage, img) // Read the message from the picture file // if the user specifies a location to write the message to... if messageOutputFile != "" { diff --git a/steganography.go b/steganography.go index f047503..0f670fc 100644 --- a/steganography.go +++ b/steganography.go @@ -106,7 +106,7 @@ func Encode(writeBuffer *bytes.Buffer, pictureInputFile image.Image, message []b } -// DecodeRGBA gets messages from pictures using LSB steganography, decode the message from the picture and return it as a sequence of bytes +// decodeRGBA gets messages from pictures using LSB steganography, decode the message from the picture and return it as a sequence of bytes /* Input: startOffset uint32 : number of bytes used to declare size of message @@ -115,7 +115,7 @@ func Encode(writeBuffer *bytes.Buffer, pictureInputFile image.Image, message []b Output: message []byte decoded from image */ -func DecodeRGBA(startOffset uint32, msgLen uint32, rgbImage *image.RGBA) (message []byte) { +func decodeRGBA(startOffset uint32, msgLen uint32, rgbImage *image.RGBA) (message []byte) { var byteIndex uint32 var bitIndex uint32 @@ -187,7 +187,7 @@ func DecodeRGBA(startOffset uint32, msgLen uint32, rgbImage *image.RGBA) (messag return } -// Decode gets messages from pictures using LSB steganography, decode the message from the picture and return it as a sequence of bytes +// decode gets messages from pictures using LSB steganography, decode the message from the picture and return it as a sequence of bytes // It wraps EncodeRGBA making the conversion from image.Image to image.RGBA /* Input: @@ -197,10 +197,24 @@ func DecodeRGBA(startOffset uint32, msgLen uint32, rgbImage *image.RGBA) (messag Output: message []byte decoded from image */ -func Decode(startOffset uint32, msgLen uint32, pictureInputFile image.Image) (message []byte) { +func decode(startOffset uint32, msgLen uint32, pictureInputFile image.Image) (message []byte) { rgbImage := imageToRGBA(pictureInputFile) - return DecodeRGBA(startOffset, msgLen, rgbImage) + return decodeRGBA(startOffset, msgLen, rgbImage) + +} + +// Decode gets messages from pictures using LSB steganography, decode the message from the picture and return it as a sequence of bytes +// It wraps EncodeRGBA making the conversion from image.Image to image.RGBA +/* + Input: + msgLen uint32 : size of the message to be decoded + pictureInputFile image.Image : image data used in decoding + Output: + message []byte decoded from image +*/ +func Decode(msgLen uint32, pictureInputFile image.Image) (message []byte) { + return decode(4, msgLen, pictureInputFile) // the offset of 4 skips the "header" where message lenght is defined } @@ -220,7 +234,7 @@ func MaxEncodeSize(img image.Image) uint32 { // GetMessageSizeFromImage gets the size of the message from the first four bytes encoded in the image func GetMessageSizeFromImage(pictureInputFile image.Image) (size uint32) { - sizeAsByteArray := Decode(0, 4, pictureInputFile) + sizeAsByteArray := decode(0, 4, pictureInputFile) size = combineToInt(sizeAsByteArray[0], sizeAsByteArray[1], sizeAsByteArray[2], sizeAsByteArray[3]) return } diff --git a/steganography_test.go b/steganography_test.go index c54b94d..4d5471d 100644 --- a/steganography_test.go +++ b/steganography_test.go @@ -65,7 +65,7 @@ func TestDecodeFromFile(t *testing.T) { sizeOfMessage := GetMessageSizeFromImage(img) - msg := Decode(4, sizeOfMessage, img) // Read the message from the picture file + msg := Decode(sizeOfMessage, img) // Read the message from the picture file if !bytes.Equal(msg, bitmessage) { log.Println(string(msg)) @@ -106,7 +106,7 @@ func TestEncodeDecodeGeneratedSmallImage(t *testing.T) { sizeOfMessage := GetMessageSizeFromImage(decodeImg) - msg := Decode(4, sizeOfMessage, decodeImg) // Read the message from the picture file + msg := Decode(sizeOfMessage, decodeImg) // Read the message from the picture file // otherwise, print the message to STDOUT From e5222624fefe7ca189fe0058b51de633906da2e7 Mon Sep 17 00:00:00 2001 From: Rafael Passos Date: Sat, 27 Apr 2019 02:06:11 -0300 Subject: [PATCH 4/5] examples updated to new api --- README.md | 51 ++++++++++++++++++++++++++++----------------------- 1 file changed, 28 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index a4a2058..c841f7b 100644 --- a/README.md +++ b/README.md @@ -17,12 +17,11 @@ go get -u github.com/auyer/steganography ## Demonstration -| Original | Encoded | +| Original |Encoded | | -------------------- | ------------------| -| ![Original File](examples/stegosaurus.png) | ![Encoded File](examples/encoded_stegosaurus.png) -| 79,955 bytes | 80,629 bytes | +| ![Original File](examples/stegosaurus.png) | ![Encoded File](examples/encoded_stegosaurus.png) -The second image contains the first paragaph of the description of a stegosaurus on [Wikipidia](https://en.wikipedia.org/wiki/Stegosaurus), also available in [examples/message.txt](examples/message.txt) as an example. +The second image contains the first paragaph of the description of a stegosaurus on [Wikipidia](https://en.wikipedia.org/wiki/Stegosaurus), also available in [examples/message.txt](https://raw.githubusercontent.com/auyer/steganography/master/examples/message.txt) as an example. ------ Getting Started @@ -42,12 +41,22 @@ Encode ------ Write mode is used to take a message and embed it into an image file using LSB steganography in order to produce a secret image file that will contain your message. +Note that the minnimum image size is 24 pixels for one byte. For each additional byte, it is necessary 3 more pixels. + ```go -inFile, _ := os.Open(file_path) // reads the File -img, _, err := image.Decode(reader) // Decodes image -encodedImg := steganography.EncodeString(message, img) // Encode the message into the provided image file -outFile, _ := os.Create(pictureOutputFile) // Creates the new file -bufio.NewWriter(outFile).Write(encodedImg.Bytes()) // writes file into disk +inFile, _ := os.Open("input_file.png") // opening file +reader := bufio.NewReader(inFile) // buffer reader +img, _, _ := image.Decode(reader) // decoding to golang's image.Image + +w := new(bytes.Buffer) // buffer that will recieve the results +err := steganography.Encode(w, img, "message") // Encode the message into the image +if err != nil { + log.Printf("Error Encoding file %v", err) + return +} +outFile, _ := os.Create("out_file.png") // create file +w.WriteTo(outFile) // write buffer to it +outFile.Close() ``` Size of Message @@ -55,7 +64,7 @@ Size of Message Length mode can be used in order to preform a preliminary check on the carrier image in order to deduce how large of a file it can store. ```go -sizeOfMessage := steganography.GetSizeOfMessageFromImage(img) // retrieves the size of the encoded message +sizeOfMessage := GetMessageSizeFromImage(img) // retrieves the size of the encoded message ``` Decode @@ -63,21 +72,17 @@ Decode Read mode is used to read an image that has been encoded using LSB steganography, and extract the hidden message from that image. ```go -inFile, _ := os.Open(file_path) // reads the File -img, _, err := image.Decode(bufio.NewReader(inFile)) // Decodes image -sizeOfMessage := steganography.GetSizeOfMessageFromImage(img) // retrieves the size of the encoded message +inFile, _ := os.Open(encodedInputFile) // opening file +inFile.Close() -msg := steganography.DecodeMessageFromPicture(4, sizeOfMessage, img) // Decodes the message from file -``` +reader := bufio.NewReader(inFile) // buffer reader +img, _, _ := image.Decode(reader) // decoding to golang's image.Image + +sizeOfMessage := GetMessageSizeFromImage(img) // retrieving message size to decode in the next line + +msg := Decode(sizeOfMessage, img) // decoding the message from the file +fmt.Println(string(msg)) -Open Image From Path ------ -If you do not want to deal with opening the image file in your code, there is a helper function for you. It will do the dirty job and return the image in a way usable by the encode and decode fucntions. -```go -img, err := OpenImageFromPath(imagePath) -if err != nil { - log.Printf("Error opening or Decoding file %s: %v", imagePath, err) -} ``` Complete Example From d7762d8ebbf5d5f0d809f8b4e4ffebd15ab1f28f Mon Sep 17 00:00:00 2001 From: Rafael Passos Date: Sat, 27 Apr 2019 02:16:05 -0300 Subject: [PATCH 5/5] bumped version and import notice --- README.md | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c841f7b..59b15c9 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ This library is inspired by [Stego by EthanWelsh](https://github.com/EthanWelsh/ ## Installation ```go -go get -u github.com/auyer/steganography +go get -u gopkg.in/auyer/steganography.v2 ``` ## Demonstration @@ -33,7 +33,7 @@ import ( "image" "io/ioutil" - "github.com/auyer/steganography" + "gopkg.in/auyer/steganography.v2" ) ``` @@ -89,6 +89,14 @@ Complete Example ------ For a complete example, see the [examples/stego.go](examples/stego.go) file. It is a command line app based on the original fork of this repository, but modifid to use the Steganography library. +---- +### V1 Compatibility: + +It is highly recommended for past users to upgrade to v2, but old users can still use it with: +``` +import "gopkg.in/auyer/steganography.v1" +``` + ----- ### Attributions - Stegosaurus Picture By Matt Martyniuk - Own work, CC BY-SA 3.0, https://commons.wikimedia.org/w/index.php?curid=42215661