如何在vigenere cipherkey cs50 pset2中重用(循环)密钥

时间:2017-08-13 17:54:42

标签: c cs50 vigenere

我正在为Vigenere密码制作程序。我让程序成功打印了密文。但是,我无法循环关键。所以,如果我的密钥是'abc'并且我的纯文本是你好的,它应该打印'hfnlp'而不是'hfn'。

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

int main(int argc, string argv[])
{
    if(argc != 2)
    {
        printf("\aError\n");
        return 1;
    }
    else
    {
        string a = argv[1]; // converts argv[1]

        printf("plaintext: ");
        string b = get_string(); // takes the plaintext

        printf("ciphertext: ");

        for(int c = 0, d = strlen(a); c < d; c++)
        {
            for(int e = 0, f = strlen(b); e < f; e++)
            {
                if(islower(a[c]))
                    {
                        printf("%c\n",  b[e] + ( (a[c] - 97) % 26) ); // works for lowercase letters
                        return 0;
                    }
                    else if(isupper(a[i]))
                    {
                        printf("%c\n",  b[e] + ( (a[c] - 65) % 26) ); // works for uppercase letter
                    }
                    else
                    {
                         printf("%c", b[e]); // works for non alphabetical inputs
                    }

                    if(true)
                        break;
            }
   }

    printf("\n");
}
}

2 个答案:

答案 0 :(得分:1)

您选择的单字母变量名称是奇数;这使得使用代码变得更加困难。我也不是长名的粉丝,而是中间长度的变量名(2-8个字符 - 除了一些风格化的单字母名称(cij,{ {1}},kp) - 通常是合适的。)

你遇到了麻烦,因为如果你的密钥是6个字符而你的字符串是24个字母字符,你会因为循环结构而尝试输出144个字母字符。您只需要一个循环遍历纯文本中的字符。你有一个单独的变量循环键的长度,当它用完时重置回到开始。在此代码中,密钥长度为s(您使用keylen),密钥的偏移量(索引)位于d(您使用keyoff) - 但密钥仍然在c,因为这是您使用的。留给我自己的设备,我可能会使用a(或者text)代替plainb代替textlen,而我对循环变量使用f而不是i。如果我想使用短索引,我可能会使用e而不是k。我也可以在原地编辑字符串并在最后打印整个字符串。

此代码还确保密钥中的字母字符为小写。它不能确保密钥全部为alpha;它可以说应该而且这样做是微不足道的,因为无论如何都要扫描钥匙。就目前而言,这是一个GIGO的情况 - 垃圾进入,垃​​圾出来。

代码通过减去keyoffa-z将输入字母(A-Za)转换为“字母表中的偏移量”,将关键字转换为偏移到字母表中,添加两个偏移模26(字母表中的字母数),并将偏移量转换回适当大小写的字母。

A

当编译到程序#include <stdio.h> #include <cs50.h> #include <string.h> #include <ctype.h> int main(int argc, string argv[]) { if (argc != 2 || strlen(argv[1]) == 0) { fprintf(stderr, "Usage: %s key < text\n", argv[0]); return 1; } string a = argv[1]; int keylen = strlen(a); for (int i = 0; i < keylen; i++) a[i] = tolower((unsigned char)a[i]); printf("key: %s\n", a); printf("plaintext: "); string b = get_string(); printf("ciphertext: "); int keyoff = 0; // Step through each character of the plain text. Encrypt each // alpha character with the (lower-case) key letter at a[keyoff], // incrementing keyoff. Don't increment key offset when processing // non-alpha data. for (int e = 0, f = strlen(b); e < f; e++) { if (islower(b[e])) printf("%c", ((b[e] - 'a') + (a[keyoff++] - 'a')) % 26 + 'a'); else if (isupper(b[e])) printf("%c", ((b[e] - 'A') + (a[keyoff++] - 'a')) % 26 + 'A'); else printf("%c", b[e]); if (keyoff >= keylen) keyoff = 0; } printf("\n"); return 0; } 并运行时,它会生成,例如:

vc41

我生成了一个8个字母的随机密钥(它是$ vc41 abcdef key: abcdef plaintext: The quick brown Fox jumped over the lazy Dog. ciphertext: Tig tyncl dusbn Gqa nzmqgg saes vki qaaa Gsl. $ )并在一些“完整字母”字符串上运行代码:

GZlfmTMk

(我会注意到在使用GCC 7.1.0运行macOS Sierra 10.12.6的Mac上,此代码链接不包括(新)CS50库 - 有一个系统函数$ vc41 GZlfmTMk key: gzlfmtmk plaintext: Pack my box with five dozen liquor jugs. ciphertext: Vznp yr nyd vtyt yufk czeqg xswtzw vnsc. $ vc41 GZlfmTMk key: gzlfmtmk plaintext: The five boxing wizards jump quickly. ciphertext: Zgp kuoq luwtss pujgqox vnyz wtthwek. $ vc41 GZlfmTMk key: gzlfmtmk plaintext: How vexingly quick daft zebras jump. ciphertext: Nnh aqquxmkj vgbou jzqy lxnbgr uzyi. $ vc41 GZlfmTMk key: gzlfmtmk plaintext: Bright vixens jump; dozy fowl quack. ciphertext: Hqtltm hsddyx vnyz; jnkd rhiv wtlhw. $ vc41 GZlfmTMk key: gzlfmtmk plaintext: The quick brown fox jumps over the lazy dog. ciphertext: Zgp vgbou hqzbz yah ptxue hhox ssj xtli jnr. $ 一个与CS50版本不同的接口,它满足了引用但崩溃了程序。但是,get_string()没有记录它,所以我不确定该名称的系统功能实际上是什么;我没有更积极地追逐它,或者发现问题有多广泛。这让我很头疼,旧的CS50库没有。抱怨......)

答案 1 :(得分:0)

像这样修复

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

int main(int argc, string argv[]){
    if(argc != 2 || !*argv[1]){
        printf("\aError:The number of command arguments is incorrect.\n");
        printf("Usage: %s key_string\n", argv[0]);
        return 1;
    }
    //Since it is `return 1;` in the if-statement, 
    //the else clause is unnecessary (unnecessarily deepening the nest)
    string key = argv[1];//It does not convert.
    size_t i, key_len;
    unsigned char curr_char;
    for(i = 0; (curr_char = key[i]) != '\0'; ++i){
        if(!isalpha(curr_char)){
            printf("\aError:Only the alphabet can be specified as the key.\n");
            return 1;
        }
        key[i] -= islower(curr_char) ? 'a' : 'A';//Convert to Deviation
    }
    key_len = i;
    i = 0;

    printf("plaintext : ");
    string plain = get_string();

    printf("ciphertext: ");

    for(size_t j = 0; (curr_char = plain[j]) != '\0'; ++j){//Scan of plain text should be the main loop.
        if(isalpha(curr_char)){
            char base_char = islower(curr_char) ? 'a' : 'A';//Avoid using magic numbers

            putchar(base_char + (curr_char - base_char + key[i]) % 26);//Make the same process one
            if(++i == key_len)
                i = 0;//reset key index
        } else {
            putchar(curr_char);//non alphabetical inputs
        }
    }
    printf("\n");
    free(plain);
}