Image Decryption
Getting your image back — the password matters, the metadata matters more
- encrypted_image
- metadata
- decrypted_image
This is the other half of the ComfyUI-Image-Encryption pair: point it at the static-looking image the encryption node produced, give it the same password, and it rebuilds the original, pixel for pixel. One input you care about is obvious (the password). The other one - the thing that actually bites people - is the metadata.
Why the metadata is the whole game
The encryption node doesn't just scramble pixels. It also writes a JSON metadata payload recording exactly how it did it: block size, rounds, permutation mode, diffusion mode, seed, and the original image dimensions. Decryption needs that recipe. It can't infer it from the pixels, and the password alone isn't enough.
So how does the metadata get to this node? Three ways, in this order:
- The
metadatainput - explicitly wired from the encryption node's JSON output. Bulletproof. - Attached to the tensor in memory - the encryption node sticks the metadata onto the image object itself, so if you encrypt and decrypt in the same workflow without reloading from disk, it just works with nothing connected.
extra_pnginfo- when the encrypted image goes through a standardSaveImage, the metadata rides along into the PNG's text chunks (the same workflow-in-the-file plumbing ComfyUI uses everywhere).
And here's the trap, straight from the README: that tensor-attached metadata and extra_pnginfo only exist while the image is in memory in the same run. The moment you save the encrypted PNG, restart, and reload it with LoadImage, you get a plain tensor - no attached metadata, no extra_pnginfo. Decrypting a reloaded file without explicitly connecting the saved metadata JSON gives you the "No encryption metadata found" error. Keep the metadata JSON output wired in, or save it alongside the file, and you're fine.
The inputs and the output
encrypted_image(IMAGE) - the scrambled tensor.password(STRING) - must match the encryption password exactly. It's hashed the same way (SHA-256) and every permutation, every keystream byte, derives from it.metadata(JSON, optional) - connect it if you're decrypting a reloaded file.
Output is a single decrypted_image (IMAGE), lossless at 8-bit: the pipeline reverses the chained diffusion first, then undoes each permutation round in reverse order, then crops the edge-padding back to the original dimensions. Wire the output into SaveImage and you've got your original back.
The wrong-password failure mode
Here's the thing nobody warns you about: this is not authenticated encryption. Type the wrong password and the node doesn't error - it happily "decrypts" into meaningless noise, because every wrong key produces some deterministic garbage. The only way to know you got it wrong is to look at the output and see static. So double-check the password before you panic. (Also: if you see noise after a successful decrypt, make sure the metadata is the one from that exact image - a mismatched recipe garbles the output the same way.)
Install
Same pack as Image Encryption - one install gives you both nodes. ComfyUI Manager, search ComfyUI-Image-Encryption, or:
cd ComfyUI/custom_nodes
git clone https://github.com/Zhuozhuo-219/ComfyUI-Image-Encryption
Restart ComfyUI and it'll be in the ImageEncrypt category. The only extra dependency (cryptography) is needed for decrypting AES-CTR-encrypted images - same rule as on the encryption side.
Honest bottom line: it's a tidy, deterministic utility, not bank-grade crypto. Use it for keeping images private from the curious. Just never delete that metadata JSON.
Inputs (3)
| Name | Type | Default | Description |
|---|---|---|---|
| encrypted_image | IMAGE | — | |
| password | STRING | — | |
| metadataopt | JSON | — |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| decrypted_image | IMAGE | — |