Shift Encryption Filter
Here is a re-implementation of a couple of programs I made around 10 years ago. It's a standard in/out filter that performs simple shift encryption, of the Caesar or Vigenere variants.
It supports both text and binary mode. Text mode only operates on A to Z, while binary mode operates on the whole 8-bit range of a character byte.
Take a look at the code and compile it:
#include <stdlib.h> #include <stdio.h> #include <unistd.h> typedef enum { CIPHER_NONE, CIPHER_CAESAR, CIPHER_VIGENERE, } cipher_t; typedef enum { MODE_NONE, MODE_TEXT, MODE_BINARY, } mode_t; typedef enum { DIRECTION_NONE, DIRECTION_ENCRYPT, DIRECTION_DECRYPT, } direction_t; static inline int binary_shift(int c, int n) { c += n; if (c > 255) { c -= 256; } return c; } static inline int binary_unshift(int c, int n) { c -= n; if (c < 0) { c += 256; } return c; } static inline int text_shift(int c, int n) { if (c >= 65 && c <= 90) { c += n; if (c > 90) c -= 26; } if (c >= 97 && c <= 122) { c += n; if (c > 122) c -= 26; } return c; } static inline int text_unshift(int c, int n) { if (c >= 65 && c <= 90) { c -= n; if (c < 65) c += 26; } if (c >= 97 && c <= 122) { c -= n; if (c < 97) c += 26; } return c; } static void caesar_filter(int shift_amount, mode_t mode, direction_t direction) { int c; while ((c = fgetc(stdin)) != EOF) { if (mode == MODE_TEXT) { if (direction == DIRECTION_ENCRYPT) { c = text_shift(c, shift_amount); } else { /* DIRECTION_DECRYPT */ c = text_unshift(c, shift_amount); } } else { /* MODE_BINARY */ if (direction == DIRECTION_ENCRYPT) { c = binary_shift(c, shift_amount); } else { /* DIRECTION_DECRYPT */ c = binary_unshift(c, shift_amount); } } fputc(c, stdout); } } static void vigenere_filter(char *key, mode_t mode, direction_t direction) { int c; char *p; p = &key[0]; while ((c = fgetc(stdin)) != EOF) { if (mode == MODE_TEXT) { if (direction == DIRECTION_ENCRYPT) { c = text_shift(c, *p - 97); } else { /* DIRECTION_DECRYPT */ c = text_unshift(c, *p - 97); } } else { /* MODE_BINARY */ if (direction == DIRECTION_ENCRYPT) { c = binary_shift(c, *p - 97); } else { /* DIRECTION_DECRYPT */ c = binary_unshift(c, *p - 97); } } fputc(c, stdout); p++; if (*p == '\0') p = &key[0]; } } static void display_help(char *progname) { fprintf(stderr, "Usage: %s <options>\n", progname); fprintf(stderr, "Options:\n" " -h Display this help and exit.\n" " -c SHIFT Use Caesar cipher, with SHIFT.\n" " -v KEY Use Vigenere cipher, with KEY.\n" " -t Text mode. (Operate on 'a-z' and 'A-Z' only.)\n" " -b Binary mode. (Operate on 0-255 byte range.)\n" " -e Encrypt. (Forward shift.)\n" " -d Decrypt. (Reverse shift.)\n" "\n"); } int main(int argc, char *argv[]) { int c; mode_t mode = MODE_NONE; cipher_t cipher = CIPHER_NONE; direction_t direction = DIRECTION_NONE; char *vigenere_key = NULL; int caesar_shift = 0; while ((c = getopt(argc, argv, "hc:v:tbed")) != -1) { switch (c) { case 'h': display_help(argv[0]); return EXIT_SUCCESS; case 'c': cipher = CIPHER_CAESAR; caesar_shift = atoi(optarg); break; case 'v': cipher = CIPHER_VIGENERE; vigenere_key = optarg; break; case 't': mode = MODE_TEXT; break; case 'b': mode = MODE_BINARY; break; case 'e': direction = DIRECTION_ENCRYPT; break; case 'd': direction = DIRECTION_DECRYPT; break; case '?': default: display_help(argv[0]); return EXIT_FAILURE; } } if (mode == MODE_NONE) { fprintf(stderr, "Error: Specify text or binary mode.\n"); display_help(argv[0]); return EXIT_FAILURE; } if (direction == DIRECTION_NONE) { fprintf(stderr, "Error: Specify encryption or decryption.\n"); display_help(argv[0]); return EXIT_FAILURE; } switch (cipher) { case CIPHER_CAESAR: caesar_filter(caesar_shift, mode, direction); break; case CIPHER_VIGENERE: vigenere_filter(vigenere_key, mode, direction); break; default: fprintf(stderr, "Error: Specify a cipher to use.\n"); display_help(argv[0]); return EXIT_FAILURE; } return EXIT_SUCCESS; }