• Re: Putting encrypted data in an X-Face Header :-)

    From Stefan Claas@21:1/5 to Stefan Claas on Sat Mar 22 12:59:35 2025
    Stefan Claas wrote:

    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;

    d2x and no longer sx.

    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)
  • From Stefan Claas@21:1/5 to All on Sat Mar 22 12:53:51 2025
    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)
  • From Stefan Claas@21:1/5 to Rich on Sat Mar 22 17:10:08 2025
    Rich wrote:
    Stefan Claas <fgrsna.pynnf@vagrearg.eh> wrote:
    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.

    Nice. Provided one had a public key system with keys less than 288
    bytes, that could carry a public key for further comms (or for
    authenticating the message contents).


    Ed25519 pub keys are 32 hex bytes. I use my minicrypt and sv and sve with friends for encryption/signing.

    https://github.com/706f6c6c7578/minicrypt https://github.com/706f6c6c7578/hex2pem
    https://github.com/706f6c6c7578/red
    https://github.com/706f6c6c7578/sv
    https://github.com/706f6c6c7578/sve

    Regards
    Stefan

    P.S. This message is signed with my 'coffee' key. (I always sign
    my Usenet messages. :-))

    --
    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)
  • From Rich@21:1/5 to Stefan Claas on Sat Mar 22 15:28:50 2025
    Stefan Claas <fgrsna.pynnf@vagrearg.eh> wrote:
    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.

    Nice. Provided one had a public key system with keys less than 288
    bytes, that could carry a public key for further comms (or for
    authenticating the message contents).

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Stefan Claas@21:1/5 to Stefan Claas on Sat Mar 22 17:16:28 2025
    Stefan Claas wrote:
    Rich wrote:
    Stefan Claas <fgrsna.pynnf@vagrearg.eh> wrote:
    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.

    Nice. Provided one had a public key system with keys less than 288
    bytes, that could carry a public key for further comms (or for authenticating the message contents).


    Ed25519 pub keys are 32 hex bytes. I use my minicrypt and sv and sve with friends for encryption/signing.

    https://github.com/706f6c6c7578/minicrypt https://github.com/706f6c6c7578/hex2pem
    https://github.com/706f6c6c7578/red
    https://github.com/706f6c6c7578/sv
    https://github.com/706f6c6c7578/sve

    Regards
    Stefan

    P.S. This message is signed with my 'coffee' key. (I always sign
    my Usenet messages. :-))

    Forgot, the 'coffee' Ed25519 key pair was generated with my ve program. https://github.com/706f6c6c7578/ve

    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)