Skip to content

Instantly share code, notes, and snippets.

@rustyrussell
Created February 21, 2020 04:53
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rustyrussell/f23ed9ae67b01e603686ad0c1344e82d to your computer and use it in GitHub Desktop.
Save rustyrussell/f23ed9ae67b01e603686ad0c1344e82d to your computer and use it in GitHub Desktop.
Quick code to scramble / unscramble an image given a key.
#include <ccan/array_size/array_size.h>
#include <ccan/asort/asort.h>
#include <ccan/crypto/sha256/sha256.h>
#include <ccan/err/err.h>
#include <ccan/str/hex/hex.h>
#include <ccan/short_types/short_types.h>
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include <SDL2/SDL_pixels.h>
#define GRIDBITS 4
#define GRIDPIX (1 << GRIDBITS)
static u8 *pixpos(SDL_Surface *image, size_t x, size_t y)
{
u8 *p = image->pixels;
/* Get to correct row, then correct byte */
return p + image->pitch * y + image->format->BytesPerPixel * x;
}
static u32 get_pixelval(const u8 *p, int bytes_per_pixel)
{
if (bytes_per_pixel == 3)
return ((u32)p[0] << 16) | ((u32)p[1] << 8) | p[2];
else if (bytes_per_pixel == 4)
return *(u32 *)p;
else
errx(1, "FIXME: Support %u BytesPerPixel!",
bytes_per_pixel);
}
static void put_pixelval(u8 *p, int bytes_per_pixel, u32 pixel)
{
if (bytes_per_pixel == 3) {
p[0] = pixel >> 16;
p[1] = pixel >> 8;
p[2] = pixel;
} else if (bytes_per_pixel == 4)
*(u32 *)p = pixel;
else
errx(1, "FIXME: Support %u BytesPerPixel!",
bytes_per_pixel);
}
struct coord {
u16 key;
u8 x, y;
};
static int cmp_key(const struct coord *a, const struct coord *b, void *unused)
{
if (a->key < b->key)
return -1;
else if (a->key > b->key)
return 1;
return 0;
}
static u16 get_16_bits(struct sha256 *val, size_t *bytes_used)
{
u16 v;
/* Need more bits? Hash again */
if (*bytes_used + 2 > sizeof(*val)) {
sha256(val, val, sizeof(*val));
*bytes_used = 0;
}
v = ((u16)val->u.u8[*bytes_used] << 8) | val->u.u8[*bytes_used + 1];
(*bytes_used) += 2;
return v;
}
/* To make swap reversible, we can only swap pairs once.
* Simplest algorithm is sort by a key, and swap in pairs.
*/
static void scramble_grid(SDL_Surface *image,
size_t x, size_t y,
struct sha256 *val)
{
struct coord coords[GRIDPIX * GRIDPIX];
size_t bytes_used = 0;
for (size_t i = 0; i < ARRAY_SIZE(coords); i++) {
coords[i].key = get_16_bits(val, &bytes_used);
coords[i].x = i % GRIDPIX;
coords[i].y = i / GRIDPIX;
}
asort(coords, ARRAY_SIZE(coords), cmp_key, NULL);
for (size_t i = 0; i < ARRAY_SIZE(coords); i += 2) {
u8 *p1 = pixpos(image, x + coords[i].x, y + coords[i].y);
u8 *p2 = pixpos(image, x + coords[i+1].x, y + coords[i+1].y);
u32 p1val = get_pixelval(p1, image->format->BytesPerPixel);
u32 p2val = get_pixelval(p2, image->format->BytesPerPixel);
put_pixelval(p1, image->format->BytesPerPixel, p2val);
put_pixelval(p2, image->format->BytesPerPixel, p1val);
}
}
int main(int argc, char *argv[])
{
struct sha256 val;
if (argc != 4)
errx(1, "Usage: permute-image 64-hexchars in.png out.png");
if (!hex_decode(argv[1], strlen(argv[1]), &val, sizeof(val)))
errx(1, "Invalid seed");
if (SDL_Init(SDL_INIT_VIDEO) == -1)
errx(1, "SDL init failed: %s", SDL_GetError());
SDL_Surface *image = IMG_Load(argv[2]);
SDL_LockSurface(image);
for (size_t x = 0; x + GRIDPIX <= image->w; x += GRIDPIX) {
for (size_t y = 0; y + GRIDPIX <= image->h; y += GRIDPIX) {
scramble_grid(image, x, y, &val);
}
}
SDL_UnlockSurface(image);
IMG_SavePNG(image, argv[3]);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment