Hi all,
just for fun. You can put up to 288 bytes in an X-Face header. If the
message is shorter than 288 bytes it will be padded with a checkerboard pattern.
https://www.dairiki.org/xface/
$ echo "Hello sci.crypt community. :-)" | d2x
#define image_width 48
#define image_height 48
static unsigned char image_bits[] = {
0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x73, 0x63, 0x69, 0x2e, 0x63, 0x72,
0x79, 0x70, 0x74, 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x75, 0x6e, 0x69, 0x74,
0x79, 0x2e, 0x20, 0x3a, 0x2d, 0x29, 0x0a, 0x00, 0xff, 0x00, 0xff, 0x00,
0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,
0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,
0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,
0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,
0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,
0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,
0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,
0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,
0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,
0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,
0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,
0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff
};
Here is the C source code:
// d2x - data to xbm
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#define IMAGE_WIDTH 48
#define IMAGE_HEIGHT 48
#define IMAGE_SIZE (IMAGE_WIDTH * IMAGE_HEIGHT / 8) // 288 Bytes
#define INPUT_SIZE IMAGE_SIZE // 288 Bytes
// Function to embed data into an image with checkerboard padding
void encode(uint8_t *image, const uint8_t *data, size_t bytesRead) {
for (size_t i = 0; i < bytesRead; i++) {
image[i] = data[i];
}
// Checkerboard padding
for (size_t i = bytesRead; i < IMAGE_SIZE; i++) {
// Alternate between 0xFF and 0x00 based on row and column
if ((i / IMAGE_WIDTH) % 2 == (i % IMAGE_WIDTH) % 2) {
image[i] = 0xFF; // White
} else {
image[i] = 0x00; // Black
}
}
}
// Function to extract data from an image
void decode(const uint8_t *image, uint8_t *data) {
for (int i = 0; i < INPUT_SIZE; i++) {
data[i] = image[i];
}
}
// Function to write the XBM format
void write_xbm(const uint8_t *image, FILE *out) {
fprintf(out, "#define image_width %d\n", IMAGE_WIDTH);
fprintf(out, "#define image_height %d\n", IMAGE_HEIGHT);
fprintf(out, "static unsigned char image_bits[] = {\n");
for (int i = 0; i < IMAGE_SIZE; i++) {
// Single space before the first hex value on each line
if (i % 12 == 0) {
fprintf(out, " ");
}
// Write the hex value
fprintf(out, "0x%02x", image[i]);
// Add a comma unless it's the last value
if (i < IMAGE_SIZE - 1) {
fprintf(out, ",");
}
// Add a space after each value
fprintf(out, " ");
// Add a newline after every 12 values
if ((i + 1) % 12 == 0 || i == IMAGE_SIZE - 1) {
fprintf(out, "\n");
}
}
fprintf(out, "};\n");
}
// Function to read the XBM format
int read_xbm(FILE *input, uint8_t *image) {
char line[256];
int index = 0;
while (fgets(line, sizeof(line), input)) {
// Skip lines that do not contain hex values
if (!strstr(line, "0x")) {
continue;
}
// Parse hex values
char *token = strtok(line, ",");
while (token != NULL) {
if (sscanf(token, " 0x%02hhx", &image[index]) == 1) {
index++;
}
token = strtok(NULL, ",");
}
}
return index;
}
// Main function
int main(int argc, char *argv[]) {
int mode = 0; // 0 = Encode, 1 = Decode
// Argument check
if (argc > 1) {
if (strcmp(argv[1], "-d") == 0) {
mode = 1; // Decode mode
} else {
fprintf(stderr, "Usage:\n");
fprintf(stderr, " sx Put data (max. 288 bytes) from stdin into XBM format and write to stdout\n");
fprintf(stderr, " sx -d Decode XBM image from stdin and write data to stdout\n");
return 1;
}
}
if (mode == 1) {
// Decode mode
uint8_t image[IMAGE_SIZE] = {0};
int bytesRead = read_xbm(stdin, image);
if (bytesRead != IMAGE_SIZE) {
fprintf(stderr, "Error: Invalid image size (expected %d bytes, got %d)\n", IMAGE_SIZE, bytesRead);
return 1;
}
uint8_t data[INPUT_SIZE] = {0};
decode(image, data);
fwrite(data, 1, INPUT_SIZE, stdout);
} else {
// Encode mode
uint8_t data[INPUT_SIZE] = {0};
size_t bytesRead = fread(data, 1, INPUT_SIZE, stdin);
if (bytesRead > INPUT_SIZE) {
fprintf(stderr, "Error: Input data too large\n");
return 1;
}
uint8_t image[IMAGE_SIZE] = {0};
encode(image, data, bytesRead);
write_xbm(image, stdout);
}
return 0;
}
Regards
Stefan
--
Onion Courier Home Server Mon-Fri 15:00-21:00 UTC Sat-Sun 11:00-21:00 UTC ohpmsq5ypuw5nagt2jidfyq72jvgw3fdvq37txhnm5rfbhwuosftzuyd.onion:8080 inbox
age1yubikey1qv5z678j0apqhd4ng7p22g4da8vxy3q5uvthg6su76yj0y8v7wp5kvhstum
--- SoupGate-Win32 v1.05
* Origin: fsxNet Usenet Gateway (21:1/5)