如何使用C语言实现Vigenère密码加解密

如何使用C语言实现Vigenère密码加解密

在洛谷看到这题,觉得有意思,遂写。

参考文章:C语言实现Vigenere加解密算法(附带源码)

1. Vigenère密码简介与原理

Vigenère密码是一种多表密码,使用一系列凯撒密码(Caesar cipher)来实现加密。在Vigenère密码中,明文中的每个字符都被替换为密文中的对应字符,而密钥用于确定使用哪个凯撒密码表。具体来说,明文中的每个字符都会根据密钥中的字符进行位移,从而生成密文。如图:img
加密例子:明文:HELLO,密钥:KEY,加密后:RIJVS

对照表中,先将密钥填充至与明文长度相同:KEYKE。然后在对照表中找到明文字符对应的密文字符,如第一个字符在对照表中的K行找到H列,对应的字符是R,于是第一个字符就被加密成R。以此类推,直到明文全部加密完成。

实际操作中,其实就是一系列的不同的凯撒密码加密,而密钥决定了使用哪个凯撒密码表,这里不赘述。我们把字母转换成数字(A = 0,B = 1,……),写成公式可以表达成:

加密:C = (P + K)% 26

其中C为密文字符数,P为明文字符数,K为密钥字符。同样可以得到解密公式:

解密:P = (C - K + 26)% 26

2.具体实现

这里仅给出函数实现,以及省略了引入string.h和ctype.h头文件。

我们可以考虑先忽略字母的大小写,解密后再对照原文判断是否转换大小写。先实现字母转数字、数字转字母的函数:

int Char_to_Number(char c)
{
    return c - 'A';
}

char Number_to_Char(int num, char origin)
{
    char c = 'A' + num;
    //* 对照原文
    if (islower(origin))
    {
        return tolower(c);
    }
    return c;
}

解码:

char *Decode(char *key, char *C, char *M)
{
    for (int i = 0, j = 0; i < strlen(C); i++)
    {
        if (isalpha(C[i]))
        {
            int keyNum = Char_to_Number(key[j % strlen(key)]); // 填充密钥
            int CNum = Char_to_Number(C[i]);
            int MNum = (CNum - keyNum + 26) % 26;
            M[i] = Number_to_Char(MNum, C[i]);
            // 不能在循环体里面写j++😡,否则遇到非字母字符j也会增加
            j++; 
        }
        else
        {
            M[i] = C[i];
        }
    }
    return M;
}

加密:

char *Encode(char *key, char *M, char *C)
{
    for (int i = 0, j = 0; i < strlen(M); i++)
    {
        if (isalpha(M[i]))
        {
            int keyNum = Char_to_Number(key[j % strlen(key)]);
            int MNum = Char_to_Number(M[i]);
            int CNum = (MNum + keyNum) % 26;
            C[i] = Number_to_Char(CNum, M[i]);
            j++;
        }
        else
        {
            C[i] = M[i];
        }
    }
}

完整测试用例代码:

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

int Char_to_Number(char c);
char Number_to_Char(int num, char origin);
char *Decode(char *key, char *C, char *M);
char *Encode(char *key, char *M, char *C);

int main()
{
    char key[101];
    char C[1001];
    char M[1001];

    fgets(key, sizeof(key), stdin);
    fgets(C, sizeof(C), stdin);
    key[strcspn(key, "\n")] = '\0';
    C[strcspn(C, "\n")] = '\0';
    Decode(key, C, M);

    printf("%s\n", M);
    // Encode(key, M, C);
    // printf("%s\n", C);

    return 0;
}

int Char_to_Number(char c)
{
    return toupper(c) - 'A';
}

char Number_to_Char(int num, char origin)
{
    char c = 'A' + num;
    //* 对照原文
    if (islower(origin))
    {
        return tolower(c);
    }
    return c;
}

char *Decode(char *key, char *C, char *M)
{
    for (int i = 0, j = 0; i < strlen(C); i++)
    {
        if (isalpha(C[i]))
        {
            int keyNum = Char_to_Number(key[j % strlen(key)]); // 填充密钥
            int CNum = Char_to_Number(C[i]);
            int MNum = (CNum - keyNum + 26) % 26;
            M[i] = Number_to_Char(MNum, C[i]);
            j++; // 不能在循环体里面写j++😡,否则遇到非字母字符j也会增加
        }
        else
        {
            M[i] = C[i];
        }
    }
    return M;
}

char *Encode(char *key, char *M, char *C)
{
    for (int i = 0, j = 0; i < strlen(M); i++)
    {
        if (isalpha(M[i]))
        {
            int keyNum = Char_to_Number(key[j % strlen(key)]);
            int MNum = Char_to_Number(M[i]);
            int CNum = (MNum + keyNum) % 26;
            C[i] = Number_to_Char(CNum, M[i]);
            j++;
        }
        else
        {
            C[i] = M[i];
        }
    }
}

3. 总结

知道了加解密公式,实现起来就很简单,以及注意需要对照原文判断转换字母的大小写。

介绍和图片来源于网络,侵删。

posted @ 2025-09-23 12:29  Franksama  阅读(60)  评论(0)    收藏  举报