stegano

package module
v1.7.8 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 21, 2025 License: MIT Imports: 15 Imported by: 0

README

Stegano: The fastest Steganography Library for Go

Tests GitHub License Go Reference Go Report Card

Table of Contents

  1. Features
  2. What is Steganography?
  3. Use Cases
  4. Installation
  5. Usage
  6. Working with Images
  7. Working with Audio
  8. Advanced Options
  9. Notes
  10. Benchmarks
  11. Future Improvements

Features

  • Multi-Image Support: Works with any image type compatible with Go's image.Image.
  • Data Compression: Supports ZSTD compression to minimize the size of embedded data.
  • Reed-Solomon Codes: Implements Reed-Solomon error correction.
  • Capacity Calculation: Automatically calculates the maximum capacity of an image for data embedding.
  • Variable Depth Encoding: Allows you to embed data up to a specified bit depth.
  • Concurrency: Supports concurrent processing for improved speed (higher memory usage).
  • Custom Bit Depth Embedding: Lets you specify the bit depth used for data embedding (e.g., LSB, MSB).
  • Encryption: Enables secure encryption of data before embedding into the image.
  • Efficient PNG Encoding: Saves the image in PNG format.

What is Steganography?

Steganography is the practice of concealing data within other, seemingly innocent data in such a way that it remains undetectable to the casual observer. Unlike encryption, which focuses on making data unreadable, steganography hides it entirely, making the data appear normal and undisturbed.

The most common use case for steganography is hiding text or binary data within an image. This library enables you to easily embed and extract such hidden information from images.


Installation

To integrate Stegano into your Go project, simply run:

go get github.com/scott-mescudi/stegano@latest

Usage

Import the Library
import (
    "github.com/scott-mescudi/stegano"
)

Working with Images

Quickstart

The following are high-level functions for embedding and extracting data easily:

func main() {
	err := stegano.EmbedFile("cover.png", "data.txt", stegano.DefaultOutputFile, "password123", stegano.LSB)
	if err != nil {
		log.Fatalln("Error:", err)
	}
}
func main() {
	err := stegano.ExtractFile(stegano.DefaultOutputFile, "password123", stegano.LSB)
	if err != nil {
		log.Fatalln("Error:", err)
	}
}

For more control over the process, refer to the examples below:

1. Embed a Message into an Image

You can embed a message into an image using the EmbedHandler class.

func main() {
	// wrapper function around different image decoders.
	coverFile, err := stegano.Decodeimage("coverimage.png")
	if err != nil {
		log.Fatalln(err)
	}

	embedder := stegano.NewEmbedHandler()

	// Encode and save the message in the cover image.
	err = embedder.Encode(coverFile, []byte("Hello, World!"), stegano.MaxBitDepth, stegano.DefaultOutputFile, true)
	if err != nil {
		log.Fatalln(err)
	}
}
2. Extract a Message from an Embedded Image

Extract a hidden message from an image using the ExtractHandler class.

func main() {
	coverFile, err := stegano.Decodeimage("embeddedimage.png")
	if err != nil {
		log.Fatalln(err)
	}

	extractor := stegano.NewExtractHandler()

	// Decode the message from the image.
	data, err := extractor.Decode(coverFile, stegano.MaxBitDepth, true)
	if err != nil {
		log.Fatalln(err)
	}

	// Print the extracted message.
	fmt.Println(string(data))
}
3. Embed Data Without Compression

Embed data into an image without using any compression.

func main() {
	coverFile, err := stegano.Decodeimage("coverimage.png")
	if err != nil {
		log.Fatalln(err)
	}

	embedder := stegano.NewEmbedHandler()

	// Embed the message into the image without compression.
	embeddedImage, err := embedder.EmbedDataIntoImage(coverFile, []byte("Hello, World!"), stegano.LSB)
	if err != nil {
		log.Fatalln(err)
	}

	err = stegano.SaveImage(stegano.DefaultOutputFile, embeddedImage)
	if err != nil {
		log.Fatalln(err)
	}
}
4. Extract Data Without Compression

Extract data from an image where no compression was used.

func main() {
	coverFile, err := stegano.Decodeimage("embeddedimage.png")
	if err != nil {
		log.Fatalln(err)
	}

	extractor := stegano.NewExtractHandler()

	// Extract uncompressed data from the image.
	data, err := extractor.ExtractDataFromImage(coverFile, stegano.LSB)
	if err != nil {
		log.Fatalln(err)
	}

	// Print the extracted message.
	fmt.Println(string(data))
}
5. Embed at a Specific Bit Depth

Embed data at a specific bit depth for better control over the hiding technique.

func main() {
	coverFile, err := stegano.Decodeimage("coverimage.png")
	if err != nil {
		log.Fatalln(err)
	}

	embedder := stegano.NewEmbedHandler()

	// Embed the message at a specific bit depth (e.g., 3).
	embeddedImage, err := embedder.EmbedAtDepth(coverFile, []byte("Hello, World!"), 3)
	if err != nil {
		log.Fatalln(err)
	}

	err = stegano.SaveImage(stegano.DefaultOutputFile, embeddedImage)
	if err != nil {
		log.Fatalln(err)
	}
}
6. Extract Data from a Specific Bit Depth

Extract data from an image using the same bit depth used for embedding.

func main() {
	coverFile, err := stegano.Decodeimage("embeddedimage.png")
	if err != nil {
		log.Fatalln(err)
	}

	extractor := stegano.NewExtractHandler()

	// Extract data from the image at a specific bit depth (e.g., 3).
	data, err := extractor.ExtractAtDepth(coverFile, 3)
	if err != nil {
		log.Fatalln(err)
	}

	// Print the extracted message.
	fmt.Println(string(data))
}
7. Check Image Capacity

Check how much data an image can hold based on the bit depth.

func main() {
	coverFile, err := stegano.Decodeimage("embeddedimage.png")
	if err != nil {
		log.Fatalln(err)
	}

	// Calculate and print the data capacity of the image.
	capacity := stegano.GetImageCapacity(coverFile, stegano.MaxBitDepth)
	fmt.Printf("Image capacity at bit depth %d: %d bytes\n", stegano.MaxBitDepth, capacity)
}
8. Embed Encrypted Data

Encrypt the data before embedding it into the image for added security.

func main() {
	coverFile, err := stegano.Decodeimage("coverimage.png")
	if err != nil {
		log.Fatalln(err)
	}

	// Encrypt the data before embedding.
	encryptedData, err := stegano.EncryptData([]byte("Hello, World!"), "your-encryption-key")
	if err != nil {
		log.Fatalln(err)
	}

	embedder := stegano.NewEmbedHandler()

	// Embed the encrypted data into the image.
	err = embedder.Encode(coverFile, encryptedData, stegano.LSB, stegano.DefaultOutputFile, true)
	if err != nil {
		log.Fatalln(err)
	}
}
9. Extract and Decrypt Data

Extract encrypted data from the image and decrypt it.

func main() {
	coverFile, err := stegano.Decodeimage("embeddedimage.png")
	if err != nil {
		log.Fatalln(err)
	}

	extractor := stegano.NewExtractHandler()

	// Extract the encrypted data.
	encryptedData, err := extractor.Decode(coverFile, stegano.LSB, true)
	if err != nil {
		log.Fatalln(err)
	}

	// Decrypt the data.
	decryptedData, err := stegano.DecryptData(encryptedData, "your-encryption-key")
	if err != nil {
		log.Fatalln(err)
	}

	// Print the decrypted message.
	fmt.Println(string(decryptedData))
}

Working with Audio

1. Embed Data into WAV Files
func main() {
    embedder := stegano.NewAudioEmbedHandler()
    
    err := embedder.EmbedIntoWAVWithDepth("input.wav", "output.wav", []byte("Hello World"), stegano.LSB)
    if err != nil {
        log.Fatalln(err)
    }
}
2. Extract Data from WAV Files
func main() {
    extractor := stegano.NewAudioExtractHandler()
    
    data, err := extractor.ExtractFromWAVWithDepth("embedded.wav", stegano.LSB)
    if err != nil {
        log.Fatalln(err)
    }
    fmt.Println(string(data))
}
3. Embed at Specific Bit Depth
func main() {
    embedder := stegano.NewAudioEmbedHandler()
    
    err := embedder.EmbedIntoWAVAtDepth("input.wav", "output.wav", []byte("Hello World"), 3)
    if err != nil {
        log.Fatalln(err)
    }
}
4. Extract from Specific Bit Depth
func main() {
    extractor := stegano.NewAudioExtractHandler()
    
    data, err := extractor.ExtractFromWAVAtDepth("embedded.wav", 3)
    if err != nil {
        log.Fatalln(err)
    }
    fmt.Println(string(data))
}

Advanced Options

You can use concurrency to speed up the embedding and extraction process. Use the NewEmbedHandlerWithConcurrency or NewExtractHandlerWithConcurrency functions to specify the number of goroutines to be used.

embedder, err := stegano.NewEmbedHandlerWithConcurrency(12)
if err != nil {
	log.Fatalln(err)
}

extractor, err := stegano.NewExtractHandlerWithConcurrency(12)
if err != nil {
	log.Fatalln(err)
}

Notes

  • This library can be used with any image type but works best with PNG images.
  • Bit Depth and Compression: Ensure that the same bit depth and compression settings are used during both embedding and extraction.
  • Default Output Format: By default, images NEED to be saved in PNG format to avoid any data loss.

Benchmarks

Library Name Test 1 (ns/op) Test 2 (ns/op) Test 3 (ns/op) Avg Time (ns/op) Avg Time (ms/op)
Stegano 352,531,567 349,444,200 348,196,967 350,390,578 350.39 ms
Stegano with Concurrency 286,168,125 293,260,925 284,079,175 287,169,408 287.17 ms
auyer/steganography 1,405,256,700 1,424,957,200 1,401,682,600 1,410,965,500 1,410.97 ms

Image size: 10,473,459 bytes
Text size: 641,788 bytes
Benchmark code can be found here


Future Improvements

  • Multi-Carrier Support: Enable splitting data across multiple images or files for larger data embedding.

Documentation

Index

Constants

View Source
const (
	LSB         uint8 = 0
	MaxBitDepth uint8 = 7
)

Variables

View Source
var (
	ErrDepthOutOfRange      = errors.New("bitDepth is out of range (0-7)")
	ErrFailedToExtractRGB   = errors.New("failed to extract RGB channels from the image")
	ErrFailedToExtractData  = errors.New("failed to extract data from RGB channels")
	ErrInvalidDataLength    = errors.New("extracted data length is zero")
	ErrInvalidCoverImage    = errors.New("coverImage is nil or has invalid dimensions")
	ErrInvalidData          = errors.New("data is empty or invalid")
	ErrDataTooLarge         = errors.New("data exceeds the embedding capacity of the image")
	ErrFailedToCompressData = errors.New("failed to compress data")
	ErrFailedToDecryptData  = errors.New("failed to decrypt data")
	ErrFailedToSaveImage    = errors.New("failed to save image")
)

Errors for image_embedder.go and image_core.go

View Source
var (
	DefaultOutputFile string = "stegano_out.png"
)
View Source
var (
	ErrInvalidGoroutines = errors.New("invalid number of goroutines")
)

Errors for methods.go

Functions

func Decodeimage added in v1.4.3

func Decodeimage(path string) (image.Image, error)

takes in path to image and returns image.Image

func DecryptData added in v1.5.0

func DecryptData(ciphertext []byte, password string) (plaintext []byte, err error)

DecryptData decrypts the given ciphertext using the provided password. It returns the decrypted plaintext or an error if the decryption fails.

Parameters: - ciphertext ([]byte): The encrypted data to be decrypted. - password (string): The password to be used for decryption.

Returns: - plaintext ([]byte): The decrypted data. - err (error): An error if the decryption fails.

func EmbedFile added in v1.5.0

func EmbedFile(coverImagePath, dataFilePath, outputFilePath, password string, bitDepth uint8) error

ExtractFile extracts embedded data from an image using a default bit depth of 1 (the last two bits in a byte). The embedded data is decrypted and decompressed using the provided password. The extracted file is saved using its original name (stored within the embedded data). Returns an error if the process fails at any stage.

Parameters: - coverImagePath: The file path of the image containing embedded data. - password: A password used to decrypt the embedded data after extraction.

func EncryptData added in v1.5.0

func EncryptData(data []byte, password string) (ciphertext []byte, err error)

EncryptData encrypts the given data using the provided password. It returns the encrypted ciphertext or an error if the encryption fails.

Parameters: - data ([]byte): The plaintext data to be encrypted. - password (string): The password to be used for encryption.

Returns: - ciphertext ([]byte): The encrypted data. - err (error): An error if the encryption fails.

func ExtractFile added in v1.5.0

func ExtractFile(coverImagePath, password string, bitDepth uint8) error

ExtractFile extracts embedded data from an image using a default bit depth of 1 (the last two bits in a byte). The embedded data is decrypted and decompressed using the provided password. The extracted file is saved using its original name (stored within the embedded data). Returns an error if the process fails at any stage.

Parameters: - coverImagePath: The file path of the image containing embedded data. - password: A password used to decrypt the embedded data after extraction.

func GetImageCapacity added in v1.4.1

func GetImageCapacity(coverImage image.Image, bitDepth uint8) int

GetImageCapacity calculates the maximum amount of data (in bytes) that can be embedded in the given image, based on the specified bit depth. Returns 0 if the bit depth exceeds 7, as higher depths are unsupported.

func LoadAudioData added in v1.7.4

func LoadAudioData(file string) *wav.Decoder

GetAudioData opens the WAV file and returns a decoder

func RsDecode added in v1.7.6

func RsDecode(packedDataShards []byte, parity int) ([]byte, error)

Wrapper around rsDecode private function

func RsEncode added in v1.7.6

func RsEncode(data []byte, parity int) ([]byte, error)

Wrapper around rsEncode private function

func SaveAudioToFile added in v1.7.4

func SaveAudioToFile(fileName string, decoder *wav.Decoder, buffer *audio.IntBuffer) error

WriteAudioFile writes the decoded and modified data to a new WAV file

func SaveImage added in v1.4.6

func SaveImage(outputfile string, embeddedImage image.Image) error

SaveImage saves the provided image to the specified output file.

Parameters:

outputfile: The path to the output PNG file. Must not be empty and must have a .png extension.
embeddedImage: The image to save. Must not be nil.

Returns:

An error if the input is invalid or if an issue occurs during the file creation or encoding process.

Types

type AudioEmbedHandler added in v1.7.0

type AudioEmbedHandler struct{}

func NewAudioEmbedHandler added in v1.7.2

func NewAudioEmbedHandler() *AudioEmbedHandler

func (*AudioEmbedHandler) EmbedIntoWAVAtDepth added in v1.7.4

func (s *AudioEmbedHandler) EmbedIntoWAVAtDepth(audioFilename, outputFilename string, data []byte, bitDepth uint8) error

EmbedDataIntoWAVAtDepth embeds compressed data into a WAV file at a specified bit depth.

func (*AudioEmbedHandler) EmbedIntoWAVWithDepth added in v1.7.4

func (s *AudioEmbedHandler) EmbedIntoWAVWithDepth(audioFilename, outputFilename string, data []byte, bitDepth uint8) error

EmbedDataIntoWAVWithDepth embeds compressed data into a WAV file with a specified bit depth.

type AudioExtractHandler added in v1.7.0

type AudioExtractHandler struct{}

func NewAudioExtractHandler added in v1.7.0

func NewAudioExtractHandler() *AudioExtractHandler

func (*AudioExtractHandler) ExtractFromWAVAtDepth added in v1.7.4

func (s *AudioExtractHandler) ExtractFromWAVAtDepth(audioFilename string, bitDepth uint8) ([]byte, error)

ExtractDataFromWAVAtDepth extracts compressed data from a WAV file at a specified bit depth.

func (*AudioExtractHandler) ExtractFromWAVWithDepth added in v1.7.4

func (s *AudioExtractHandler) ExtractFromWAVWithDepth(audioFilename string, bitDepth uint8) ([]byte, error)

ExtractDataFromWAVWithDepth extracts compressed data from a WAV file with a specified bit depth.

type EmbedHandler added in v1.4.1

type EmbedHandler struct {
	// contains filtered or unexported fields
}

func NewEmbedHandler added in v1.4.1

func NewEmbedHandler() *EmbedHandler

NewEmbedHandler initializes an EmbedHandler with default concurrency

func NewEmbedHandlerWithConcurrency added in v1.4.4

func NewEmbedHandlerWithConcurrency(concurrency int) (*EmbedHandler, error)

NewEmbedHandlerWithConcurrency initializes an EmbedHandler with a specified concurrency

func (*EmbedHandler) EmbedAtDepth added in v1.4.1

func (m *EmbedHandler) EmbedAtDepth(coverimage image.Image, data []byte, depth uint8) (image.Image, error)

EmbedAtDepth embeds the provided data into a specific bit depth of the RGB channels of the image. Unlike other embedding methods, this modifies a single bit per channel at the specified depth.

func (*EmbedHandler) EmbedDataIntoImage added in v1.4.1

func (m *EmbedHandler) EmbedDataIntoImage(coverImage image.Image, data []byte, bitDepth uint8) (image.Image, error)

EmbedDataIntoImage embeds the given data into the RGB channels of the specified image.

func (*EmbedHandler) Encode added in v1.5.31

func (m *EmbedHandler) Encode(coverImage image.Image, data []byte, bitDepth uint8, outputFilename string, defaultCompression bool) error

Parameters: - coverImage: The original image where data will be embedded. - data: The data to embed into the image. - bitDepth: The number of bits per channel used for embedding (0-7). - outputFilename: The name of the file where the modified image will be saved. - defaultCompression: A flag indicating whether the data should be compressed before embedding.

type ExtractHandler added in v1.4.1

type ExtractHandler struct {
	// contains filtered or unexported fields
}

func NewExtractHandler added in v1.4.1

func NewExtractHandler() *ExtractHandler

NewExtractHandler initializes an ExtractHandler with default concurrency

func NewExtractHandlerWithConcurrency added in v1.4.4

func NewExtractHandlerWithConcurrency(concurrency int) (*ExtractHandler, error)

NewExtractHandlerWithConcurrency initializes an ExtractHandler with a specified concurrency

func (*ExtractHandler) Decode added in v1.4.1

func (m *ExtractHandler) Decode(coverImage image.Image, bitDepth uint8, isDefaultCompressed bool) ([]byte, error)

Decode extracts data embedded in an image using the specified bit depth. If the embedded data was compressed, it will be decompressed when `isDefaultCompressed` is true. Returns the extracted data or an error if the extraction or decompression fails.

Parameters: - coverImage: The image containing embedded data to be extracted. - bitDepth: The bit depth used during the embedding process. - isDefaultCompressed: A flag indicating whether the embedded data was compressed.

func (*ExtractHandler) ExtractAtDepth added in v1.4.1

func (m *ExtractHandler) ExtractAtDepth(coverimage image.Image, depth uint8) ([]byte, error)

ExtractAtDepth extracts data embedded at a specific bit depth from the RGB channels of an image. Only retrieves data from the specified bit depth. Returns the extracted data or an error if the process fails.

func (*ExtractHandler) ExtractDataFromImage added in v1.4.1

func (m *ExtractHandler) ExtractDataFromImage(coverImage image.Image, bitDepth uint8) ([]byte, error)

ExtractDataFromImage retrieves data embedded in the RGB channels of the specified image.

type SecureEmbedHandler added in v1.5.31

type SecureEmbedHandler struct {
	// contains filtered or unexported fields
}

func NewSecureEmbedHandler added in v1.5.2

func NewSecureEmbedHandler() *SecureEmbedHandler

NewSecureEmbedHandler initializes a SecureEmbedHandler with default concurrency

func NewSecureEmbedHandlerWithConcurrency added in v1.5.2

func NewSecureEmbedHandlerWithConcurrency(concurrency int) (*SecureEmbedHandler, error)

NewSecureEmbedHandlerWithConcurrency initializes a SecureEmbedHandler with a specified concurrency

func (*SecureEmbedHandler) Encode added in v1.5.31

func (m *SecureEmbedHandler) Encode(coverImage image.Image, data []byte, bitDepth uint8, outputFilename string, password string) error

Encode embeds data into a cover image using a specified bit depth, encrypts and compresses the data, and saves the resulting image to the specified output file. Secure uses reed solomon codes for persistency Parameters: - coverImage: The image to embed data into. - data: The data to embed in the image. - bitDepth: The bit depth used for embedding (valid range: 0-7). - outputFilename: The file name to save the resulting image. Defaults to a pre-defined name if empty. - password: The password used to encrypt the data. Returns: - error: An error if any part of the embedding process fails.

type SecureExtractHandler added in v1.5.31

type SecureExtractHandler struct {
	// contains filtered or unexported fields
}

func NewSecureExtractHandler added in v1.5.2

func NewSecureExtractHandler() *SecureExtractHandler

NewSecureExtractHandler initializes a SecureExtractHandler with default concurrency

func NewSecureExtractHandlerWithConcurrency added in v1.5.2

func NewSecureExtractHandlerWithConcurrency(concurrency int) (*SecureExtractHandler, error)

NewSecureExtractHandlerWithConcurrency initializes a SecureExtractHandler with a specified concurrency

func (*SecureExtractHandler) Decode added in v1.5.31

func (m *SecureExtractHandler) Decode(coverImage image.Image, bitDepth uint8, password string) ([]byte, error)

Decode extracts embedded data from a cover image using a specified bit depth, decrypts and decompresses it, and returns the original data. Secure uses reed solomon codes for persistency Parameters: - coverImage: The image containing the embedded data. - bitDepth: The bit depth used for extracting data (valid range: 0-7). - password: The password used to decrypt the embedded data. Returns: - []byte: The extracted original data. - error: An error if the extraction process fails.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL