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

Topic: Scripts and Code, by Kjetil @ 03/05-2015, Article Link