简体   繁体   中英

Vigenere Square Decryption in C

I'm trying to encrypt and decrypt a message using a passphrase and a vigenere square stored in an array. I am able to encrypt the message successfully however I can't work out how to decrypt it again afterwards. Any ideas?

#include <stdio.h>
#include <string.h>
#include <ctype.h>

void encrypt(char *text, char *pass, int n, int m, char *vs);
void decrypt(char *text, char *pass, int n, int m, char *vs);
void vigsq(char *vs);

main()
{
     char text[] = "HELLOWORLD";
     char pass[] = "MAGIC";
     int n, m;
     char vs[26*26];
     char *vsPointer, *textPointer, *passPointer;
     char command;
     char inputfile[10];
     char outputfile[10];
     //printf("Please enter e/d, pass phrase, input file, output file:");
     //scanf("%c, %s, %s, %s", &command, &pass, &inputfile, &outputfile);
     vsPointer = vs;
     textPointer = text;
     passPointer = pass;
     vigsq(vsPointer);
     //printf("%c, %s, %s, %s\n", command, pass, inputfile, outputfile);

    n = strlen(text);
    m = strlen(pass);
    //printf("%d, %d", n, m);
    encrypt(textPointer, passPointer, n, m, vsPointer);
    printf("%s\n", text);
    decrypt(textPointer, passPointer, n, m, vsPointer);
    printf("%s\n", text);   
}

void encrypt(char *text, char *pass, int n, int m, char *vs)
{
    int i;
    int ascii1;
    int ascii2;
    int passcount = 0;
    char encrypt;
    for (i = 0; i < n; i++)
    {
        ascii1 = (int)text[i];
        ascii2 = (int)pass[passcount];
        ascii1 = ascii1 - 64;
        ascii2 = ascii2 - 64;
        encrypt = vs[((ascii1 -1)*26) + (ascii2)];
        // printf("%d, %d, %c\n", ascii1, ascii2, encrypt);
        text[i] = encrypt;
        passcount++;
        if (passcount == m)
        {
            passcount = 0;
        }
    }   
}

void decrypt(char *text, char *pass, int n, int m, char *vs)
{
    int i;
    int ascii1;
    int ascii2;
    int passcount = 0;
    char decrypt;
    for (i = 0; i < n; i++)
    {
        ascii1 = (int)text[i];
        ascii2 = (int)pass[passcount];
        ascii1 = ascii1 - 64;
        ascii2 = ascii2 - 64;
        decrypt = vs[//Don't know what to put here];
        //printf("%d, %d, %c\n", ascii1, ascii2, decrypt);
        text[i] = decrypt;
        passcount++;
        if (passcount == m)
        {
            passcount = 0;
        }
    }       
}

void vigsq(char *vs)
{
    char alphabet[] = {'A','B','C','D','E','F','G','H','I','J','K',
        'L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'};

    int a = 0, i, j, count = 0;
    for(i = 1; i <= 26*26; i++)
    {                           
        vs[i] = alphabet[a];
        a++;
        if (i % 26 == 0)
        {
            count++;
            a = count;
        }   
        if (a == 26)        
        {
            a = 0;
        }               
    }
}

(Please ignore the I/O stuff I'll be implementing that later.) Thanks for the help :)

When you encode a letter, you look up letter at the the row of the password letter m[j] and the columns of the plaintext letter p[i] in the Vigenère table. When you decode, you must find the column where encrypted letter c[i] is in the row of the password letter. In code, encrypting is a simple table lookup, but decrypting is not.

You don't really need the table, though. You can describe the Vigenère cipher algorithmically. The cipher really is just a Ceasar cipher – a simple letter shift &ndash, where the shift amount is determined by the current letter in the password. Encrypting means shifting forwards, decrypting means shifting backwards:

c[i] = (p[i] + m[j]) % 26
p[i] = (c[i] - m[j]) & 26

In this formula, the letters are represented by the numbers 0 (A) to 25 (Z). Remember that indices start at zero in C. That also means that you have to subtract 'A' (65) from your letters, not 64.

Because decryption and encryption are so similar, you can implement them in a single function with a flag for the mode of operation:

enum {
    Encrypt, 
    Decrypt
};                    

void vigenere(char *text, const char *pass, int mode)
{
    int i;
    int passcount = 0;

    for (i = 0; text[i] != '\0'; i++)
    {
        int ascii1 = text[i] - 'A';
        int ascii2 = pass[passcount] - 'A';

        // Negate shift for decryption
        if (mode == Decrypt) ascii2 = -ascii2;

        text[i] = 'A' + (26 + ascii1 + ascii2) % 26;

        passcount++;
        if (pass[passcount] == '\0') passcount = 0;
    }
}

Things to note:

  • The addition of 26 in the formula is to prevent taking the remainder of a negative number, which will yield a negative number in C.
  • The code works only if all characters are upper-case letters.
  • The explicit string lengths have been omitted; you can test whether you have reached the end of a C string by checking whather the current character is the terminating null, '\\0' .

Call this code like so:

int main()
{
    char text[] = "HELLOWORLD";
    const char *pass = "MAGIC";

    printf("plain %s\n", text);    

    vigenere(text, pass, Encrypt);
    printf("crypt %s\n", text);

    vigenere(text, pass, Decrypt);
    printf("decpt %s\n", text); 

    return 0;  
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM