1、引入PlayFair密码的原因

(1)、因为单表代替的密钥量很小,不能抵抗穷尽搜索攻击
(2)、单表代替密码没有将明文字母出现的概率隐藏起来。很容易收到频率分析的攻击

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

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

(1)、编制密码表:
  1. 基于一个5×5的字母矩阵
  2. 该矩阵使用一个密钥(关键词)来构造
  3. 从左到右、从上到下;依次填入密钥的字母(PS:密钥中重复的字母不填),然后再以字母表顺序依次填入其他字母。
  4. 字母 I 和 J 算作一个字母 (PS:25的矩阵只能存储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;
}

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

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐