arkimg 0.0.1
Encrypted image library
To use this package, run the following command in your project's root directory:
Manual usage
Put the following dependency into your project's dependences section:
ArkImg
ArkImg is a library that allows you to embed encrypted data into image files (PNG, JPEG, BMP, WebP). It can be used to hide and securely store or transfer confidential information or files within images.
Features
- Embed and extract data in PNG/JPEG/BMP/WebP images
- Data encryption using AES
- Signing and verification using Ed25519
- Support for embedding multiple files and metadata
How to Use as a Library
Usage
dub add arkimg
Sample Code
import arkimg;
import std.file;
auto commonKey = createCommonKey();
auto prvKey = createPrivateKey();
auto pubKey = createPublicKey(prvKey);
auto img = new ArkPng;
// Set the AES common key. 128bits/192bits/256bits
img.setKey(commonKey);
// Load and set the base image to be used as a thumbnail
img.baseImage = cast(immutable(ubyte)[])std.file.read("input.bmp");
// Insert a hidden file
img.addSecretItem(cast(immutable(ubyte)[])std.file.read("secret.png"));
// Optionally, you can sign the image
// The key used for image signing must be a 32-byte Ed25519 private key.
img.sign(prvKey);
assert(img.hasSign);
assert(img.verify(pubKey));
std.file.write("encrypted.png", img.save());
API
- ArkImg: interface
void load(in ubyte[] binary)
: Load image file dataimmutable(ubyte)[] save() const
: Save data to image filevoid setKey(in ubyte[] commonKey)
: Set the common key for encryption/decryptionvoid sign(in ubyte[] prvKey)
: Sign all databool verify(in ubyte[] pubKey) const
: Verify the signature of all databool hasSign() const
: Check if the image has a signaturevoid metadata(in JSONValue metadata)
: Set metadataJSONValue metadata() const
: Get metadatavoid baseImage(in ubyte[] binary, string mimeType = "image/bmp")
: Set base imageimmutable(ubyte)[] baseImage(string mimeType = "image/bmp")
: Get base imagevoid addSecretItem(in ubyte[] binary, string name = null, string mimeType = null, in ubyte[] prvKey = null)
: Add attached data (in plaintext)void clearSecretItems()
: Remove all attached datasize_t getSecretItemCount() const
: Get the number of attached encrypted dataimmutable(ubyte)[] getDecryptedItem(size_t idx) const
: Get decrypted attached dataimmutable(ubyte)[] getEncryptedItem(size_t idx) const
: Get encrypted attached data- ArkBmp: ArkImg
- ArkPng: ArkImg
- ArkJpg: ArkImg
- ArkWebp: ArkImg
- Helper functions
string mimeType(string filename)
: Get MIME type from filenameimmutable(ubyte)[] createCommonKey(size_t keySize = 32)
: Generate a common keyimmutable(ubyte)[] createRandomIV()
: Generate an initialization vector (usually not used)immutable(ubyte)[] createPrivateKey()
: Generate a private key for signingimmutable(ubyte)[] createPublicKey(in ubyte[] prvKey)
: Generate a public key for verificationArkImg loadImage(immutable(ubyte)[] binary, string mimeType = "image/png", in ubyte[] commonKey, in ubyte[] iv = null)
: Load image from byte arrayArkImg loadImage(string filename, in ubyte[] commonKey = null, in ubyte[] iv = null)
: Load image from filenameimmutable(ubyte)[] saveImage(ArkImg img, string mimeType = "image/png", in ubyte[] commonKey, in ubyte[] iv = null)
: Save image to byte array (save to file separately)
File Structure Specifications
PNG
Data is included at any position, but usually after the IDAT chunk (image data):
- eDAt chunk: Encrypted data body. There may be multiple per file.
- eMDt chunk: Metadata. 0 or 1 per file.
Note: Some browsers or viewers may not be able to handle PNG images with chunks after the IDAT chunk.
JPG
Data is included after the EOI (end marker) in the following structure:
[SOI] | [Segment 1] | [Segment 2] | ... | [EOI] | [Encrypted Chunk 1] | [Encrypted Chunk 2] ...
[Encrypted Chunk]
: [Type: 4 bytes] | [Length: 4 bytes] | [Data: N bytes]
- Encrypted chunk: multiple
- Signature: 4 bytes
- Data length: 4 bytes LittleEndian unsigned 64-bit integer
- Data: N bytes
There may be multiple encrypted chunks. Each encrypted chunk contains a signature, a data length, and variable-length data.
- Signature
['E', 'D', 'A', 'T']
: Data is encrypted data body. There may be multiple per file. 4 bytes: [0x45, 0x44, 0x41, 0x54] as "EDAT" in ASCII codes. - Signature
['E', 'M', 'D', 'T']
: Data is metadata. 0 or 1 per file. 4 bytes: [0x45, 0x4d, 0x44, 0x54] as "EMDT" in ASCII codes.
Note: Some browsers or viewers may not be able to handle JPG images with data after the EOI marker.
BMP
Data is included after the end of the pixel data specified by the image size in the BMP info header, in the following structure:
[Bitmap File Header] | [Bitmap Info Header] | [Color Pallete] | [Pixel Data] | [Encrypted Chunk 1] | [Encrypted Chunk 2] ...
[Encrypted Chunk]
: [Signature: 4 bytes] | [Length: 4 bytes] | [Data: N bytes]
- Encrypted chunk: multiple
- Signature: 4 bytes
- Data length: 4 bytes LittleEndian unsigned 64-bit integer
- Data: N bytes
There may be multiple encrypted chunks. Each encrypted chunk contains a signature, a data length, and variable-length data.
- Signature
['E', 'D', 'A', 'T']
: Data is encrypted data body. There may be multiple per file. 4 bytes: [0x45, 0x44, 0x41, 0x54] as "EDAT" in ASCII codes. - Signature
['E', 'M', 'D', 'T']
: Data is metadata. 0 or 1 per file. 4 bytes: [0x45, 0x4d, 0x44, 0x54] as "EMDT" in ASCII codes.
WebP
Data is included after the end of the pixel data specified by the image size in the BMP info header, in the following structure:
- Encrypted chunk: multiple
- Chunk FourCC: 4 bytes
- Chunk size: 4 bytes LittleEndian unsigned 32-bit integer
- Payload: N bytes
[Webp File Header] | [Chunks] | ... | [Encrypted Chunk 1] | [Encrypted Chunk 2] ...
[Encrypted Chunk]
: [FourCC: 4 bytes] | [Chunk Size: 4 bytes] | [Data: N bytes]
There may be multiple encrypted chunks. Each encrypted chunk contains a FourCC, a chunk size, and variable-length payload.
- FourCC
['E', 'D', 'A', 'T']
: Data is encrypted data body. There may be multiple per file. 4 bytes: [0x45, 0x44, 0x41, 0x54] as "EDAT". - FourCC
['E', 'M', 'D', 'T']
: Data is metadata. 0 or 1 per file. 4 bytes: [0x45, 0x4d, 0x44, 0x54] as "EMDT".
Encrypted Data Body
Encrypted byte array in one of the following formats:
- GCM encryption mode
- Start: IV (12 bytes)
- Data: AES-encrypted data
- End: Authentication data (16 bytes)
- CBC encryption mode (no IV specified/IV included in data)
- Start: IV (16 bytes)
- Data: AES-encrypted data
- CBC encryption mode (IV specified/IV not included in data)
- Data: AES-encrypted data
Decrypting the encrypted data body yields the confidential information as a byte array.
Metadata
Encrypted byte array in one of the following formats:
- GCM encryption mode
- Start: IV (12 bytes)
- Data: AES-encrypted data
- End: Authentication data (16 bytes)
- CBC encryption mode (no IV specified/IV included in data)
- Start: IV (16 bytes)
- Data: AES-encrypted data
- CBC encryption mode (IV specified/IV not included in data)
- Data: AES-encrypted data
Decrypting the metadata yields the following JSON data:
(root)
: Object(root).items
: Array, optional(root).items[*]
: Object / Metadata for the Nth encrypted data(root).items[*].name
: String, optional / Filename of the encrypted data(root).items[*].mime
: String, optional / File type of the encrypted data(root).items[*].sign
: String, optional / 32-byte Ed25519 signature data encoded in Base64URLNoPadding(root).items[*].modified
: String, optional / File modification date (ISO8601/UTC) formatYYYY-MM-DDTHH:mm:SS.SSSZ
(root).items[*].comment
: String, optional / Any comment(root).items[*].(any)
: Any, optional / Any additional data per encrypted data(root).(any)
: Any, optional / Any additional data for the entire file
Example JSON for metadata:
{
"items": [
{
"comment": "Test encrypted image",
"mime": "image/png",
"modified": "2025-05-02T10:10:02.1455478Z",
"name": "secret.png",
"sign": "C5S8mzGFto9X8aUStlkvue06cGKYA6G7bi4alClNQAveq1GfZKxNnhlUsBBWqxzjm-umSIUSuPvR5m0gb9e_Bw"
}
]
}
How to Use the Command Line Tool
Main Features
- Embed secret data into images (archive)
- Extract embedded data (extract)
- Encrypt and decrypt data
- Edit, delete, and list embedded data
- Key generation, signing, and verification
Build
cd examples/arkimg_cli
dub build
Usage
Command Line Examples
# Generate a key
# CommonKey: F25B09DF39C113BD5F81871ED12221C2
# The generated key will be output. Use this CommonKey for <key> below.
$ arkimg keyutil --genkey
# Embed a file into an image (file specified)
# Encrypt and embed secret.png into input.png, save as encrypted.png
arkimg encrypt -i input.png -s secret.png -o encrypted.png -k <key>
# Extract an embedded file (file specified)
# Decrypt and extract secret.png from encrypted.png, save as decrypted.png
arkimg encrypt -i encrypted.png -s secret.png -o decrypted.png -k <key>
# Embed all files in a directory into an image
# Encrypt and embed all files in secretdir into input.png, save as encrypted.png
arkimg archive -i input.png -s secretdir -o encrypted.png -k <key>
# Extract all embedded files to a directory
# Decrypt and extract all files from encrypted.png, save to outdir
arkimg extract -i encrypted.png -o outdir -k <key>
License
This program is provided under the BSL-1.0 license, but depends on the following libraries, each provided under their respective licenses.
This project depends on the following libraries:
Optionally, the following libraries can be enabled:
- 0.0.1 released 32 days ago
- shoo/arkimg
- BSL-1.0
- Copyright © 2024, SHOO
- Authors:
- Dependencies:
- libwebp, jpeg-turbo, libpng, openssl-static
- Versions:
-
0.0.1 2025-Jul-30 ~main 2025-Jul-30 - Download Stats:
-
-
0 downloads today
-
1 downloads this week
-
2 downloads this month
-
2 downloads total
-
- Score:
- 0.0
- Short URL:
- arkimg.dub.pm