I implemented a Vigenere cipher that preserves case and can also decrypt if you pass the -d
argument. Usage is ./vigenere <plaintext|ciphertext> key [-d]
and it works fine but I think there are probably some things I could do better. So, just looking for critique.
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#define ENCRYPT 1
#define DECRYPT -1
int mod(int x, int n)
{
return (x % n + n) % n;
}
char *vigenere(char *input, char *keystream, int mode)
{
if (strlen(keystream) != strlen(input))
return NULL;
int output_len = strlen(input), offset = 'a', wasupper = 0;
char *output = malloc(output_len);
for (int i = 0; i < output_len; ++i)
{
if (isupper(input[i]))
{
input[i] = tolower(input[i]);
wasupper = 1;
}
else
wasupper = 0;
output[i] = mod((input[i] - offset) + (keystream[i] - offset) * mode, 26) + offset;
if (wasupper)
output[i] = toupper(output[i]);
}
return output;
}
char *gen_keystream(char *key, int keystream_len)
{
int key_len = strlen(key), j = 0;
char *keystream = malloc(keystream_len);
for (int i = 0; i < keystream_len; j = ++i % key_len)
keystream[i] = key[j];
return keystream;
}
int main(int argc, char **argv)
{
if (argc < 3)
return EXIT_FAILURE;
int mode = ENCRYPT;
if (argc > 3 && strcmp(argv[3], "-d") == 0)
mode = DECRYPT;
int keystream_len = strlen(argv[1]);
char *keystream = gen_keystream(argv[2], keystream_len);
char *result = vigenere(argv[1], keystream, mode);
printf("%s\n", result);
free(keystream);
free(result);
return EXIT_SUCCESS;
}