PSET 2:Vigenere Cipher 部分工作?

Posted

技术标签:

【中文标题】PSET 2:Vigenere Cipher 部分工作?【英文标题】:PSET 2: Vigenere Cipher partially working? 【发布时间】:2019-08-03 11:12:48 【问题描述】:

我创建了以下代码作为对 CS50x PSET2: Vigenere 的回答,它在一定程度上可以工作,但是在运行 check50 时,我得到了下面列出的一些错误:

:) vigenere.c exists.
:) vigenere.c compiles.
:) encrypts "a" as "a" using "a" as keyword
:( encrypts "barfoo" as "caqgon" using "baz" as keyword - output not valid ASCII text 
:( encrypts "BaRFoo" as "CaQGon" using "BaZ" as keyword - output not valid ASCII text 
:) encrypts "BARFOO" as "CAQGON" using "BAZ" as keyword
:( encrypts "world!$?" as "xoqmd!$?" using "baz" as keyword- output not valid ASCII text 
:( encrypts "hello, world!" as "iekmo, vprke!" using "baz" as keyword- output not valid ASCII text 
:) handles lack of argv[1]
:) handles argc > 2
:( rejects "Hax0r2" as keyword - timed out while waiting for program to exit 

似乎正在发生的事情是密钥包含一个高值(即 z/Z),它会导致代码跳到下一行并错过看似随机序列的内容。例如。在字符串的第一个单词中,它漏掉了第三个字符,然后第二个单词漏掉了第三个和第四个字符,然后第三个单词漏掉了第一个字符。我只是不明白发生了什么。

我使用 printf 来确保设置和传递给函数的所有变量在运行时都是正确的。函数本身正在返回正确的响应(Hax0r2 的验证除外)。我尝试通过将结果与在线 vigenere 密码工具进行比较来进行调试。

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

int Validate1(int argc);
int Validate2(string argv);
void Cypher(string x);
void KeyCalc(string argv);

string MESSAGE;
int LENGTH;
int *KEY;
int COUNTER = 0;

int main(int argc, string argv[])

    //Check if right amount of arguments are supplied
    int Val1 = Validate1(argc);

    if (Val1 == 0)
    
        //Check if argument is a string of chars
        int Val2 = Validate2(argv[1]);

        if (Val2 == 0)
        
            //get the string length
            LENGTH = strlen(argv[1]);

            //Dynamically update KEY array length
            KEY = (int *)malloc(LENGTH * sizeof(*KEY));
            if (KEY == NULL)
            
                fprintf(stderr, "malloc failed\n");   
            

            //calculate the key
            KeyCalc(argv[1]);

            //get the message from the user to be encrypted
            MESSAGE = get_string("plaintext: ");
            printf("ciphertext: ");

            //encrypt message from user
            Cypher(argv[1]);
            free(KEY);
            return 0;
        
        else
        
            //validation failed
            printf("Usage: ./vigenere keyword\n");
            return 1;
        
    
    else
    
        //validation failed
        printf("Usage: ./vigenere keyword\n");
        return 1;
    


//Validate the number of arguments supplied
int Validate1(int argc)

    if (argc != 2)
    
        return 1;
    
    else
    
        return 0;   
    


//Validate the argument is a string
int Validate2(string argv)

    int k = 0;

    //loop through all characters in argument line string and check if alphabetic 
    for (int i = 0; i < LENGTH; i++)
     
        if isalpha(argv[i])
        
            //Do Nothing
        
        else
        
            k++; 
        
    

    //k counts the number of non-alphabetic characters, so if > 0 then invalid input
    if (k > 0)
    
        return 1;
    
    else
    
        return 0;    
    



void Cypher(string x)

    //identify the length of the message to be coded
    int Mlength = strlen(MESSAGE);

    //identify the length of the key
    int Slen = strlen(x);

    //cycle through all characters in message supplied by user
    for (int i = 0; i < Mlength; i++)
    
        // loop through key
        if (COUNTER > Slen - 1)
        
            COUNTER = 0;
        
        //check if the character is alphabetic
        if (isalpha(MESSAGE[i]))
        
            //convert the character to ASCII int value
            char l = MESSAGE[i];

            //add key value to message value and wrap around ascii mapping
            if (isupper(MESSAGE[i]))
            
                l = l + KEY[COUNTER];
                if (l > 'Z')
                
                    l = l - 26;    
                
            
            else
            
                l = l + KEY[COUNTER];
                if (l > 'z')
                
                    l = l - 26;    
                    
            

            //convert value back into character and store in array
            MESSAGE[i] = (char) l;
            // print character 
            printf("%c", MESSAGE[i]);
            COUNTER++;
        
        else
        
            //character is 'numeric' or 'symbol' or 'space' just display it
            printf("%c", MESSAGE[i]);
        
    
    printf("\n");


void KeyCalc(string argv)

    //convert key entry to values A/a = 0 to Z/z = 26
    for (int i = 0; i < LENGTH; i++)
    
        char k = argv[i];
        if (islower(argv[i]))
        
            KEY[i] = k - 'a'; 
        
        else
        
            KEY[i] = k - 'A'; 
              
        

使用“baz”作为关键字将“barfoo”加密为“caqgon” 使用“BaZ”作为关键字将“BaRFoo”加密为“CaQGon” 加密“世界!$?”作为“xoqmd!$?”使用“baz”作为关键字 加密“你好,世界!”作为“iekmo,vprke!”使用“baz”作为关键字 拒绝“Hax0r2”作为关键字

【问题讨论】:

【参考方案1】:

来自凯撒 pset 的规范:

...凯撒算法(即密码)通过以下方式加密消息 将每个字母“旋转”k 个位置。更正式地说,如果 p 是一些 明文(即未加密的消息),pi 是第 i 个字符 p, k 是一个密钥(即一个非负整数),那么每个 密文中的字母 ci 计算为

ci = (pi + k) % 26

这个算法(在任何一种情况下)都不会这样做:

 l = l + KEY[COUNTER];
                if (l > 'Z')
                
                    l = l - 26;    
                

This walkthrough 从 9:30 开始是如何实施“班次”的很好的入门读物。

此代码中问题的直接原因是此l = l + KEY[COUNTER]; 可以产生ascii range 之外的结果。在 CS50 实现中,char 默认为 signed 字符。因此,例如,'r' + 'z'(如用“baz”加密的“barfoo”)将产生 -117。

【讨论】:

感谢您指出这一点。我现在可以正常工作了。

以上是关于PSET 2:Vigenere Cipher 部分工作?的主要内容,如果未能解决你的问题,请参考以下文章

关于 CS50 pset2 vigenere

Vigenere cs50 Pset2 末尾的额外字符

我的代码有啥问题? (Vigenere cypher cs50, pset2)

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

Vigenere Cipher(Java)[重复]

CS50 - pset2 - 维吉尼