单表代替密码的缺点是通过分析每个字母出现的频率可以破解出密码, 那么如果我们把多个字母当成一个单元整体替换,那么这种概率就会小很多。

比如最著名的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

 

 

 

 

 

这个矩阵的规则是:

1. 先将加密词中的不重复字母填充到矩阵的开头;

2. 按照字母顺序将剩余字母填充进矩阵,I和J 当成同一个字母处理。

二、对明文进行加密, 比如加密单词balloon,

1, 将明文拆成字母对,如果该字母对是相同的字母,则在他们之间填充一个固定的字母,这里我们使用x, 那么上面的单词就变成了如下的字母对:

ba-lx-lo-on

2,对上一步奏的字母对进行加密:

a), 落在矩阵同一行的明文字母对由其右边的字母代替,每行最右边的那个字母就使用该列最左边的字母代替, 比如AR-> RM

b),落在矩阵同一列的明文字母对由其下面的字母代替,没列最后一个字母就使用该列第一个字母字母代替,比如MU->CM

c),其他的每组明文字母对的中的字母按照如下方式代替,该字母所在行为密文所在行,另一个字母所在列作为密文所在列, 比如HS->BP,EA->IM

 

写了个大概的Java实现,可能有点问题, 用语表达意思:

  1 public class Playfair {
  2     public static final String KEY = "MONARCHY";
  3     public static char[][] getKeyMatrix(String key){
  4         key = key.toUpperCase(Locale.ENGLISH).replace('J','I');
  5         List<Character> chars = new ArrayList<Character>();
  6         for (char c : key.toCharArray()){
  7             if(!chars.contains(c)){
  8                 chars.add(c);
  9             }
 10         }
 11         char flag;
 12         for(int i = 65 ; i < 91 ; i++){
 13             flag = (char)i;
 14             if(flag == 'J'){
 15                 flag = 'I';
 16             }
 17             if (!chars.contains(flag)){
 18                 chars.add(flag);
 19             }
 20         }
 21         char[][] keyMatrix = new char[5][5];
 22         for(int i = 0 ; i < 5 ; i ++){
 23             for(int j = 0 ; j < 5 ; j++){
 24                 keyMatrix[i][j] = chars.get(i*5 + j);
 25             }
 26         }
 27         return keyMatrix;
 28     }
 29 
 30     public static short[] getLocation(char c, char[][] keyMatrix){
 31         c = c == 'J' ? 'I' : c;
 32         for (short i = 0 ; i < 5 ;i++){
 33             for(short j = 0 ; j < 5 ; j++){
 34                 if( c == keyMatrix[i][j]){
 35                     return new short[]{i,j};
 36                 }
 37             }
 38         }
 39         return null;
 40     }
 41 
 42     public static char[] mapKeyMatrix(char[] inputs, char[][] keyMatrix){
 43         short[] location1 = getLocation(inputs[0],keyMatrix);
 44         short[] location2 = getLocation(inputs[1],keyMatrix);
 45         if (location1[0] == location2[0]){
 46             if(location1[1] == 4){
 47                 return new char[]{keyMatrix[location1[0]][0],keyMatrix[location1[0]][location2[1]+1]};
 48             }
 49             if (location2[1] == 4){
 50                 return new char[]{keyMatrix[location1[0]][location1[1]+1],keyMatrix[location1[0]][0]};
 51             }
 52             return new char[]{keyMatrix[location1[0]][location1[1]+1],keyMatrix[location1[0]][location2[1]+1]};
 53         }
 54         if(location1[1] == location2[1]){
 55             if(location1[0] == 4){
 56                 return new char[]{keyMatrix[0][location1[1]],keyMatrix[location1[1]+1][location2[1]]};
 57             }
 58             if (location2[0] == 4){
 59                 return new char[]{keyMatrix[location1[0]+1][location1[1]],keyMatrix[0][location2[1]]};
 60             }
 61             return new char[]{keyMatrix[location1[0]+1][location1[1]],keyMatrix[location1[0]+1][location2[1]]};
 62         }
 63         return new char[]{keyMatrix[location1[0]][location2[1]], keyMatrix[location2[0]][location1[1]]};
 64     }
 65     public static String encode(String str,String key){
 66         if (str == null || key == null){
 67             return null;
 68         }
 69         char[][] keyMatrix = Playfair.getKeyMatrix(key);
 70         char[] chars = str.toUpperCase(Locale.ENGLISH).toCharArray();
 71         StringBuffer encode = new StringBuffer();
 72         char[] maps = new char[2];
 73         for (int i = 0 ; i < chars.length ; i++){
 74             if(chars[i] < 65 || chars[i] > 90){
 75                 encode.append(chars[i]);
 76                 continue;
 77             }
 78             if((i+1) < chars.length && (chars[i+1] < 65 || chars[i+1] > 90)){
 79                 maps = new char[]{chars[i],'X'};
 80                 encode.append(mapKeyMatrix(maps,keyMatrix));
 81                 i++;
 82                 continue;
 83             }
 84             if( i == chars.length - 1){
 85                 maps = new char[]{chars[i],'X'};
 86                 encode.append(mapKeyMatrix(maps,keyMatrix));
 87                 break;
 88             }
 89             if(chars[i] == chars[i+1]){
 90                 encode.append(mapKeyMatrix(new char[]{chars[i],'X'},keyMatrix));
 91                 continue;
 92             }else{
 93                 encode.append(mapKeyMatrix(new char[]{chars[i],chars[i+1]},keyMatrix));
 94             }
 95             i++;
 96         }
 97         return encode.toString();
 98     }
 99     public static void main(String[] args) {
100         System.out.println(encode("I am Jerry, I come from Jian Yang, I don't know where is the future", KEY));
101     }
102 }

这种密码算法可以掩盖一部分字母出现频率导致密码被破译的问题, 但是这只是并没有解决本质问题, 还是可以通过分析字母出现的频率破解密码。

-wellmax