维吉尼亚密码

在古典密码学中,有一种密码叫维吉尼亚密码,为了生成密码,需要使用表格法。这一表格(如图1所示)包括了26行字母表(大写),每一行都由前一行向左偏移一位得到。具体使用哪一行字母表进行编译是基于密钥进行的,在过程中会不断地变换。例如,假设明文为:ATTACKATDAWN选择某一关键词并重复而得到密钥,如关键词为LEMON时,密钥为:LEMONLEMONLE对于明文的第一个字母A,对应密钥的第一个字母L,于是使用表格中L行字母表进行加密,得到密文第一个字母L。类似地,明文第二个字母为T,在表格中使用对应的E行进行加密,得到密文第二个字母X。以此类推,可以得到:

明文:ATTACKATDAWN

密钥:LEMONLEMONLE

密文:LXFOPVEFRNHR

解密的过程则与加密相反。例如:根据密钥第一个字母L所对应的L行字母表,发现密文第一个字母L位于A列,因而明文第一个字母为A。密钥第二个字母E对应E行字母表,而密文第二个字母X位于此行T列,因而明文第二个字母为T。以此类推便可得到明文。请按照如上的解释设计一段程序,要求如下:

1)定义二维数组用于存储维吉尼亚密码表;

2)利用scanf函数或gets函数输入密钥和明文(密文),并使用合适的数据结构对输入数据进行存储(本次实验规定密钥为实验者本人姓名全拼,如LISHEN,明文为GOODGOODSTUDY);

3)根据密钥对明文进行加密或对密文进行解密。选择使用数组方式或指针方式编写加密函数及解密函数。

以下是代码

#include <stdio.h>
#include <stdlib.h>
#define MINCHAR 65
#define CHARSUM 26
#define DIFFER  32

//----利用指针实现----------
int encode(char* key, char* source, char* dest);
int decode(char* key, char* source, char* dest);

//----利用数组实现----------
int encode1(char key[], char source[], char dest[]);
int decode1(char key[], char source[], char dest[]);

char table[CHARSUM][CHARSUM];

int main()
{
    int i, j;
    char key[256];
    char source[256];
    char destination[256];
    int operation;
    //构造维吉尼亚密码表 CHARSUM是字母个数26,
    //MINCHAR对应字母A,值是65
    for(i = 0; i < CHARSUM; i++)
        for(j = 0; j < CHARSUM; j++)
            table[i][j] = MINCHAR + (i + j) % CHARSUM;
    printf("please choose one operation code:\n");
    printf("1. Encode; 2. Decode; Others. Exit.\n");
    scanf("%d", &operation);

    switch (operation)
    {
    case 1:
        printf("please input the key code:\n");
        scanf("%s", key);//密钥,将输入的字符存入数组
        getchar();
        printf("please input the source code you want to encode:\n");
        gets(source);//允许输入空格及数字等其他字符,非字母符号不对其进行加密,源码显示

        encode(key, source, destination);
        printf("after encode is: \n");
        printf("%s\n", destination);
        encode1(key, source, destination);
        printf("after encode1 is: \n");
        printf("%s\n", destination);
    break;
    case 2:
        printf("please input the key code:\n");
        scanf("%s", key);
        printf("please input the source code you want to decode:\n");
        scanf("%s", source);
        decode(key, source, destination);
        printf("after decode is: \n");
        printf("%s\n", destination);
        decode1(key, source, destination);
        printf("after decode1 is: \n");
        printf("%s\n", destination);
    break;
    default:
        return 0;
    }
    return 0;
}

int encode(char* pkey, char* psource, char* pdest)
{//只对大写字母加密
    char* ptempkey = pkey;
    do
    {
        if(*psource>=65&&*psource<=90)//是大写字母
            *pdest = table[(*ptempkey) - MINCHAR][(*psource) - MINCHAR];
        else
           *pdest = *psource;
        pdest++;
        if (!(*(++ptempkey)))//密钥完成一轮,重新从第一个字符开始
            ptempkey = pkey;
    } while(*psource++);
    *pdest = '\0';
    return 1;
}

/*------encode1函数功能说明-------
-----允许接收明文为任意字符组合字符串----
----密钥要求是大写字母----
----字母按照密码表加密,小写密文为小写字母---
----非字母类字符不对其进行加密处理----
--*/
int encode1(char key[], char source[], char dest[])
{
    int i,j;
    for(i=0,j=0;source[i]!='\0';i++,j++)
    {
        if(key[j]=='\0')
            j=0;//密钥循环使用,到最后一个字母再从头开始

        //---加密实际就是查表,行标就是密钥和A(0行0列)的偏移
        //列就是明文和A的偏移
        //因为维吉尼亚密码表是对称的,所以行当明文,列当密钥或者行是密钥,列是明文都可以
        //--判断是否为字母---
        if(source[i]>=65&&source[i]<=90)
        {//说明是大写字母
            dest[i] = table[source[i]-MINCHAR][key[j]-MINCHAR];
        }
        else if(source[i]>=97 &&source[i]<=122)
        {//小写字母
             dest[i] = table[source[i]-MINCHAR-DIFFER][key[j]-MINCHAR] + DIFFER;
        }
        else
        {//原样输出
            dest[i]=source[i];
        }

    }
    //加密结束,记得密文是字符串,要加'\0'
    dest[i]='\0';
    return 1;
}

int decode(char* pkey, char* psource, char* pdest)
{//解密就是密文和密钥的差
    char* tempKey = pkey;
    int offset;
    do
    {
        offset = (*psource) - (*tempKey);
        offset = offset >= 0 ? offset : (offset + CHARSUM);
        *pdest = MINCHAR + offset;
        pdest++;
        if (!(*(++tempKey)))
        tempKey = pkey;
    } while(*++psource);
     *pdest= '\0';
    return 1;
}

int decode1(char key[], char source[], char dest[])
{
    int i,j,offset;
    for(i=0,j=0;source[i]!='\0';i++,j++)
    {
        if(key[j]=='\0')//密钥长度小于密文,循环使用
            j=0;
        //解密操作,实际就是找密文和密钥之间的偏移量
        offset = source[i]-key[j];
        if(offset<0)
            offset = offset + CHARSUM;

        dest[i] = MINCHAR + offset;
    }
    dest[i]='\0';
}
 

运行结果如图

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值