commit 624a774bb131d7d66d5be5ac8535a166b5eb9733 Author: Masahiko AMANO Date: Sat Jul 20 13:13:27 2024 +0300 init diff --git a/README.md b/README.md new file mode 100644 index 0000000..4f6f3a7 --- /dev/null +++ b/README.md @@ -0,0 +1,42 @@ +# RENSA cipher + +## Contents + +- [About](#about) +- [How it works](#how-it-works) +- [Usage](#usage) + +## About + +RENSA (_jp._ 連差, _lit._ "chain variation", _omon._ 連鎖 "chain") is an encryption method I invented a couple of days ago while relaxing at sea. Actually, I'm not sure if I'm not reinventing the wheel with this method because it is pretty simple and obvious, but anyway, it really works. As for me, one of the coolest features of RENSA is that it can even be used for encrypted communications with virtually no latency. + +## How it works + +First of all, RENSA needs a key. This key maps each char to a specific value. Let's call these values _hashes_ of chars. When encrypting, each char is shifted up by the hash of the previous char; when decrypting, it is shifted down. Very simple. + +For example, if you have a message like "kagi", "a" is shifted by the hash of "k", "g" is shifted by the hash of "a" and so on. By default, the first char in the message is shifted by the hash of the _zeroth_ char which defaults to `'\0'` but can also be specified particularly. + +## Usage + +Just compile [`main.c`](main.c), [`rensa.h`](rensa.h) and [`rensa.c`](rensa.c) and you are all set. + +``` +Usage: + rensa [-e/-d] [-i ] [-o ] [-k ] [-s ] [-z ] + +Options: + -h Print help and exit + -e Encryption mode (default) + -d Decryption mode + -i Input file path (stdio by default) + -o Output file path (stdout by default) + -k Key file path + -s Key shift in bytes (0 by default) + -z Zeroth char (0 by default) +``` + +If `-k` is omitted, the default key is used. The default key simply maps each char to its value. + +--- + +_© Masahiko AMANO aka H1K0, 2024-present_ diff --git a/main.c b/main.c new file mode 100644 index 0000000..8a90af2 --- /dev/null +++ b/main.c @@ -0,0 +1,92 @@ +#include +#include +#include + +#include "rensa.h" + + +int main(int argc, char **argv) +{ + if (argc == 1) { + fprintf(stderr, "No options provided\n"); + return 1; + } + int opt; + FILE *input = stdin, *output = stdout, *key = NULL; + size_t key_shift = 0; + char zeroth_char = 0; + int encrypt_mode = 1; + char *endptr = NULL; + while ((opt = getopt(argc, argv, "hedi:o:k:s:z:")) != -1) { + switch (opt) { + case 'h': + printf( + "(c) Masahiko AMANO aka H1K0, 2024-present\n" + "(https://github.com/H1K0/rensa)\n\n" + "Usage:\n" + " rensa [-e/-d] [-i ] [-o ] [-k ] [-s ] [-z ]\n\n" + "Options:\n" + " -h Print help and exit\n" + " -e Encryption mode (default)\n" + " -d Decryption mode\n" + " -i Input file path (stdio by default)\n" + " -o Output file path (stdout by default)\n" + " -k Key file path\n" + " -s Key shift in bytes (0 by default)\n" + " -z Zeroth char (0 by default)\n" + ); + return 0; + case 'd': + encrypt_mode = 0; + break; + case 'i': + input = fopen(optarg, "rb"); + if (input == NULL) { + perror("Failed to open input file"); + return errno; + } + break; + case 'o': + output = fopen(optarg, "wb"); + if (output == NULL) { + perror("Failed to open output file"); + return errno; + } + break; + case 'k': + key = fopen(optarg, "rb"); + if (key == NULL) { + perror("Failed to open key file"); + return errno; + } + break; + case 's': + if (key == NULL) { + fprintf(stderr, "Key shift is only available if key file specified\n"); + return 1; + } + key_shift = strtoull(optarg, &endptr, 10); + if (*endptr != 0) { + fprintf(stderr, "Invalid key shift\n"); + return 1; + } + break; + case 'z': + zeroth_char = (char) strtol(optarg, &endptr, 10); + if (*endptr != 0) { + fprintf(stderr, "Invalid zeroth char\n"); + return 1; + } + break; + case '?': + return 1; + default: + break; + } + } + if (encrypt_mode) { + return rensa_fencrypt(input, output, key, key_shift, zeroth_char); + } else { + return rensa_fdecrypt(input, output, key, key_shift, zeroth_char); + } +} diff --git a/rensa.c b/rensa.c new file mode 100644 index 0000000..bf4bb90 --- /dev/null +++ b/rensa.c @@ -0,0 +1,106 @@ +#include +#include + +#include "rensa.h" + + +#define BUFSIZ 8192 + + +int rensa_encrypt(const char *plain, size_t len, const char *key, char zeroth_char, char *cipher) { + if (key == NULL) { + *(cipher++) = *(plain++) + zeroth_char; + for (int i = 1; i < len; i++, plain++, cipher++) { + *cipher = *plain + *(plain - 1); + } + } else { + *(cipher++) = *(plain++) + key[(unsigned char) zeroth_char]; + for (int i = 1; i < len; i++, plain++, cipher++) { + *cipher = *plain + key[(unsigned char) *(plain - 1)]; + } + } + return 0; +} + +int rensa_decrypt(const char *cipher, size_t len, const char *key, char zeroth_char, char *plain) { + if (key == NULL) { + *(plain++) = *(cipher++) - zeroth_char; + for (int i = 1; i < len; i++, plain++, cipher++) { + *plain = *cipher - *(plain - 1); + } + } else { + *(plain++) = *(cipher++) - key[(unsigned char) zeroth_char]; + for (int i = 1; i < len; i++, plain++, cipher++) { + *plain = *cipher - key[(unsigned char) *(plain - 1)]; + } + } + return 0; +} + +int rensa_fencrypt(FILE *input, FILE *output, FILE *key, size_t key_shift, char zeroth_char) { + if (input == NULL) { + input = stdin; + } + if (output == NULL) { + output = stdout; + } + int status; + size_t readcount; + char key_buffer[256]; + if (key != NULL) { + if (fseek(key, key_shift, SEEK_SET) != 0) { + return errno; + } + readcount = fread(key_buffer, 1, 256, key); + for (int i = readcount; i < 256; i += readcount) { + rewind(key); + readcount = fread(key_buffer + i, 1, 256 - i, key); + } + } + char rbuffer[BUFSIZ], wbuffer[BUFSIZ]; + while ((readcount = fread(rbuffer, 1, BUFSIZ, input)) != 0) { + status = rensa_encrypt(rbuffer, BUFSIZ, (key != NULL) ? key_buffer : NULL, zeroth_char, wbuffer); + if (status != 0) { + return status; + } + if (fwrite(wbuffer, 1, readcount, output) < readcount) { + return -1; + } + zeroth_char = rbuffer[BUFSIZ - 1]; + } + return 0; +} + +int rensa_fdecrypt(FILE *input, FILE *output, FILE *key, size_t key_shift, char zeroth_char) { + if (input == NULL) { + input = stdin; + } + if (output == NULL) { + output = stdout; + } + int status; + size_t readcount; + char key_buffer[256]; + if (key != NULL) { + if (fseek(key, key_shift, SEEK_SET) != 0) { + return errno; + } + readcount = fread(key_buffer, 1, 256, key); + for (int i = readcount; i < 256; i += readcount) { + rewind(key); + readcount = fread(key_buffer + i, 1, 256 - i, key); + } + } + char rbuffer[BUFSIZ], wbuffer[BUFSIZ]; + while ((readcount = fread(rbuffer, 1, BUFSIZ, input)) != 0) { + status = rensa_decrypt(rbuffer, BUFSIZ, (key != NULL) ? key_buffer : NULL, zeroth_char, wbuffer); + if (status != 0) { + return status; + } + if (fwrite(wbuffer, 1, readcount, output) < readcount) { + return -1; + } + zeroth_char = wbuffer[BUFSIZ - 1]; + } + return 0; +} diff --git a/rensa.h b/rensa.h new file mode 100644 index 0000000..91f23c4 --- /dev/null +++ b/rensa.h @@ -0,0 +1,11 @@ +#include +#include + + +int rensa_encrypt(const char *plain, size_t len, const char *key, char zeroth_char, char *cipher); + +int rensa_decrypt(const char *cipher, size_t len, const char *key, char zeroth_char, char *plain); + +int rensa_fencrypt(FILE *input, FILE *output, FILE *key, size_t key_shift, char zeroth_char); + +int rensa_fdecrypt(FILE *input, FILE *output, FILE *key, size_t key_shift, char zeroth_char);