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;
}