PlayFair密码原理、代码

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

1、引入PlayFair密码的原因

1、因为单表代替的密钥量很小不能抵抗穷尽搜索攻击

2、单表代替密码没有将明文字母出现的概率隐藏起来。很容易收到频率分析的攻击

综上所述我们会引入PlayFair密码加密

2、PlayFair密码的原理以及完成加密解密的步骤

1、编制密码表

  1. 基于一个5×5的字母矩阵
  2. 该矩阵使用一个密钥关键词来构造
  3. 从左到右、从上到下依次填入密钥的字母PS密钥中重复的字母不填然后再以字母表顺序依次填入其他字母。
  4. 字母 I 和 J 算作一个字母 PS25的矩阵只能存储25个字母
  5. 示例全片以此例举例
    密钥是PLAYFAIR IS A DIGRAM CIPHER

第一步填入不重复的密钥如果有重复则跳过在这里插入图片描述
第二部将剩未出现的字母依次写入
在这里插入图片描述

2、加密方法本质按照特定方法替换

1、将明文两两分组
case1明文个数为偶数个

根据以上例子可以得到
P=PL——AY——FA——IR——CI——PH——ER

case2明文个数为奇数个

解决办法缺补在最后一个明文字母的后面补上其下一位字母

示例
AB——C补完变为AB——CD

case3明文分组后同一组字母相同

解决办法同插在相同的字母中间插入其下一位字母

示例
AA——BC 插完变为 AB——AB——CD这里执行了一次缺补

PS同插缺补操作不分先后执行结果相同

2、移位和替换

规则

  • 若p1 p2在同一行对应密文c1 c2分别是紧靠p1 p2 右端的字母。其中第一列被看做是最后一列的右方。
  • 若p1 p2在同一列对应密文c1 c2分别是紧靠p1 p2 下方的字母。其中第一行被看做是最后一行的下方。
  • 若p1 p2不在同一行不在同一列则c1 c2是由p1 p2确定的矩形的其他两角的字母
  • 示例 P=PL——AY——FA——IR——CI——PH——ER

首先看前四个
前四个都符合规则的第一条
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

得到前四组的密文C
C=LA——YF——PY——RS

再看剩余几组满足变换规则第三条本质构建子矩阵并找到反对角
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

PS一定要注意字母对应的顺序明文对应同行的才是密文

所以得到C=LA——YF——PY——RS——MR——AM——CD

3、解密方法

三条规则逆推即可不再做详细赘述

3、代码


#include<iostream>
#include<cstring>

using namespace std;
void encrypt()
{
    const int N = 100;
    char letters[26] = "ABCDEFGHIKLMNOPQRSTUVWXYZ";//用于填充矩阵
    int flag[25] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };//字母是否已在矩阵中与letters数组对应
    char ch[5][5];//5X5矩阵
    char ch1[N];//密钥
    char ch2[N];//明文
    char ch4;//无关字符
    int len = 'a' - 'A';
    cout << "输入密钥";
    cin >> ch1;
    int flg = 1;
    while (flg == 1)
    {
        for (int i = 0; i < strlen(ch1); i++)//把所输入的密钥转化为大写字母
        {
            if (ch1[i] > 'z' || ch1[i] < 'a')
            {
                cout << "请重新选择操作" << endl;
                flg = 0; break;
            }
            else
                ch1[i] = ch1[i] - len;
        }
        if (flg == 1)
        {
            for (int i = 0; i < strlen(ch1); i++)//把密钥中的J都变为I
            {
                if (ch1[i] == 'J')ch1[i] = 'I';
            }
            int i = 0; int j = 0;
            //把密钥中的字母填入到矩阵中并把该字母标记为已用
            for (int k = 0; k < strlen(ch1); k++)
            {
                for (int t = 0; t < 25; t++)
                {
                    if (ch1[k] == letters[t] && flag[t] == 0)
                    {
                        ch[i][j] = letters[t];
                        flag[t] = 1;
                        if (j < 4)j++;
                        else { i++; j = 0; }
                    }
                }
            }
            for (int k = 0; k < 25; k++)//按字母表顺序把未用字母依次填入到矩阵中
            {
                if (flag[k] == 0)
                {
                    ch[i][j] = letters[k];
                    flag[k] = 1;
                    if (j < 4)j++;
                    else { i++; j = 0; }
                }
            }
            cout << "密钥填充后的矩阵为 " << endl;
            for (i = 0; i < 5; i++)
                for (j = 0; j < 5; j++)
                {
                    cout << ch[i][j];
                    cout << " ";
                    if (j == 4)
                        cout << endl;
                }
            cout << endl;
            cout << "请输入明文请输入英文字符";
            cin >> ch2;
            cout << "输入一个无关字符";
            cin >> ch4;
            if (ch4 >= 'a')
                ch4 = ch4 - len;
            for (int k = 0; k < strlen(ch2); k++)//把所输入的明文转化为大写字母
            {
                if (ch2[k] >= 'a')
                    ch2[k] = ch2[k] - len;
            }
            for (int k = 0; k < strlen(ch2); k++)//把明文中的J都变为I
            {
                if (ch2[k] == 'J')
                    ch2[k] = 'I';
            }
            //为明文添加必要的无关字符以防止同一组的两个字符相同
            for (int k = 0; k < strlen(ch2); k += 2)
            {
                if (ch2[k] == ch2[k + 1])
                {
                    for (int t = strlen(ch2); t > k; t--)
                        ch2[t + 1] = ch2[t];
                    ch2[k + 1] = ch4;
                }
            }
            //若明文有奇数个字符则添加一个无关字符以凑够偶数个
            if (strlen(ch2) % 2 != 0)
            {
                ch2[strlen(ch2) + 1] = ch2[strlen(ch2)];//字符串结尾赋'\0'
                ch2[strlen(ch2)] = ch4;//明文串尾插入无关字符
            }
            cout << "经过处理后的明文为";
            for (int k = 0; k < strlen(ch2); k += 2)
                cout << ch2[k] << ch2[k + 1] << " ";
            cout << endl;
            cout << "其最终长度为" << strlen(ch2) << endl;
            //明文输入并整理完毕///
            for (int k = 0; k < strlen(ch2); k += 2)
            {
                int m1, m2, n1, n2;
                for (m1 = 0; m1 <= 4; m1++)
                {
                    for (n1 = 0; n1 <= 4; n1++)
                    {
                        if (ch2[k] == ch[m1][n1])break;
                    }
                    if (ch2[k] == ch[m1][n1])break;
                }
                for (m2 = 0; m2 <= 4; m2++)
                {
                    for (n2 = 0; n2 <= 4; n2++)
                    {
                        if (ch2[k + 1] == ch[m2][n2])break;
                    }
                    if (ch2[k + 1] == ch[m2][n2])break;
                }
                m1 = m1 % 5;
                m2 = m2 % 5;
                if (n1 > 4) { n1 = n1 % 5; m1 = m1 + 1; }
                if (n2 > 4) { n2 = n2 % 5; m2 = m2 + 1; }
                if (m1 == m2)
                {
                    ch2[k] = ch[m1][(n1 + 1) % 5];
                    ch2[k + 1] = ch[m2][(n2 + 1) % 5];
                }
                else
                {
                    if (n1 == n2)
                    {
                        ch2[k] = ch[(m1 + 1) % 5][n1];
                        ch2[k + 1] = ch[(m2 + 1) % 5][n2];
                    }
                    else
                    {
                        ch2[k] = ch[m1][n2];
                        ch2[k + 1] = ch[m2][n1];
                    }
                }
            }
            cout << "加密后所得到的密文是";
            for (int k = 0; k < strlen(ch2); k += 2)
                cout << ch2[k] << ch2[k + 1] << " ";
            cout << endl;
        }
        else break;
    }

}

//解密算法
void decrypt()
{
    const int N = 100;
    char letters[26] = "ABCDEFGHIKLMNOPQRSTUVWXYZ";//用于填充矩阵
    int flag[25] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
    //标记字母是否已在矩阵中与letters数组对应
    char ch[5][5];//5X5矩阵
    char ch1[N];//密钥
    char ch2[N];//密文
    int len = 'a' - 'A';
    int flg = 1;
    cout << "输入密钥";
    cin >> ch1;
    while (flg == 1)
    {
        for (int i = 0; i < strlen(ch1); i++)//把所输入的密钥转化为大写字母
        {
            if (ch1[i] > 'z' || ch1[i] < 'a')
            {
                cout << "请重新选择操作" << endl;
                flg = 0; break;
            }
            else
                ch1[i] = ch1[i] - len;
        }
        if (flg == 1)
        {
            for (int i = 0; i < strlen(ch1); i++)//把密钥中的J都变为I        
            {
                if (ch1[i] == 'J')ch1[i] = 'I';
            }
            int i = 0; int j = 0;
            //把密钥中的字母填入到矩阵中并把该字母标记为已用
            for (int k = 0; k < strlen(ch1); k++)
            {
                for (int t = 0; t < 25; t++)
                {
                    if (ch1[k] == letters[t] && flag[t] == 0)
                    {
                        ch[i][j] = letters[t];
                        flag[t] = 1;
                        if (j < 4)j++;
                        else { i++; j = 0; }
                    }
                }
            }
            for (int k = 0; k < 25; k++)//按字母表顺序把未用字母依次填入到矩阵中
            {
                if (flag[k] == 0)
                {
                    ch[i][j] = letters[k];
                    flag[k] = 1;
                    if (j < 4)j++;
                    else { i++; j = 0; }
                }
            }
            cout << "密钥填充后的矩阵为 " << endl;
            for (i = 0; i < 5; i++)

                for (j = 0; j < 5; j++)
                {
                    cout << ch[i][j];
                    cout << " ";
                    if (j == 4)
                        cout << endl;
                }
            cout << endl;
            // 矩阵生成完毕
                int f = 0;
            do {
                cout << "请输入密文英文字符";
                cin >> ch2;
                for (int k = 0; k < strlen(ch2); k++)//把所输入的密文转化为大写字母
                {
                    if (ch2[k] >= 'a')
                        ch2[k] = ch2[k] - len;
                }
                for (int k = 0; k < strlen(ch2); k++)//把密文中的J都变为I
                {
                    if (ch2[k] == 'J')ch2[k] = 'I';
                }
                for (int k = 0; k < strlen(ch2); k += 2)
                {
                    if (ch2[k] == ch2[k + 1])
                    {
                        cout << "同一分组中不能出现相同字符请重新输入。" << endl;
                        f = 1;
                        break;
                    }
                    else f = 2;
                }
                if (f == 1)continue;
                if (strlen(ch2) % 2 != 0)
                {
                    cout << "字符串不能为奇数个请重新输入。" << endl;
                    f = 1;
                }
                else f = 2;
            } while (f == 1);
            //解密开始
            for (int k = 0; k < strlen(ch2); k += 2)
            {
                int m1, m2, n1, n2;
                for (m1 = 0; m1 <= 4; m1++)
                {
                    for (n1 = 0; n1 <= 4; n1++)
                    {
                        if (ch2[k] == ch[m1][n1])break;
                    }
                    if (ch2[k] == ch[m1][n1])break;
                }
                for (m2 = 0; m2 <= 4; m2++)
                {
                    for (n2 = 0; n2 <= 4; n2++)
                    {
                        if (ch2[k + 1] == ch[m2][n2])break;
                    }
                    if (ch2[k + 1] == ch[m2][n2])break;
                }
                m1 = m1 % 5;
                m2 = m2 % 5;
                if (n1 > 4) { n1 = n1 % 5; m1 = m1 + 1; }
                if (n2 > 4) { n2 = n2 % 5; m2 = m2 + 1; }
                if (m1 == m2)
                {
                    ch2[k] = ch[m1][(n1 + 4) % 5];
                    ch2[k + 1] = ch[m2][(n2 + 4) % 5];
                }
                else
                {
                    if (n1 == n2)
                    {
                        ch2[k] = ch[(m1 + 4) % 5][n1];
                        ch2[k + 1] = ch[(m2 + 4) % 5][n2];
                    }
                    else
                    {
                        ch2[k] = ch[m1][n2];
                        ch2[k + 1] = ch[m2][n1];
                    }
                }
            }
            cout << "解密后所得到的明文是";
            for (int k = 0; k < strlen(ch2); k += 2)
                cout << ch2[k] << ch2[k + 1] << " ";
            cout << endl;
        }
        else break;
    }

}

int main()
{

    int n;
    cout << "请选择1加密2解密:" << endl;
    while (true)
    {
        cin >> n;
        switch (n)
        {
        case 1:
            encrypt();
            break;
        case 2:
            decrypt();
            break;
        default:
            break;
        }
    }
    return 0;
}

代码执行结果操作的时候不要打空格空格视为默认字符
在这里插入图片描述

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

“PlayFair密码原理、代码” 的相关文章