目录

1、原理

2、流程图

3、编程实现

4、总结


1、原理

        Playfair密码是一种使用一个关键词方格来加密字符对的加密算法,是一种多表代换的对称加密技术

它依据一个5*5的正方形组成的密码表来编写,密码表里排列有25个字母。如果一种语言字母超过25个,可以去掉使用频率最少的一个。如,法语一般去掉w或k,德语则是把i和j合起来当成一个字母看待。英语中z使用最少,可以去掉它。可以很好的防御频率分析法的攻击。

同时Playfair密码对明文和密文有一定的要求:在加密之前首先需要整理明文,将明文中两个字母组成一组,如果两个字母相同则分成两组,在每组的后面加字母X或Q。如果明文字母个数是奇数,在最后一个字母之后加字母X或Q。密文的字母个数一定是偶数,任意两个同组的字母都不会相同。

Playfair密码加密的一般过程:

1、输入明文

2、输入密钥得到密码表

3、整理明文

4、加密明文得到密文

首先通过将密钥字母放在密码表的头部(第一行及之后或第一列及之后),之后将其他字母按字母顺序填充到密码表中以得到密码表。由于英文字母有26个,所以一般会将i和j放在同一个位置上。之后整理明文,最后加密明文。

加密规则:

  • 若m1,m2在同一行,对应密文c1,c2分别是紧靠m1,m2 右端的字母。其中第一列被看做是最后一列的右方。

  • 若m1,m2在同一列,对应密文c1,c2分别是紧靠m1,m2 下方的字母。其中第一行被看做是最后一行的下方。

  • 若m1,m2不在同一行,不在同一列,则c1,c2是由m1,m2确定的矩形的其他两角的字母(横向替换或者纵向替换)。

    解密就是加密的逆过程。

  • 若c1,c2在同一行,对应明文m1,m2分别是紧靠c1,c2 左端的字母。其中第一列被看做是最后一列的右方。

  • 若c1,c2在同一列,对应明文m1,m2分别是紧靠c1,c2 上方的字母。其中第一行被看做是最后一行的下方。

  • 若c1,c2不在同一行,不在同一列,则m1,m2是由c1,c2确定的矩形的其他两角的字母(横向替换或者纵向替换)。

2、流程图

3、编程实现

 难点:

1、如何根据密钥生成密码表

2、如何将密文解密恢复成明文

 难点1:

由于密码表是25个字母,可以将j和i都看作字母i,即将明文中的j全部看作是i。

对于密码表,先将密钥字母填入密码表,再按字母顺序将未填入的字母填入到密码表中。

void initkey() {cout << endl << "请输入密钥以生成密码表:" << endl;string key = "";//输入密钥cin >> key;int i = 0;int j = 0;for (char ch : key) {if (ch == ' ' || vis[ch - 'a'])continue;if (ch == 'j')ch = 'i';m.insert(myMap::value_type(ch - 32, { i,j }));//不知道哪根筋抽了用map来存储密码表vis[ch - 'a'] = 1;i += j == 4;j = (j + 1) % 5;}for (int k = 0; k < 26; k++) {if (k == 9)continue;if (!vis[k]) {m.insert(myMap::value_type(k + 'A', { i,j }));vis[k] = 1;i += j == 4;j = (j + 1) % 5;}}//for (auto &temp : m) {// cout << temp.first << " " << temp.second.first << " " << temp.second.second << endl;//}cout << "成功生成密码表" << endl;
}

  难点2:

密文恢复成明文就是明文加密成密文的逆过程,但是由于明文中的j变成了i,如果明文为奇数或者相邻两个字母相同时,还会加X,所以最后得到的明文并不是真正的明文,需要经过一些处理,在这里省略了处理的过程(其实是不会处理),毕竟主要还是学习密码的思想。

        具体代码如下:  

默认输入为小写字母不带空格

主函数

#include"Playfair.h"int main() {while (1) {show();     //菜单界面keyDown();    //按键处理system("pause");system("cls");}
}

        Playfair.h

#pragma once
#include<cstdio>
#include<iostream>
#include<string>
#include<Windows.h>
#include<unordered_map>
using namespace std;
void init();
void initkey();
void show();
void keyDown();
void readFile();
void saveFile();
void encrypt();
void decrypt();

        Playfair.cpp

#include "Playfair.h"string finalStr;
string fileStr;
typedef unordered_map<char, pair<int, int>> myMap;//密码表
myMap m;//5*5密码表 大写
int vis[26];//生成密码表标记 去掉jvoid init() {finalStr = "";fileStr = "";m = myMap();memset(vis, 0, sizeof(vis));
}void show()
{cout << "****************Playfair密码****************" << endl;cout << "\t\t1.加密文件" << endl;cout << "\t\t2.解密文件" << endl;cout << "\t\t3.退出" << endl;cout << "******************************************" << endl;
}void keyDown()//按键处理
{int userkey = 0;cin >> userkey;switch (userkey) {case 1:cout << "-----------------加密文件-----------------" << endl;readFile();initkey();encrypt();saveFile();init();break;case 2:cout << "-----------------解密文件-----------------" << endl;readFile();initkey();decrypt();saveFile();init();break;case 3:exit(0);break;}
}void readFile()//读取文件
{cout << "请输入文件名:" << endl;string fileName;cin >> fileName;FILE* fp = fopen(fileName.c_str(), "r+");if (fp == nullptr) {cout << "未找到相关文件" << endl;return;}else {cout << "成功打开文件" << endl;}char ch;int pos = 0;while ((ch = fgetc(fp)) != EOF) {fileStr += ch;}cout << endl << "明文为:" << endl;cout << fileStr << endl;fclose(fp);
}void saveFile()//保存文件
{string fileName;cout << endl << "请输入要保存信息的文件名:" << endl;cin >> fileName;FILE* fp = fopen(fileName.c_str(), "w+");if (fp == nullptr) {cout << endl << "保存文件失败" << endl;return;}else {cout << endl << "保存成功" << endl;}fprintf(fp, "%s", finalStr.c_str());fclose(fp);}void initkey() {cout << endl << "请输入密钥以生成密码表:" << endl;string key = "";//输入密钥cin >> key;int i = 0;int j = 0;for (char ch : key) {if (ch == ' ' || vis[ch - 'a'])continue;if (ch == 'j')ch = 'i';m.insert(myMap::value_type(ch - 32, { i,j }));vis[ch - 'a'] = 1;i += j == 4;j = (j + 1) % 5;}for (int k = 0; k < 26; k++) {if (k == 9)continue;if (!vis[k]) {m.insert(myMap::value_type(k + 'A', { i,j }));vis[k] = 1;i += j == 4;j = (j + 1) % 5;}}//for (auto &temp : m) {//  cout << temp.first << " " << temp.second.first << " " << temp.second.second << endl;//}cout << "成功生成密码表" << endl;
}char researchkey(int x, int y) {//在密码表里面查找明文字母对应的密文字母for (myMap::iterator it = m.begin(); it != m.end(); it++) {if (it->second.first == x && it->second.second == y) {return it->first;}}
}void encrypt() {//整理明文并加密string temp;//存放大写明文for (int i = 0; i < fileStr.size(); i++) {// 通过这个for循环去除非法字符以及将明文字母变为大写,将'J'变为'I'  if ((fileStr[i] >= 'a' && fileStr[i] <= 'z') || (fileStr[i] >= 'A' && fileStr[i] <= 'Z')) {if (fileStr[i] == 'j' || fileStr[i] == 'J') {temp += 'I';}else {temp += fileStr[i] >= 'a' ? fileStr[i] - 'a' + 'A' : fileStr[i];}}}if (temp.size() % 2 == 1) {temp += 'X';}//cout << temp << endl;int j1 = 0, j2 = 0, l1 = 0, l2 = 0;   //两个字符的坐标char p1, p2;                               //两个字符for (int i = 0; i < temp.size(); i += 2) {p1 = temp[i];p2 = temp[i + 1];j1 = m[p1].first;l1 = m[p1].second;j2 = m[p2].first;l2 = m[p2].second;if (p1 != p2) {//printf("%c %c %d %d %d %d\n",p1,p2,j1,l1,j2,l2);if (j1 == j2) {finalStr += researchkey(j1, (l1 + 1) % 5);finalStr += researchkey(j2, (l2 + 1) % 5);}else if (l1 == l2) {finalStr += researchkey((j1 + 1) % 5, l1);finalStr += researchkey((j2 + 1) % 5, l2);}else if (j1 != j2 && l1 != l2) {finalStr += researchkey(j1, l2);finalStr += researchkey(j2, l1);}}else {//p1p3 p2p3char p3 = 'X';int j3, l3;j3 = m[p3].first;l3 = m[p3].second;if (j1 == j3) {finalStr += researchkey(j1, (l1 + 1) % 5);finalStr += researchkey(j3, (l3 + 1) % 5);}else if (l1 == l3) {finalStr += researchkey((j1 + 1) % 5, l1);finalStr += researchkey((j3 + 1) % 5, l3);}else if (j1 != j3 && l1 != l3) {finalStr += researchkey(j1, l3);finalStr += researchkey(j3, l1);}if (j2 == j3) {finalStr += researchkey(j2, (l2 + 1) % 5);finalStr += researchkey(j3, (l3 + 1) % 5);}else if (l2 == l3) {finalStr += researchkey((j2 + 1) % 5, l2);finalStr += researchkey((j3 + 1) % 5, l3);}else if (j3 != j2 && l3 != l2) {finalStr += researchkey(j2, l3);finalStr += researchkey(j3, l2);}}}cout << endl << "生成的密文为:" << endl;cout << finalStr << endl;
}void decrypt() {//解密密文string temp = fileStr;int j1 = 0, j2 = 0, l1 = 0, l2 = 0;   //两个字符的坐标char p1, p2;                       //两个字符for (int i = 0; i < temp.size(); i += 2) {p1 = temp[i];p2 = temp[i + 1];j1 = m[p1].first;l1 = m[p1].second;j2 = m[p2].first;l2 = m[p2].second;if (j1 == j2) {finalStr += researchkey(j1, (l1 + 4) % 5) + 32;finalStr += researchkey(j2, (l2 + 4) % 5) + 32;}else if (l1 == l2) {finalStr += researchkey((j1 + 4) % 5, l1) + 32;finalStr += researchkey((j2 + 4) % 5, l2) + 32;}else if (j1 != j2 && l1 != l2) {finalStr += researchkey(j1, l2) + 32;finalStr += researchkey(j2, l1) + 32;}}cout << endl << "明文为:" << endl;cout << finalStr << endl;}

4、总结

Playfair密码作为一种多表代换密码,不同位置上相同的字母会被加密成不一样的密文,可以有效的防止频率分析法的攻击。不过在使用Playfair之前双方需要进行一些规定,比如密码表是去掉z还是将i和j放到一个位置上,是加字母Q还是加字母X等等。所以没有必要去纠结一些细节,现在也不会再使用这样的古典密码算法,学习密码算法的思想才是关键。

Playfair密码(原理+代码)相关推荐

  1. PlayFair密码原理、代码

    1.引入PlayFair密码的原因 (1).因为单表代替的密钥量很小,不能抵抗穷尽搜索攻击 (2).单表代替密码没有将明文字母出现的概率隐藏起来.很容易收到频率分析的攻击 综上所述,我们会引入Play ...

  2. 加密算法学习(一、中、1)——传统加密算法(playfair密码)

    本博文借鉴自书本<密码编码学与网络安全--原理与实践(第七版)>,由William Stallings著,王后珍.李莉等译. 参考博客:信息安全-1:python之playfair密码算法 ...

  3. CTF-Crypto 密码原理及解密方法

    CTF-Crypto 密码原理及解密方法 文章目录 CTF-Crypto 密码原理及解密方法 推荐综合加解密网址 一.常见密码格式 二.古典密码 凯撒密码 仿射密码 埃特巴什码 培根密码 棋盘密码 希 ...

  4. 深入 WEP和 WPA密码原理

    深入 WEP和 WPA密码原理 1 概述 目前情况下: WEP的破解为利用加密体制缺陷,通过收集足够的数据包,使用分析密算法还原出密码. WPA目前没有加密体制的缺陷可被利用,破解WPA密码使用的是常 ...

  5. 深入 WEP和 WPA密码原理 1

    深入 WEP和 WPA密码原理   1  概述  目前情况下: WEP的破解为利用加密体制缺陷,通过收集足够的数据包,使用分析密算法还原出密码. WPA目前没有加密体制的缺陷可被利用,破解WPA密码使 ...

  6. python 古典密码第一弹(凯撒密码,Playfair密码,维吉尼亚密码)

    各位白嫖-漂亮大哥哥姐姐们好,在下菜鸡一枚,主要想在这和大家一起探讨学习之道,一起愉快的学习密码学基础.总所周知,密码学学的好,头发掉的少... 直接进入正题,今天我就主要讲三个密码,而且都是古典密码 ...

  7. CTF-Crypto-各种密码原理及解密方法

    CTF-Crypto-各种密码原理及解密方法 一.常见密码格式(太懒了,待补充) 二.古典密码 凯撒密码 仿射密码 埃特巴什码 培根密码 棋盘密码 希尔密码 维吉尼亚密码 摩尔斯密码 栅栏密码(普通型 ...

  8. playfair密码和凯撒密码加密算法的Java实现

    文章目录 一.实现广义的凯撒密码加密算法 二.实现广义的playfair密码的加密算法 总结 加密原理: 一.实现广义的凯撒密码加密算法 //实现广义的凯撒密码//凯撒密码的加密String plai ...

  9. 浏览器记住密码--原理/不记住密码的方法

    原文网址:浏览器记住密码--原理/不记住密码的方法_IT利刃出鞘的博客-CSDN博客 简介 本文介绍浏览器是如何自动跳出保存密码的提示的,并介绍如何让浏览器不自动跳出保存密码的提示的方法. 记住密码的 ...

最新文章

  1. 【怒怼老乔】居然苹果手机IOS系统还不支持css3的transparent属性值,我去~~~~
  2. C++ Primer 5th笔记(chap 14 重载运算和类型转换)算术和关系运算符
  3. [密码学] 双重与三重DES
  4. Mysql5.X重点难点速记
  5. Java程序设计----Java编程基础
  6. php里的抽象类和接口
  7. 如果有一天生你养你的两个人都走了
  8. pyecharts anaconda_Pyecharts安装使用和绘图案例
  9. 洛谷P3386 【模板】二分图匹配
  10. Illustrator中文版教程,如何在 Illustrator中设置图标项目?
  11. vb调用c语言程序,用VB编写程序,求S=A!+B!+C!,阶乘的计算分别用Sub过程和Function过程两种方法来实现...
  12. 实验2 网络扫描--Nmap与X-Scan
  13. twaver html5软件价格,TWaver数据中心可视化软件
  14. Mac电脑没声音了怎么办?苹果电脑没声音的解决方法
  15. 乔布斯的创新故事_创新工作的真实故事
  16. Win11 连接不上NAS
  17. SCUT校赛130:对抗女巫的魔法碎片(思维)
  18. Gwallet小百科 | 一文透析腾讯区块链技术
  19. 如何像说话一样去写作 -- Ray Dalio
  20. 美国核聚变反应中首次实现净能量增益 或改变未来能源路线图

热门文章

  1. 输入两个整数,求他们相除的余数。用带参的宏来实现,编程序。
  2. 为什么条码扫描器太靠近条形码会扫描不出来?
  3. 我的世界麦块的java_麦块游戏盒子App手机mod版下载-麦块盒子我的世界Java版v9.0.2 最新版-007游戏网...
  4. 西工大计算机专业代码,2022考研西北工业大学计算机专业招生简章-招生目录-初试范围/科目-什么时候公布?...
  5. word表格放在文件夹中卡死打不卡(未响应)
  6. CPU核心数线程数、程序进程线程、并发并行
  7. 《我叫刘跃进》------羊吃狼的故事
  8. clamav完整查杀linux病毒实战(转)
  9. 魅族android10内侧,魅族Flyme内测招募:10款机型升级Android 10!
  10. 关于支付宝证书错误 800A138F