{"id":29767717,"url":"https://github.com/501urchin/stegano","last_synced_at":"2025-07-27T02:15:15.010Z","repository":{"id":263322766,"uuid":"875279409","full_name":"501urchin/stegano","owner":"501urchin","description":"The fastest steganography library built for go","archived":false,"fork":false,"pushed_at":"2025-02-12T20:36:19.000Z","size":3468,"stargazers_count":92,"open_issues_count":0,"forks_count":4,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-07-23T18:27:48.293Z","etag":null,"topics":["audio","bit-manipulation","golang-library","hiding-information","jpeg","png","reed-solomon-codes","simple","steganography","wav"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/501urchin.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-10-19T15:05:20.000Z","updated_at":"2025-06-11T22:42:23.000Z","dependencies_parsed_at":"2025-01-03T19:28:51.558Z","dependency_job_id":"c06ab2a1-c78b-4d98-b89a-2d2209db972a","html_url":"https://github.com/501urchin/stegano","commit_stats":null,"previous_names":["scott-mescudi/stegano","501urchin/stegano"],"tags_count":31,"template":false,"template_full_name":null,"purl":"pkg:github/501urchin/stegano","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/501urchin%2Fstegano","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/501urchin%2Fstegano/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/501urchin%2Fstegano/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/501urchin%2Fstegano/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/501urchin","download_url":"https://codeload.github.com/501urchin/stegano/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/501urchin%2Fstegano/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":267286447,"owners_count":24064338,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-07-27T02:00:11.917Z","response_time":82,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["audio","bit-manipulation","golang-library","hiding-information","jpeg","png","reed-solomon-codes","simple","steganography","wav"],"created_at":"2025-07-27T02:15:14.207Z","updated_at":"2025-07-27T02:15:14.988Z","avatar_url":"https://github.com/501urchin.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Stegano: The fastest Steganography Library for Go\n\n[![Tests](https://github.com/scott-mescudi/stegano/actions/workflows/go.yml/badge.svg?event=push)](https://github.com/scott-mescudi/stegano/actions/workflows/go.yml) ![GitHub License](https://img.shields.io/github/license/scott-mescudi/stegano) [![Go Reference](https://pkg.go.dev/badge/github.com/scott-mescudi/stegano.svg)](https://pkg.go.dev/github.com/scott-mescudi/stegano)  [![Go Report Card](https://goreportcard.com/badge/github.com/scott-mescudi/stegano)](https://goreportcard.com/badge/github.com/scott-mescudi/stegano)\n\n\n\n## Table of Contents\n\n1. [Features](#features)\n2. [What is Steganography?](#what-is-steganography)\n3. [Use Cases](./docs/usecases.md)\n4. [Installation](#installation)\n5. [Usage](#usage)\n    - [Import the Library](#import-the-library)\n6. [Working with Images](#working-with-images)\n\t- [Quickstart](#Quickstart)\n    - [Embed a Message into an Image](#1-embed-a-message-into-an-image)\n    - [Extract a Message from an Embedded Image](#2-extract-a-message-from-an-embedded-image)\n    - [Embed Data Without Compression](#3-embed-data-without-compression)\n    - [Extract Data Without Compression](#4-extract-data-without-compression)\n    - [Embed at a Specific Bit Depth](#5-embed-at-a-specific-bit-depth)\n    - [Extract Data from a Specific Bit Depth](#6-extract-data-from-a-specific-bit-depth)\n    - [Check Image Capacity](#7-check-image-capacity)\n    - [Embed Encrypted Data](#8-embed-encrypted-data)\n    - [Extract and Decrypt Data](#9-extract-and-decrypt-data)\n7. [Working with Audio](#working-with-audio)\n    - [Embed Data into WAV Files](#1-embed-data-into-wav-files)\n    - [Extract Data from WAV Files](#2-extract-data-from-wav-files)\n    - [Embed at Specific Bit Depth](#3-embed-at-specific-bit-depth)\n    - [Extract from Specific Bit Depth](#4-extract-from-specific-bit-depth)\n8. [Advanced Options](#advanced-options)\n9. [Notes](#notes)\n10. [Benchmarks](#benchmarks)\n11. [Future Improvements](#future-improvements)\n\n---\n\n## Features\n\n- **Multi-Image Support**: Works with any image type compatible with Go's `image.Image`.\n- **Data Compression**: Supports ZSTD compression to minimize the size of embedded data.\n- **Reed-Solomon Codes**: Implements Reed-Solomon error correction.\n- **Capacity Calculation**: Automatically calculates the maximum capacity of an image for data embedding.\n- **Variable Depth Encoding**: Allows you to embed data up to a specified bit depth.\n- **Concurrency**: Supports concurrent processing for improved speed (higher memory usage).\n- **Custom Bit Depth Embedding**: Lets you specify the bit depth used for data embedding (e.g., LSB, MSB).\n- **Encryption**: Enables secure encryption of data before embedding into the image.\n- **Efficient PNG Encoding**: Saves the image in PNG format.\n\n---\n\n## What is Steganography?\n\nSteganography 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.\n\nThe 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.\n\n---\n\n## Installation\n\nTo integrate Stegano into your Go project, simply run:\n\n```bash\ngo get github.com/scott-mescudi/stegano@latest\n```\n\n---\n\n## Usage\n\n### Import the Library\n\n```go\nimport (\n    \"github.com/scott-mescudi/stegano\"\n)\n```\n\n---\n\n## Working with Images\n\n### Quickstart\n\nThe following are high-level functions for embedding and extracting data easily:\n\n```go\nfunc main() {\n\terr := stegano.EmbedFile(\"cover.png\", \"data.txt\", stegano.DefaultOutputFile, \"password123\", stegano.LSB)\n\tif err != nil {\n\t\tlog.Fatalln(\"Error:\", err)\n\t}\n}\n```\n\n```go\nfunc main() {\n\terr := stegano.ExtractFile(stegano.DefaultOutputFile, \"password123\", stegano.LSB)\n\tif err != nil {\n\t\tlog.Fatalln(\"Error:\", err)\n\t}\n}\n```\n\nFor more control over the process, refer to the examples below:\n\n### 1. Embed a Message into an Image\n\nYou can embed a message into an image using the `EmbedHandler` class.\n\n```go\nfunc main() {\n\t// wrapper function around different image decoders.\n\tcoverFile, err := stegano.Decodeimage(\"coverimage.png\")\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\n\tembedder := stegano.NewEmbedHandler()\n\n\t// Encode and save the message in the cover image.\n\terr = embedder.Encode(coverFile, []byte(\"Hello, World!\"), stegano.MaxBitDepth, stegano.DefaultOutputFile, true)\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n}\n```\n\n### 2. Extract a Message from an Embedded Image\n\nExtract a hidden message from an image using the `ExtractHandler` class.\n\n```go\nfunc main() {\n\tcoverFile, err := stegano.Decodeimage(\"embeddedimage.png\")\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\n\textractor := stegano.NewExtractHandler()\n\n\t// Decode the message from the image.\n\tdata, err := extractor.Decode(coverFile, stegano.MaxBitDepth, true)\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\n\t// Print the extracted message.\n\tfmt.Println(string(data))\n}\n```\n\n### 3. Embed Data Without Compression\n\nEmbed data into an image without using any compression.\n\n```go\nfunc main() {\n\tcoverFile, err := stegano.Decodeimage(\"coverimage.png\")\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\n\tembedder := stegano.NewEmbedHandler()\n\n\t// Embed the message into the image without compression.\n\tembeddedImage, err := embedder.EmbedDataIntoImage(coverFile, []byte(\"Hello, World!\"), stegano.LSB)\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\n\terr = stegano.SaveImage(stegano.DefaultOutputFile, embeddedImage)\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n}\n```\n\n### 4. Extract Data Without Compression\n\nExtract data from an image where no compression was used.\n\n```go\nfunc main() {\n\tcoverFile, err := stegano.Decodeimage(\"embeddedimage.png\")\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\n\textractor := stegano.NewExtractHandler()\n\n\t// Extract uncompressed data from the image.\n\tdata, err := extractor.ExtractDataFromImage(coverFile, stegano.LSB)\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\n\t// Print the extracted message.\n\tfmt.Println(string(data))\n}\n```\n\n### 5. Embed at a Specific Bit Depth\n\nEmbed data at a specific bit depth for better control over the hiding technique.\n\n```go\nfunc main() {\n\tcoverFile, err := stegano.Decodeimage(\"coverimage.png\")\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\n\tembedder := stegano.NewEmbedHandler()\n\n\t// Embed the message at a specific bit depth (e.g., 3).\n\tembeddedImage, err := embedder.EmbedAtDepth(coverFile, []byte(\"Hello, World!\"), 3)\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\n\terr = stegano.SaveImage(stegano.DefaultOutputFile, embeddedImage)\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n}\n```\n\n### 6. Extract Data from a Specific Bit Depth\n\nExtract data from an image using the same bit depth used for embedding.\n\n```go\nfunc main() {\n\tcoverFile, err := stegano.Decodeimage(\"embeddedimage.png\")\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\n\textractor := stegano.NewExtractHandler()\n\n\t// Extract data from the image at a specific bit depth (e.g., 3).\n\tdata, err := extractor.ExtractAtDepth(coverFile, 3)\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\n\t// Print the extracted message.\n\tfmt.Println(string(data))\n}\n```\n\n### 7. Check Image Capacity\n\nCheck how much data an image can hold based on the bit depth.\n\n```go\nfunc main() {\n\tcoverFile, err := stegano.Decodeimage(\"embeddedimage.png\")\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\n\t// Calculate and print the data capacity of the image.\n\tcapacity := stegano.GetImageCapacity(coverFile, stegano.MaxBitDepth)\n\tfmt.Printf(\"Image capacity at bit depth %d: %d bytes\\n\", stegano.MaxBitDepth, capacity)\n}\n```\n\n### 8. Embed Encrypted Data\n\nEncrypt the data before embedding it into the image for added security.\n\n```go\nfunc main() {\n\tcoverFile, err := stegano.Decodeimage(\"coverimage.png\")\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\n\t// Encrypt the data before embedding.\n\tencryptedData, err := stegano.EncryptData([]byte(\"Hello, World!\"), \"your-encryption-key\")\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\n\tembedder := stegano.NewEmbedHandler()\n\n\t// Embed the encrypted data into the image.\n\terr = embedder.Encode(coverFile, encryptedData, stegano.LSB, stegano.DefaultOutputFile, true)\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n}\n```\n\n### 9. Extract and Decrypt Data\n\nExtract encrypted data from the image and decrypt it.\n\n```go\nfunc main() {\n\tcoverFile, err := stegano.Decodeimage(\"embeddedimage.png\")\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\n\textractor := stegano.NewExtractHandler()\n\n\t// Extract the encrypted data.\n\tencryptedData, err := extractor.Decode(coverFile, stegano.LSB, true)\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\n\t// Decrypt the data.\n\tdecryptedData, err := stegano.DecryptData(encryptedData, \"your-encryption-key\")\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\n\t// Print the decrypted message.\n\tfmt.Println(string(decryptedData))\n}\n```\n\n---\n\n## Working with Audio\n\n### 1. Embed Data into WAV Files\n\n```go\nfunc main() {\n    embedder := stegano.NewAudioEmbedHandler()\n    \n    err := embedder.EmbedIntoWAVWithDepth(\"input.wav\", \"output.wav\", []byte(\"Hello World\"), stegano.LSB)\n    if err != nil {\n        log.Fatalln(err)\n    }\n}\n```\n\n### 2. Extract Data from WAV Files\n\n```go\nfunc main() {\n    extractor := stegano.NewAudioExtractHandler()\n    \n    data, err := extractor.ExtractFromWAVWithDepth(\"embedded.wav\", stegano.LSB)\n    if err != nil {\n        log.Fatalln(err)\n    }\n    fmt.Println(string(data))\n}\n```\n\n### 3. Embed at Specific Bit Depth\n\n```go\nfunc main() {\n    embedder := stegano.NewAudioEmbedHandler()\n    \n    err := embedder.EmbedIntoWAVAtDepth(\"input.wav\", \"output.wav\", []byte(\"Hello World\"), 3)\n    if err != nil {\n        log.Fatalln(err)\n    }\n}\n```\n\n### 4. Extract from Specific Bit Depth\n\n```go\nfunc main() {\n    extractor := stegano.NewAudioExtractHandler()\n    \n    data, err := extractor.ExtractFromWAVAtDepth(\"embedded.wav\", 3)\n    if err != nil {\n        log.Fatalln(err)\n    }\n    fmt.Println(string(data))\n}\n```\n\n---\n\n## Advanced Options\n\n\u003e 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.\n\n```go\nembedder, err := stegano.NewEmbedHandlerWithConcurrency(12)\nif err != nil {\n\tlog.Fatalln(err)\n}\n\nextractor, err := stegano.NewExtractHandlerWithConcurrency(12)\nif err != nil {\n\tlog.Fatalln(err)\n}\n```\n\n---\n\n## Notes\n\n\u003e - This library can be used with any image type but works best with **PNG** images.\n\u003e - **Bit Depth and Compression**: Ensure that the same bit depth and compression settings are used during both embedding and extraction.\n\u003e - **Default Output Format**: By default, images NEED to be saved in PNG format to avoid any data loss.\n\n---\n\n## Benchmarks\n\n| **Library Name**               | **Test 1 (ns/op)** | **Test 2 (ns/op)** | **Test 3 (ns/op)** | **Avg Time (ns/op)** | **Avg Time (ms/op)** |\n|---------------------------------|--------------------|--------------------|--------------------|----------------------|----------------------|\n| **Stegano**                     | 352,531,567        | 349,444,200        | 348,196,967        | **350,390,578**      | **350.39 ms**        |\n| **Stegano with Concurrency**    | 286,168,125        | 293,260,925        | 284,079,175        | **287,169,408**      | **287.17 ms**        |\n| [**auyer/steganography**](https://github.com/auyer/steganography) | 1,405,256,700      | 1,424,957,200      | 1,401,682,600      | **1,410,965,500**    | **1,410.97 ms**      |\n\n\u003e **Image size:** 10,473,459 bytes  \n\u003e **Text size:** 641,788 bytes  \n\u003e Benchmark code can be found [here](./examples/steganobench)\n\n---\n\n## Future Improvements\n\u003e - **Multi-Carrier Support**: Enable splitting data across multiple images or files for larger data embedding.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2F501urchin%2Fstegano","html_url":"https://awesome.ecosyste.ms/projects/github.com%2F501urchin%2Fstegano","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2F501urchin%2Fstegano/lists"}