古典密码:playfair(Java实现)
(之前做实验的时候用到的,参考了网上的一些代码,最终还是想记下来,希望能够对别人有一点点帮助吧。代码有点累赘,懒得改了)
playfair算法
Playfair是最著名的多字母代替密码,它把明文中的双字母音节作为一个单元并将其换成密文的双字母音节。而且,利用频率分析字母对就更困难一些。
算法原理:
Playfair算法是基于一个由**词构成的5*5字母矩阵,填充矩阵的方法是:首先将**词(去掉重复字母)从左至右、从上至下填在矩阵格子中,再将剩下的字母按字母表的顺序从左至右、从上至下填在矩阵剩下的格子里。字母I和J暂且当成一个字母(本例中用 星号 代替),对明文按以下规则一次加密两个字母:
(1)如果该字母对的两个字母是相同的,那么在它们之间加一个填充字母,比如x。例如ballon先把它变成ba lx lo on这样四个字母对。
(2)落在矩阵同一行的明文字母对中的字母由其右边的字母来代替,每行中最右边的一个字母就用该行中最左边的第一个字母来代替。
(3)落在矩阵同一列的明文字母对中的字母由其下面的字母来代替,每列中最右边的一个字母就用该列中最上面的第一个字母来代替。
(4)其他的每组明文字母对中的字母按以下方式代替,该字母所在行为密文所在行,另一字母所在列为密文所在列。
代码部分
1.导入
输入、堆栈、正则表达式
import java.util.Scanner;
import java.util.Stack;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
2.所用到的变量
public class demo {
static String key;//**
static String plain;//明文
static String cipher;//密文
static char[][] KeyMatrix;//**矩阵
static String[] formatP;//格式化后的明文
static String[] formatC;//格式化后的密文
static String cipherString;
static int k=0;//判断是第几次输入密文
3.构造**矩阵
public char[][] getKeyMatrix(String key){
char[] array=key.toCharArray();//输入的**
char[] arraykey=new char[array.length];//去重复后的**,不超过原**长度
String keykey="";//去重复后的**
char[] zimu = new char[26];//替换掉i、j后的26个字母
String zimu1="";
char[] letter = new char[26];//去掉**后的字母
char[][] matrix = new char[5][5];
//把i和j当作一个字母*
for(int i=0;i<26;i++){
if((char)(65+i)=='I') {
zimu1 += '*';
i++;
}
else
if((char)(65+i)!='J')
zimu1 += (char)(65+i);
}
zimu=zimu1.toCharArray();
//**去重:如果有重复字母,只输入最后一次出现的字母,**中的i、j换成*
for(int i=0;i<array.length;i++) {
int r=0;
for(int j=i+1;j<array.length;j++) {
if(array[i] == array[j]) {
r=1;
break;
}
}
if(r==0) {
if(array[i] =='I' || array[i] =='J') {
keykey+='*';
}
else
keykey+=array[i];
}
}
arraykey=keykey.toCharArray();
//去除**字母后剩下的字母
int num=0;
for(int i=0;i<zimu.length;i++){
int flag=0;
for(int j=0;j<arraykey.length;j++){
if(zimu[i] == arraykey[j]) {
flag=1;
break;
}
}
if(flag==0) {
letter[num]=zimu[i];
num++;
}
}
int index=0;
int k=0;
for(int i=0;i<5;i++){
for(int j=0;j<5;j++){
//先把**写入矩阵
if(index<arraykey.length){
matrix[i][j]=arraykey[index];
index++;
}
//把不重复的字母写入矩阵
else
if(k<letter.length){
matrix[i][j]=letter[k];
k++;
}
else;
System.out.print(matrix[i][j]+" ");
}
System.out.println();
}
return matrix;
}
4.把明文转化为字母对
public String[] formatPlain(String plain) {
Stack<Character> stack = new Stack<Character>();
String[] dual_letter = new String[24];
Character[] outs = new Character[2];
char[] arrayplain1 = plain.toCharArray();
String stringplain = "";
for(int i=0;i<arrayplain1.length;i++) {
if(arrayplain1[i] != 'I') {
if(arrayplain1[i] == 'J')
stringplain += '*';
else
stringplain += arrayplain1[i];
}
else
stringplain += '*';
}
char[] arrayplain = stringplain.toCharArray();
int num = 0;
int index=0;
for(int i=0;i<arrayplain.length;i++) {
dual_letter[index]="";
if(num<2) {
stack.push(arrayplain[i]);
num++;
}
//最后剩下一个字母时
if(i==arrayplain.length-1 && num ==1) {
stack.push('X');
num=2;
}
while(num == 2) {
//如果字母对的两个字母是相同的情况
if(arrayplain[i] == arrayplain[i-1]) {
stack.pop();
stack.push('X');
i--;
}
else {
while(!stack.isEmpty()) {
for(int k=1;k>=0;k--) {
outs[k] = (Character)stack.pop();
}
for(int q=0;q<outs.length;q++) {
//System.out.print(outs[q]);
dual_letter[index] += outs[q];
}
System.out.print(dual_letter[index]);
index++;
}
num = 0;
break;
}
}
}
System.out.println();
return dual_letter;
}
5.对键盘输入的字符串进行格式化处理
提取字母并转化为大写字母
public String format(String str) {
String regEx="[^(A-Za-z)]"; //正则表达式
Pattern p = Pattern.compile(regEx); //
Matcher getStr = p.matcher(str);
str = getStr.replaceAll("").trim();
str = str.toUpperCase();
return str;
}
//加密
public String[] encode(String plain,String key) {
System.out.println("**矩阵为:");
KeyMatrix = getKeyMatrix(key);
System.out.print("格式化后的明文为:");
formatP = formatPlain(plain);
cipherString="";
int m=0;
String[] EnCipher = new String[24];//加密后的密文
int n=0;
System.out.print("加密后的密文为:");
while(formatP[m]!=null) {
EnCipher[n] = "";
int[][] position = getPosition(formatP[m],KeyMatrix);
int rowA = position[0][0];
int colA = position[0][1];
int rowB = position[1][0];
int colB = position[1][1];
int temp;
//同一行
if(rowA == rowB) {
EnCipher[n] += KeyMatrix[rowA][(colA+1)%5];
EnCipher[n] += KeyMatrix[rowA][(colB+1)%5];
}
//同一列
else if(colA == colB) {
EnCipher[n] += KeyMatrix[(rowA+1)%5][colA];
EnCipher[n] += KeyMatrix[(rowB+1)%5][colA];
}
else {
temp = colA;
colA = colB;
colB = temp;
EnCipher[n] += KeyMatrix[rowA][colA];
EnCipher[n] += KeyMatrix[rowB][colB];
}
System.out.print(EnCipher[n]);
cipherString += EnCipher[n];
n++;
m++;
}
System.out.println();
return EnCipher;
}
6.密文的格式化
字符串转化为双字母
public String[] formatCipher(String cipher) {
String[] arrayC = new String[cipher.length()];
cipher=cipher.toUpperCase();
int index = 0;
if(cipher.length()%2==0) {
System.out.print("格式化后的密文为:");
for(int i=0;i<cipher.length()-1;index++,i+=2) {
arrayC[index] = cipher.substring(i, i+2);
System.out.print(arrayC[index]);
}
System.out.println();
System.out.print("解密后的明文为:");
}
else {
System.out.println("密文不正确!");
System.out.print("请输入正确密文:");
Scanner input = new Scanner(System.in);
cipher = input.nextLine();
k++;
decode(cipher,key);
}
return arrayC;
}
public String[] decode(String cipher,String key) {
if(k == 0) {
System.out.println("**矩阵为:");
KeyMatrix = getKeyMatrix(key);
}
formatC = formatCipher(cipher);
int m=0;
String[] DeCipher = new String[24];//解密后的明文
int n=0;
while(formatC[m]!=null) {
DeCipher[n] = "";
int[][] position = getPosition(formatC[m],KeyMatrix);
int rowA = position[0][0];
int colA = position[0][1];
int rowB = position[1][0];
int colB = position[1][1];
int temp;
//同一行
if(rowA == rowB) {
if(colA == 0)
colA +=5;
if(colB == 0)
colB +=5;
DeCipher[n] += KeyMatrix[rowA][(colA-1)%5];
DeCipher[n] += KeyMatrix[rowA][(colB-1)%5];
}
//同一列
else if(colA == colB) {
if(rowA == 0)
rowA +=5;
if(rowB == 0)
rowB +=5;
DeCipher[n] += KeyMatrix[(rowA-1)%5][colA];
DeCipher[n] += KeyMatrix[(rowB-1)%5][colA];
}
else {
temp = colA;
colA = colB;
colB = temp;
DeCipher[n] += KeyMatrix[rowA][colA];
DeCipher[n] += KeyMatrix[rowB][colB];
}
System.out.print(DeCipher[n]);
n++;
m++;
}
System.out.println();
return formatC;
}
7.字母对在矩阵中的位置
public int[][] getPosition(String dual,char[][] KeyMatrix) {
//位置矩阵的值代表字母在**矩阵中的行和列
//[0][0]:字母A的行;[0][1]:字母A的列;
//[1][0]:字母B的行;[1][1]:字母B的列;
int[][] position = new int[2][2];
//确保是双字母的情况
if(dual.length()==2) {
char a = dual.charAt(0);
char b = dual.charAt(1);
for(int i=0;i<KeyMatrix.length;i++) {
for(int j=0;j<KeyMatrix[0].length;j++) {
if(a == KeyMatrix[i][j]) {
position[0][0] = i;
position[0][1] = j;
}
if(b == KeyMatrix[i][j]) {
position[1][0] = i;
position[1][1] = j;
}
}
}
}
return position;
}
8.main( )
public static void main(String[] args){
Scanner input = new Scanner(System.in);
demo play = new demo();
System.out.println("i和j看成是同一个字母*,X为填充字母");
System.out.println("===========================加密过程");
System.out.print("请输入**:");
key = input.nextLine();
System.out.print("请输入明文:");
plain = input.nextLine();
key = play.format(key);
plain = play.format(plain);
play.encode(plain,key);
System.out.println("===========================解密过程");
System.out.print("请输入解***:");
key = input.nextLine();
System.out.print("请输入密文:");
cipher = input.nextLine();
key = play.format(key);
play.decode(cipher,key);
}