{"id":19583909,"url":"https://github.com/nonprojects/steganon","last_synced_at":"2025-04-27T11:31:35.913Z","repository":{"id":219094650,"uuid":"748163599","full_name":"NonProjects/steganon","owner":"NonProjects","description":"Steganography LSB (with PRNG by seed)","archived":false,"fork":false,"pushed_at":"2024-07-24T13:54:57.000Z","size":60,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2024-10-31T17:47:05.656Z","etag":null,"topics":["lsb-steganography","steganography","steganography-algorithms","steganography-library"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"lgpl-2.1","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/NonProjects.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","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-01-25T12:08:28.000Z","updated_at":"2024-09-15T04:50:25.000Z","dependencies_parsed_at":"2024-02-05T07:47:27.054Z","dependency_job_id":null,"html_url":"https://github.com/NonProjects/steganon","commit_stats":null,"previous_names":["nonprojects/steganon"],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NonProjects%2Fsteganon","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NonProjects%2Fsteganon/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NonProjects%2Fsteganon/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NonProjects%2Fsteganon/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/NonProjects","download_url":"https://codeload.github.com/NonProjects/steganon/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":224069597,"owners_count":17250453,"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","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":["lsb-steganography","steganography","steganography-algorithms","steganography-library"],"created_at":"2024-11-11T07:45:51.173Z","updated_at":"2025-04-27T11:31:35.873Z","avatar_url":"https://github.com/NonProjects.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# SteganoN\n\n**Steganon** is an extended implementation of the [LSB Matching steganography algorithm](https://www.google.com/search?q=LSB+Matching+steganography+algorithm).\n\nIn short, steganography **LSB** is a method of hiding data inside pixels of image. Every pixel of a regular image typically consist of three integers (**0-255**, or **one byte**). They describe an amount of **R**ed, **G**reen and **B**lue colors. We take User's data to hide and convert it to a **bits**; then we take the next target pixel and select first (color channel) integer: **R**. If the last bit of color channel is the **same as our next bit** from the data bit string, **we do nothing**; **if they differ**, we **randomly add or subtract 1 from color channel**. For example, if channel is `222`, we **randomly** `+1` or `-1`, so result would be either `221` or `223`. However, **if channel is** `0` **we always** `+1`, and **if** `255` **we always** `-1`. This essentially will change the [least significant bit](https://en.wikipedia.org/wiki/Bit_numbering) of color channel (e.g **R**) to the bit we want. Repeat this process for **G** and **B** then write altered pixel back into image. Repeat on the next pixels until User's data is not empty. Such change to **RGB** is invisible to human eye and gives us chance to hide **three bits** of data **per pixel** (or, in this library, — three pixels per byte).\n\n## Difference between classic LSB and LSB\\_MWS\n\nThis repository implements a special type of LSB Matching: **LSB Matching With [Seed](https://en.wikipedia.org/wiki/Random_seed)** (short. `LSB_MWS`). This algorithm utilizes [**PRNG**](https://en.wikipedia.org/wiki/Pseudorandom_number_generator) with changeable [seed](https://en.wikipedia.org/wiki/Random_seed) to select targeted pixels. Moreover, in `LSB_MWS`, one cover Image may contain different, multiple secret Datas on different, multiple Seeds. Thus, this project supports the **Deniable Hide** feature — you can reveal as much Data as you want.\n\n**Deniable Hide** works as a chain of Seeds. Instead of specifying only one Seed, you can pass as many as you wish and attach unique secret Data to each one of them independently. `LSB_MWS` *Hide function* will ensure that each bit of different Datas are stored in unique Pixel without overlapping. On *Extract*, to get a first hidden Data you will need to provide a Seed`(1)`, to get a second Data — Seed`(1)` \u0026 Seed`(2)`, to get a third Data — Seed`(1)`, Seed`(2)` \u0026 Seed`(3)`, and so on. There is a **zero correlations between Seeds**. In case of extortion, **you can reveal only Seed**`(1)` and criminal—or *whoever*, will **never** know that there is more hidden data deeper.\n\n**We don't feed Seeds directly into the PRNG**, we **hash** them firstly in a special\\\nmanner with `SHA512` **truncated to the *last* 32 bytes**.\n\n***(Iterations on MultiSeed with three Seeds)***\n1. We create *Initializator* hash by hashing a constant-*Basis* with `ImageSize` (*Width*/*Height*);\n2. We hash *Initializator* with **Seed**`(1)` — that is our ***first*** **prngS**`(1)` (PRNG Seed);\n3. We hash **prngS**`(1)` with **Seed**`(2)`, — that is our ***second*** PRNG Seed;\n4. We hash **prngS**`(2)` with **Seed**`(3)`, — that is our ***third*** PRNG Seed.\n\nIt means that **Seeds are dependent on each other** and *Initializator* **depends on the Image Width \u0026 Height**, thus, each unique-sized Image will utilize **different Seed values for PRNG**. This will add some protection against the brute-force or seed re-usage.\n\n###### This can be disabled with `use_raw_seed=True` on `LSB_MWS`, though *not* recommended.\n\n## Installation\n\n**You can install SteganoN with PIP**\n```bash\npip install steganon\n```\n**Or you can install it after `git clone`**\n```bash\npython -m venv steganon-env\ncd steganon-env \u0026\u0026 . bin/activate\n\ngit clone https://github.com/NonProjects/steganon\npip install ./steganon\n```\n**SteganoN has basic CLI implementation**\n```bash\n# Install SteganoN with CLI\npip install steganon[cli]\n```\n![steganon1.0](https://github.com/user-attachments/assets/608752c2-3cf3-4c6f-abf5-d652700f9e6a)\n\n## Example\n\n### (One Seed) Hiding Secret Data\n\n```python3\nfrom steganon import Image, LSB_MWS\n\nimage = Image.open('example.png') # Open targeted Image\nlsb_mws = LSB_MWS(image, b'seed_0') # Init with seed=b'seed_0'\n\nlsb_mws.hide(b'Secret!!!') # Write secret message to image pixels\nimage.save('example.png') # Save altered image with secret data\n```\n\n### (One Seed) Extracting Secret Data\n```python\nfrom steganon import Image, LSB_MWS\n\nimage = Image.open('example.png') # Open Image with hidden data\nlsb_mws = LSB_MWS(image, b'seed_0') # Init with seed=b'seed_0'\n\nprint(lsb_mws.extract()) # b'Secret!!!'\n```\n\n### (MultiSeed) Hiding Secret Data\n\n```python3\nfrom steganon import Image, LSB_MWS\n\nimage = Image.open('example.png') # Open targeted Image\nseeds = (b'seed_0', b'seed_1',  b'seed_2') # You can use as many as you want\nlsb_mws = LSB_MWS(image, seeds) # Init LSB_MWS with multiple seeds\n\nlsb_mws.hide(b'Secret data on Seed(0)!!!') # Write secret message to image pixels\nlsb_mws.next() # Switch to the next Seed (b'seed_1')\n\nlsb_mws.hide(b'Secret data on Seed(1)!!!') # Write secret message to image pixels\nlsb_mws.next() # Switch to the next Seed (b'seed_2')\n\nlsb_mws.hide(b'Secret data on Seed(2)!!!') # Write secret message to image pixels\nimage.save('example.png') # Save altered image with secret data\n```\n\n### (MultiSeed) Extracting Secret Data\n```python\nfrom steganon import Image, LSB_MWS\n\nimage = Image.open('example.png') # Open targeted Image\nseeds = (b'seed_0', b'seed_1',  b'seed_2') # You can use as many as you want\nlsb_mws = LSB_MWS(image, seeds) # Init LSB_MWS with multiple seeds\n\nprint(lsb_mws.extract()) # b'Secret data on Seed(0)!!!'\nlsb_mws.next() # Switch to the next Seed (b'seed_1')\nprint(lsb_mws.extract()) # b'Secret data on Seed(1)!!!'\nlsb_mws.next() # Switch to the next Seed (b'seed_2')\nprint(lsb_mws.extract()) # b'Secret data on Seed(2)!!!'\n```\n\n## Image Comparison\n\nHere is comparison between [**Original image (1)**](https://github.com/user-attachments/assets/2d639687-718e-4868-afbb-fc431b35e747) and [**Image with written on pixels data (2)**](https://github.com/user-attachments/assets/4b3de992-2fcb-4c54-84e2-94546cd0c168).\n\n\u003cimg src=\"https://github.com/user-attachments/assets/b218038d-94c6-41bc-b471-9567112e6c6e\" width=\"777\" height=\"-1\"\u003e\u003c/img\u003e\n\n[**Modified Image (2)**](https://github.com/user-attachments/assets/4b3de992-2fcb-4c54-84e2-94546cd0c168) has whole [**Zen of Python**](https://peps.python.org/pep-0020/#the-zen-of-python) written on it.\\\nYou can extract Zen from **(2)** by using Seed `b'spam_eggs'`\n\n## TestMode on LSB\\_MWS\n\n`steganon.LSB_MWS` class has a `testmode` key. We can use it to check affected pixels under different seeds\n\n\u003cimg src=\"https://github.com/user-attachments/assets/a2e1beda-f205-432e-8c2e-56dfb0d8ead7\" width=\"777\" height=\"-1\"\u003e\u003c/img\u003e\n\n## Additional Information\n\n**Tested formats:**\n\n* ✅  **PNG**\n* ✅  **BMP**\n* ✅  **TIFF**\n* ✅  **WEBP**\n* ✅  **JPEG2000**\n* ❌  **JPG**\n* ❌  **HEIF**\n\n0. This library \u0026 implementation **wasn't** verified by steganography experts. **Use with caution!**\n1. **Always use a different seed!** Pixel positions `*`may be the same on different Images and Data!\n2. This library **will not** work with JPEG due to its lossy design. **Use lossless formats** (e.g PNG, WEBP, etc);\n3. Best `**`template to hide data is a **compressed JPEG turned to PNG**. Library has `tools.pngify`, use it;\n4. The **bigger your Image**, the **bigger amount of Data you can hide** (though the less data—the `***`better).\n\n`*  ` If Image Width/Height and Seed are the same. **Always use a unique Seed**\\\n`** ` Your cover Image **should** have a decent amount of \"Noise\" / Compression\\\n`***` Quite obviously, **the lower coverage**, the **less chance for analyze tools**\n\nContact me on **thenonproton@pm.me** (or just [**open Issue**](https://github.com/NonProjects/steganon/issues)) if you have any feedback on this library.\n\n## All Aboard!\n\nTry to download [**this example image**](https://github.com/user-attachments/assets/cd1e1785-fead-4a80-83c7-f3400334c756) and extract secret information from it with seed `b'OZZY'`\\\nSave data to the file with `.ogg` extension and play it with your favourite media player.\n\n###### *Flying high again!*\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnonprojects%2Fsteganon","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnonprojects%2Fsteganon","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnonprojects%2Fsteganon/lists"}