Latest Threat Research:SANDWORM_MODE: Shai-Hulud-Style npm Worm Hijacks CI Workflows and Poisons AI Toolchains.Details
Socket
Book a DemoInstallSign in
Socket

node-steg

Package Overview
Dependencies
Maintainers
1
Versions
7
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

node-steg

Over-complicated module for PNG/lossless WEBP-based steganography

Source
npmnpm
Version
1.1.0
Version published
Weekly downloads
0
-100%
Maintainers
1
Weekly downloads
 
Created
Source

First import the CreateBuilder helper and constants from steg

import { consts, CreateBuilder } from 'steg';

You can also import util if you want to control how verbose it is for debugging purposes.

import { util } from 'steg';

Now, lets create a builder.

let steg = CreateBuilder();

The arguments are CreateBuilder([major version, [minor version]]), if you want to use a specific version. At the time of writing, the default is v1.1.

For just packing a file in and calling it a day,

steg.inputImage('path/to/input/image.ext') .outputImage('path/to/output/image2.ext') .addFile('path/to/file') .save();

And to extract it. If reusing the same steg object, clear() must be called.

steg.clear() .inputImage('path/to/output/image2.ext') .load() .then((secs) => { // At this point, you're given a list of extractable items. If you don't care what's in it, or already know, there's a helper function for making it easier to extract everything return steg.extractAll(secs); }) .then(() => console.log('Done'));

Supported image formats are PNG and WEBP (both static and animated). When it saves PNGs, it saves at compression 9 (highest). When it saves WEBPs, it saves as lossless+exact (save transparent pixels). For what I hope are obvious reasons, lossy formats can't work.

For animated WEBP images, the syntax is mostly the same. However, when both supplying paths for saving and loading (except for one exception below) you must provide them in the format frame|<frame number, starting at 0>|.

steg.clear() .inputImage('frame|0|animated.webp') .outputImage('out.webp') // This is the one exception where you don't need the special format // do things as normal .save();

steg.clear() .inputImage('frame|0|out.webp') // etc .load() // etc

There are a number of storage modes available and can be applied separately for both alpha and non-alpha pixels. 3bpp: Stores 3 bits in the pixel, using the LSB of each of the RGB color channels 6bpp: Stores 6 bits using the lower 2 bits of each channel 9bpp: Ditto, but lower 3 bits 12bpp: Lower 4 15bpp: Lower 5 24bpp: Uses the full RGB values. This is handy if you don't care so much about the hiding but do want to use the storage 32bpp: This is a semi-special mode that forces overwriting the full RGBA data of every pixel. This is more implemented for completeness than anything.

There are also modifiers for what's considered alpha vs non-alpha, and which color channels to use if you want to leave one or more untouched.

Below is a full list of what the current steg builder can do. The term "out-of-band" is used to describe information that's needed but not stored in the image(s) and must be found by other means.

== Helper or utility ==

clear() Resets the object for re-use.

dryrun(comp = false) Switches to doing a dry run of the saving process. Everything is supported, but the save() call doesn't do the final saving. This does not create or modify any files. Any compression it would do is skipped and the full size is used instead. Set comp to true to enable compression. This does create temporary files and runs files through compression (where applicable) as it would during the normal saving process.

setPasswords(pws) This is an out-of-band setting. More of a helper function. Pass it an array of passwords to pull from (in order) whenever it needs a password rather than prompting the user.

cliPasswordHandler() Asks the user for missing passwords via the command line and a silent 'Enter password:' prompt.

== Input/output ==

inputImage(path) The input image for both saving and loading.

outputImage(path) The output image for saving.

save() (async) Saves the image(s).

load() (async) Parses the image(s) and returns a list of data sections (see Classes section below).

extractAll(secs = this.#secs) (async) Extract all the sections in secs or, if null/undefined, extract all sections found.

== Out-of-band ==

setHeaderMode(mode) This sets the mode used to store the first half of the header. It defaults to MODE_A3BPP | MODE_3BPP.

setHeaderModeMask(mask) This changes which channels are used to store the first half of the header. It defaults to MODEMASK_RGB.

setGlobalSeed(seed) This uses seed to randomly distribute the header and data around the image. It defaults to disabled. seed is an arbitrary-length string consisting of a-z, A-Z, 0-9, and spaces.

== Header ==

setGlobalMode(mode) This sets the mode used to store the second half of the header, as well as the rest of the data in general. It defaults to MODE_A3BPP | MODE_3BPP.

setGlobalModeMask(mask) This changes which channels are used to store the second half of the header, as well as the rest of the data in genereal. It defaults to MODEMASK_RGB.

setGlobalAlphaBounds(bounds) This changes what alpha value is considered alpha vs non-alpha. It supports 8 steps, each roughly 36 apart. Defaults to ALPHA_255.

== Sections ==

setAlphaBounds(bounds) This changes what alpha value is considered alpha vs non-alpha from what is set globally until another setAlphaBounds is called or is cleared.

clearAlphaBounds() Removes the active setAlphaBounds and returns the alpha value to the global one.

setRect(x, y, width, height) Bounds all operations within the defined rectangle until another setRect called or is cleared.

clearRect() Removes the active setRect.

setMode(mode) Override the global mode until another setMode is called or is cleared.

clearMode() Reset the mode back to the global mode.

setModeMask(mask) Override the global mode mask until another setModeMask is called or is cleared.

clearModeMask() Reset the mode mask back to the global mode mask.

setSeed(seed) Override the global seed until another setSeed is called or is cleared.

clearSeed() Reset the seed back to the global seed. If there was no global seed, this disables the randomness.

pushCursor()/popCursor() Save/load the image index and x,y position of the cursor.

moveCursor(x, y, index = 0) Move the cursor to x, y in the current image or the one specified by index.

setImageTable(inputFiles, outputFiles) This sets up a table of images you can jump around between with moveCursor. Both arguments are arrays and must be the same length. Naming rules from inputImage apply to both (so WEBP anim 'frame||' rules apply to outputFiles). It is, however, currently unsupported to mix anim and non-anim WEBP, or mix frames. Example: Each assuming .inputImage('frame|0|in.webp').outputImage('frame|0|out.webp') .setImageTable([ 'frame|1|in.webp' ], [ 'frame|1|out.webp' ]) This is valid .setImageTable([ 'frame|4|in.webp' ], [ 'frame|1|out.webp' ]) This is unsupported .setImageTable([ 'random.png' ], [ 'frame|1|out.webp' ]) This is also unsupported, as is using 'random.webp' .setImageTable([ 'frame|1|in.webp' ], [ 'random.webp' ]) This is also unsupported .setImageTable([ 'frame|1|in.webp' ], [ 'frame|1|different.webp' ]) This is also unsupported The short version is that it only supports modifying frames in the same animation, not replacing or extracting them. See steg/webp.mjs or the webpmux tool if you need that (I'd recommend webp.mjs as I've got a more-complete toolset than webpmux does in it).

clearImageTable() Disables the active table and moves the cursor back to the main image. Any images from any previously-active tables will still be written to properly.

setCompression(type, level = 0, text = false) Set the active compression algorithm to run files/text through. Currently, only COMP_GZIP and COMP_BROTLI are supported. For GZIP: level must range 0-9 text is unused For BROTLI: level must range 0-11 text enables BROTLI's special text-mode compression

clearCompression() Clear an active setCompression.

setEncryption(type, pw) Set the active encryption algorithm to run files/text through. Currently only CRYPT_AES256 (AES-256-CBC) is supported.

clearEncryption() Clear an active setEncryption.

== Files/text ==

addFile(path, name, compressed = false) Add the file at path to the image under the name name. Set compressed to true if the file is already compressed via the active compression mode.

addDirectory(path, full = false, recursive = false, compressed = false) Add the contents of the directory at path to the image. File names are preserved as-is and the basename of path is used as the base path. Example, addDirectory('a/b/c') will add the contents of that directory under c/. Set full to true to add the path names as-is rather than the basename. Example, addDirectory('a/b/c') will then add the contents of that directory under a/b/c/. Set recursive to true to recursively add any other directories until the path. Set compressed to true if ALL files under path are already compressed via the active compression mode.

addPartialFile(path, name, index, compressed = false) Add the file at path you intend to store in pieces under the name name and index index. Set compressed to true if the file is already compressed via the active compression mode. index can be any integer 0 <= n <= 255 and is used solely for your own reference in addPartialFilePiece.

addPartialFilePiece(index, size = 0, last = false) Add a piece of file index. If size is 0 or greater than the remaining size of the file, the rest of the file is written and last is assumed true. Set last to true to flag that this is the last piece you intend to write. You can use this if you don't intend to write the entire file.

addText(text, honor = TEXT_HONOR_NONE) Adds a simple block of text to the image. More simple than a text file. honor is a mask of TEXT_HONOR_ENCRYPTION and TEXT_HONOR_COMPRESSION to control which, if any, are desired to apply to this text block.

== Classes ==

StegFile name Name of the file size Size of the file as it was stored (after compression/encryption) realSize Uncompressed/decrypted size of the file (only computed after extracting) extract(path = './extracted') (async) Extract the file to path

StegPartialFile name Name of the file size Size of the file as it was stored (after compression/encryption) realSize Uncompressed/decrypted size of the file (only computed after extracting) extract(path = './extracted') (async) Extract the file to path

StegText size Size of the text as it was stored (after compression/encryption) realSize Uncompressed/decrypted size of the text (only computed after extracting) extract() (async) Extracts and returns the text

== Util ==

util has many things, but for controlling verbosity, only util.Channels, util.debug, and util.setChannel are important.

debug(v) Set v to true to enable debug mode, false to disable it, or pass nothing to get the current debug state. This mostly only disables the file extraction progress messages ("Saved x of size") Does NOT set channel to DEBUG

Channels SILENT: Outputs nothing at all NORMAL: Default; Outputs basic information during saving/extracting, such as the number of pixels changed per image and extraction progress during exracting. VERBOSE: Ouputs more detailed information about what it's doing to the image. Mostly useless. VVERBOSE: Outputs even more information about what it's doing, but mostly during loading. DEBUG: Outputs each and every modified pixel of every image it touches.

setChannel(channel) Sets the output channel to one of the above.

For a full (more technical) description of the format things are stored in the image(s), see the file steg/specs/v..spec (like steg/specs/v1.1.spec). Also see test.mjs for more examples in a very ugly file.

FAQs

Package last updated on 02 Oct 2020

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts