Playfair加密算法的原理
Playfair算法是基于一个由密钥词构成的5*5字母矩阵,把明文中的双字母音节作为一个单元并将其转换成密文的“双字母音节”。
- 使用密钥词monarchy。填充矩阵结果如下
M O N A R
C H Y B D
E F G I/J K
L P Q S T
U V W X Z
填充的规则是:首先将密钥词(去掉重复字母)从左至右、从上至下的填到矩阵的格子中,再将剩余的字母按照字母表的顺序从左至右、从上至下的填到矩阵中,字母I和J暂且看成同一个字母。 - 按如下规则一次加密两个字母:
- 如果该字母对的两个字母是相同的,那么在它们中间加一个填充字母,比如x。例如balloon 先把它变成 ba lx lo on 这4对字母对。
- 如果末尾字母落单,补上x, 比如 wsl 变成 ws lx
- 同行取右。每行最右边的一个字母就用该列中最左边的一个字母代替。比如ar变成RM
- 同列取下。道理同上,每列最下边的一个字母就用该列中最上边的一个字母代替。比如mu变成CM。
- 其他情况取交叉,任意选择方向。比如hs变成BP,ea变成IM(或者JM)。
工具类
/**
* @Description
* @Author yuxiang
* @CreatedDate 2019/10/10 11:08
*/
public class InputUtil {
/**
* 判断是否是英文字符
* @param str
* @return
*/
public static boolean isEngLishChar(String str) {
char[] chars=str.toCharArray();
boolean isPhontic = false;
for(int i = 0; i < chars.length; i++) {
isPhontic = (chars[i] >= 'a' && chars[i] <= 'z') || (chars[i] >= 'A' && chars[i] <= 'Z'||chars[i] <= ' ');
if (!isPhontic) {
return false;
}
}
return true;
}
/**
* 输入方法
* @return
*/
public static String input(){
Scanner sc = new Scanner(System.in);
String text = sc.nextLine();
if (!isEngLishChar(text)){
System.out.println("请输入英文文本:");
text = input();
}
return text;
}
}
加密算法的demo
/**
* @Description 加密算法===》》playfair加密
* @Author yuxiang
* @CreatedDate 2019/10/22 21:14
*
* 1.密钥构成5 x 5矩阵(I/J暂且成一个字母)
* 2.对明文的两个字母加密:
* (1)若两个字母是相同的,则在它们之间添加一个字母
* (2)同行取右、同列取下、其他取交叉
*/
public class EncryptDemo02 {
public static void main(String[] args) {
//获取输入的明文,密钥词
System.out.println("请输入明文:");
String cleartext = InputUtil.input();
System.out.println("请输入密钥词:");
String key = InputUtil.input();
System.out.println(cleartext+" ======>>> "+key);
System.out.println("处理后的密钥5*5矩阵:");
char[][] ch =matrix(key);
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 5; j++) {
System.out.print(ch[i][j]+" ");
}
System.out.println();
}
System.out.println("密文:"+encrytPlayfair(cleartext,ch));
}
/**
* 将密钥处理成5*5的矩阵
* 除去重复字母,I转换成J
* @param key
* @return
*/
public static char[][] matrix(String key){
//转化成大写
key = key.toUpperCase();
//去除非字母的字符
key = key.replaceAll("[^A-Z]","");
//用J替换I
key = key.replaceAll("I","J");
if (key.isEmpty()){
return null;
}
char[] chars = key.toCharArray();
List<Character> characterList = new ArrayList<>();
for (int i = 0; i < chars.length; i++) {
//去除重复字母
if (!characterList.contains(chars[i])){
characterList.add(chars[i]);
}
}
//添加按字母表顺序排序的剩余的字母
for (char ch='A';ch<='Z';ch++) {
if (ch!='J'&&!characterList.contains(ch)){
characterList.add(ch);
}
}
//转化5*5矩阵
char[][] matrix = new char[5][5];
int count = 0;
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 5; j++) {
matrix[i][j] = characterList.get(count);
count++;
}
}
return matrix;
}
/**
* 给明文加密 重复字母中间插X,长度非偶数添加X
* @param cleartext
* @param key
* @return
*/
public static String encrytPlayfair(String cleartext,char[][] key){
//将明文转化为大写 处理空格
// 用J替换I
String[] strings = cleartext.toUpperCase().replaceAll("J","I").trim().split(" ");
//密文结果
StringBuffer result = new StringBuffer();
for (int i = 0; i < strings.length; i++) {
/*
使用StringBuilder处理字符串
*/
StringBuilder sb = new StringBuilder(strings[i]);
for (int j = 1; j < sb.length(); j = j + 2) {
//一对明文字母如果是重复的则在这对明文字母之间插入一个填充字符
if (sb.charAt(j) == sb.charAt(j - 1)) {
sb.insert(i, 'X');
}
}
//如果末尾字母落单,补上X
if (sb.length()%2!=0){
sb.append('X');
}
char[] chars = sb.toString().toCharArray();
//取两字母向5*5矩阵中规则配对
for (int j = 1; j < chars.length; j=j+2) {
result.append(encrpt(key,chars[j-1],chars[j]));
}
//添加空格
result.append(" ");
}
return result.toString();
}
/**
* 对两个字符在5*5矩阵中进行规则匹配,返回结果
* @param matrix
* @param ch1
* @param ch2
* @return
*/
private static String encrpt(char[][] matrix,char ch1,char ch2){
//获取明文对在矩阵的位置 r行 c列
int r1 =0,r2=0,c1=0,c2= 0;
for (int i = 0; i < matrix.length; i++) {
for (int j = 0; j < matrix[i].length; j++) {
if (matrix[i][j]==ch1){
r1=i;
c1=j;
}
if (matrix[i][j]==ch2){
r2=i;
c2=j;
}
}
}
StringBuffer stringBuffer = new StringBuffer();
/*
加密关键:同行取右、同列取下、其他取交叉
*/
//同行取右
if (r1==r2){
stringBuffer.append(matrix[r1][(c1+1)%5]);
stringBuffer.append(matrix[r2][(c2+1)%5]);
}else if (c1==c2){
//同列去下
stringBuffer.append(matrix[(r1+1)%5][c1]);
stringBuffer.append(matrix[(r2+1)%5][c2]);
}else {
//其他取交叉,任意选择方向
stringBuffer.append(matrix[r1][c2]);
stringBuffer.append(matrix[r2][c1]);
}
return stringBuffer.toString();
}
}
运算结果
有什么不合理的地方大佬们可以评论提出,小白一枚~