PlayFair密码原理、代码

本文探讨了PlayFair密码的引入原因,它针对单表代替密码的局限性。PlayFair密码利用5x5矩阵和密钥进行加密,通过特定规则替换明文,包括两两分组、移位和替换。文章还提供了详细的加密和解密步骤,以及C++代码实现。
摘要由CSDN通过智能技术生成

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;
}

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

  • 26
    点赞
  • 138
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
下面是一个简单的 Python Playfair 密码实现代码: ```python from collections import OrderedDict class PlayfairCipher: def __init__(self, key): self.key = key self.key_matrix = self.generate_matrix(key) def generate_matrix(self, key): key = key.upper().replace("J", "I") key = "".join(OrderedDict.fromkeys(key)) key_matrix = [] for i in range(0, len(key), 5): key_matrix.append(list(key[i:i+5])) return key_matrix def encrypt(self, plaintext): plaintext = plaintext.upper().replace("J", "I") plaintext = "".join(OrderedDict.fromkeys(plaintext)) plaintext = plaintext.replace(" ", "") if len(plaintext) % 2 != 0: plaintext += "X" ciphertext = "" for i in range(0, len(plaintext), 2): a, b = plaintext[i], plaintext[i+1] a_pos = self.get_position(a) b_pos = self.get_position(b) if a_pos[0] == b_pos[0]: ciphertext += self.key_matrix[a_pos[0]][(a_pos[1]+1)%5] ciphertext += self.key_matrix[b_pos[0]][(b_pos[1]+1)%5] elif a_pos[1] == b_pos[1]: ciphertext += self.key_matrix[(a_pos[0]+1)%5][a_pos[1]] ciphertext += self.key_matrix[(b_pos[0]+1)%5][b_pos[1]] else: ciphertext += self.key_matrix[a_pos[0]][b_pos[1]] ciphertext += self.key_matrix[b_pos[0]][a_pos[1]] return ciphertext def decrypt(self, ciphertext): plaintext = "" for i in range(0, len(ciphertext), 2): a, b = ciphertext[i], ciphertext[i+1] a_pos = self.get_position(a) b_pos = self.get_position(b) if a_pos[0] == b_pos[0]: plaintext += self.key_matrix[a_pos[0]][(a_pos[1]-1)%5] plaintext += self.key_matrix[b_pos[0]][(b_pos[1]-1)%5] elif a_pos[1] == b_pos[1]: plaintext += self.key_matrix[(a_pos[0]-1)%5][a_pos[1]] plaintext += self.key_matrix[(b_pos[0]-1)%5][b_pos[1]] else: plaintext += self.key_matrix[a_pos[0]][b_pos[1]] plaintext += self.key_matrix[b_pos[0]][a_pos[1]] return plaintext def get_position(self, letter): for i, row in enumerate(self.key_matrix): if letter in row: return (i, row.index(letter)) raise ValueError(f"{letter} is not in the key matrix") ``` 使用示例: ```python key = "PLAYFAIREXAMPLE" cipher = PlayfairCipher(key) plaintext = "Hide the gold in the tree stump" ciphertext = cipher.encrypt(plaintext) print(ciphertext) # 输出:BMNDZBXDNABEKUDMUIXMMOUVIF decrypted_plaintext = cipher.decrypt(ciphertext) print(decrypted_plaintext) # 输出:HIDETHEGOLDINTHETREXESTUMP ```
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值