Mr Chasi
Mr Chasi

Reputation: 437

Vigenere Cipher - Inexplicable Nuance

I am implementing a Vigenere cipher in C. My solution kept enciphering the plain-text incorrectly. I thus decided to make a (somewhat arbitrary) change to my code. The aim of the alteration was simply to make the code more readable, by positioning my variables better, and giving them more appropriate names. However, This change has now caused the solution to encipher properly; I can't explain why the current solution works over the original one. Could someone perhaps enlighten me?

original.c

//...code to validate user input

string k = argv[1]; //'argv' being a main method parameter
string str = GetString();

//Encrypt using vigenere
for (int i = 0, n = strlen(str); i < n; i++) {

    /*An int to keep track of which char to use from the keyword.
    Only increment if str[i] was alphabetic.*/
    int k_index = 0;
    int k_len = strlen(k);
    char letter_key = tolower(k[k_index % k_len]);

    //Checking if str[i] is alphabetic
    if (isalpha(str[i])) {

        //Checking if str[i] is uppercase
        if (isupper(str[i])) {

            //enciphering using vigenere formula
            str[i] = ((str[i] - 'A') + (letter_key - 'a')) % 26 + 'A';
            printf("%c", str[i]);
            k_index++;
        }

        //If not uppercase, it must be lowercase
        else {
            //enciphering using vigenere formula
            str[i] = ((str[i] - 'a') + (letter_key - 'a')) % 26 + 'a';
            printf("%c", str[i]);
            k_index++;
        }

    } else {
        printf("%c", str[i]);
    }
}

Output

Key: "chasi"
Input/Result: "my plaintext" ---> "oa rnckpvgzv" 
Should be: "of pdikutwfv"

updated.c

//...code to validate user input

string k = argv[1];
string str = GetString();

//Encrypt using vigenere
for (int i = 0, j = 0, n = strlen(str); i < n; i++) {

    /*"int j" is to keep track of which char to use from the keyword.
    Only increment if str[i] was alphabetic.*/

    int k_len = strlen(k);
    char letter_key = tolower(k[j % k_len]) - 'a';

    //Checking if str[i] is alphabetic
    if (isalpha(str[i])) {

        //Checking if str[i] is uppercase
        if (isupper(str[i])) {

            //enciphering using vigenere formula
            str[i] = ((str[i] - 'A') + letter_key) % 26 + 'A';
            printf("%c", str[i]);
            j++;
        }

        //If not uppercase, it must be lowercase
        else {
            //enciphering using vigenere formula
            str[i] = ((str[i] - 'a') + letter_key) % 26 + 'a';
            printf("%c", str[i]);
            j++;
        }

    } else {
        printf("%c", str[i]);
    }
}

Output:

Key: "chasi"
Input/Result: "my plaintext" ---> "of pdikutwfv" (correct)

Upvotes: 0

Views: 72

Answers (1)

Barmar
Barmar

Reputation: 782466

The original code does:

int k_index = 0;

each time through the loop. Then when it does:

char letter_key = tolower(k[k_index % k_len]);

it's using this 0 value, so letter_key is always tolower(k[0]). The places where it does k_index++; have no effect, because the variable gets zeroed before it gets used again. So you're just using the first character of the key as the whole key.

In the updated code, the variable j takes the place of k_index. It gets initialized to 0 when the loop starts, not each time through the loop. So when you do:

char letter_key = tolower(k[j % k_len]) - 'a';

you're using the updated value of j. This properly uses the whole key.

Upvotes: 3

Related Questions