密碼學(2)-古典密碼學

古典密碼學雖然現在已經不再使用,但其反映了密碼設計和破譯的基本思想,是學習密碼學的入口。
古典密碼學主要有兩種體制:置換密碼和代換密碼。

置換密碼

根據一定的規則重新排列明文,以便打破原有的結構特性。即改變字符的原始位置,但字符還是那些字符。

  1. 列置換:比如明文m = “Beijing 2008 Olympic Games”,
    密鑰=(1 4 3)(5 6)。

該密鑰表示:一個括號一個循環,f(1) = 4,f(4) = 3 , f(3) = 1,這裏3是括號的末尾,所以f(3)的值就循環到了括號的最前面,即1。(5 6)類似,f(5) = 6 , f(6) = 5。少了2,未表示出來的等於其自身,所以f(2) = 2。其中f(a) = b 表示 a 列和 b 列的數據交換。由於它最大的數是6,則表示分組長度是6,那麼將明文m寫成如下形式:
B e i j i n
g 2 0 0 8 O
l y m p i c
G a m e s *

‘*’號爲填充,經過加密後結果爲:
j e B i n i
0 2 g 0 O 8
p y l m c i
e a G m * s

獲得密文c=“jeBini02g0O8pylmcieaGm*s”
解密時需要變換密鑰,(1 4 3)的逆置換爲(1 3 4),變換規則:對於每一個括號,第一個數字不變,後面反轉。例:(1 2 3 4 5) -》 (1 5 4 3 2)。是不是很簡單。那麼上一個解密密鑰=(1 3 4)(5 6),容易由密文再根據解密密鑰獲得明文。
寫了代碼試了下,僅供參考:

package Classical;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class Permutation {
//  private static final int MAXCOL = 1024;
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        String c = String.valueOf(columnEncry("Beijing 2008 Olympic Games", "(1 4 3)(5 6)"));
        System.out.println("密文:"+c.replace(" ",""));
        String m = String.valueOf(columnEncry(c,"(1 3 4)(5 6)"));
        System.out.println("明文:"+m.replace(" ",""));
    }
    /*
     *@author 孤舟一葉
     *@param in表示要加密的數據,key表示密鑰,形如(1 4 3)(5 6)
     *@return 返回密文
     */
    public static StringBuilder columnEncry(String in, String key){

        int colNum = 0;
        Map<Integer,Integer> relation = new HashMap<Integer,Integer>();
        String[] keySplited = key.split("[(]");
        for(int i = 1 ; i < keySplited.length ; i++){
            int len = keySplited[i].length()-1;
            keySplited[i] = keySplited[i].substring(0, len);
            String[] block = keySplited[i].split(" ");
            int[] intBlock = new int[block.length];
            for(int j = 0 ; j < block.length ; j++){
                intBlock[j] = Integer.valueOf(block[j]);
                if(colNum < intBlock[j]){
                    colNum = intBlock[j];
                }
            }
            int lenOfBlock = block.length;
            for(int m =0 ; m < lenOfBlock-1 ; m++){
                relation.put(intBlock[m], intBlock[m+1]);
            }
            relation.put(intBlock[lenOfBlock-1],intBlock[0]);
        }
        String inNoSpace = in.replace(" ", "");
        StringBuilder inNoSpaceAddEle = new StringBuilder(inNoSpace);
        int supplement = (colNum - inNoSpace.length()%colNum)%colNum;
        for(int i = 0 ; i < supplement ; i++){
            inNoSpaceAddEle.append("*");//如果添加“”,長度不會增加
        }
        StringBuilder out = new StringBuilder();
        for(int i = 0 ; i < inNoSpaceAddEle.length() ; i++){
            int from  = 0;
            if(relation.get(i % colNum + 1)!= null){
                from  = relation.get(i % colNum + 1)-1;
                out.append(inNoSpaceAddEle.charAt(i/colNum*colNum+from));
            }
            else{
                out.append(inNoSpaceAddEle.charAt(i));
            }
        }
        return out;
    }
}

運行結果:
密文:jeBini02g0O8pylmcieaGm*s
明文:Beijing2008OlympicGames*

  1. 週期置換
    我認爲其原理和列置換完全相同,真的不理解書中爲什麼將其叫做兩個名字。如果非要說不同,那只有列置換將明文豎向排列,週期置換將明文橫向排列了。還是上個例子中的明文,週期置換這麼處理:
    (Beijin)(g2008O)(lympic)(Games*)經過密鑰=(1 4 3)(5 6)處理後,密文:
    (jeBini)(02g0O8) (pylmci)(eaGm*s)

代換密碼

使用其他字符代替明文字符,密文的字符不是由原來那些字符組成了。

單表代換

  1. 基於密鑰的單表代換:最簡單查表,找出明文對應的密文。
  2. 仿射密碼:加密時,明文經過一個線性變換 y = e(x) = ax + b (mod 26),將明文字符變換爲其他字符。解密時,需要先求解 a mod 26 的乘法逆元 a^-1,然後 x = a^-1[e(x)-b] (mod26) 求解明文。相關需要的數學知識包括:歐幾里得求解最大公約數擴展歐幾里得算法求解乘法逆元
    代碼如下:
package Classical;

public class Substitution {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        String c = affine("sorcery",11,6);
        System.out.println("密文:"+c);
        int inverseOfa = mulInverse(26,11);
        String m = affine(c,inverseOfa,((-6*inverseOfa)%26+26)%26);
        System.out.println("明文:"+m);
    }
    /*
     * @author 孤舟一葉
     * @param m:明文;a,b仿射函數參數,其中a和26互素
     * @return 返回密文
     */
    public static String affine(String m,int a,int b){
        if(!isPrimeWith26(a)){
            return "仿射函數必須滿足gcd(26,a)=1";
        }
        m = m.toUpperCase();
        StringBuilder out = new StringBuilder();
        for(int i = 0; i < m.length(); i++){
            int ch = m.charAt(i);
            if(ch >= 65 && ch <= 90){
                ch = ch - 65;
                out.append((char)((ch * a + b)%26+65));
            }
            else
                out.append((char)ch);
        }
        return String.valueOf(out);
    }
    private static boolean isPrimeWith26(int a){
        if(a == 1)return true;
        int m = 26 ,n = a;
        while(m%n > 1){
            int temp = m%n;
            m = n;
            n = temp;
        }
        if(m%n == 1)return true;
        return false;
    }
    /*
     * @求解乘法逆元
     * @param 需要求解b mod a的乘法逆元
     * @return 乘法逆元
     */
    private static int mulInverse(int a , int b){
        if(0 == a || 0 == b){
            return -1;
        }
        int x1 = 1 , x2 = 0 , x3 = a;
        int y1 = 0 , y2 = 1 , y3 = b;
        int t1 = 0 , t2 = 0 , t3 = 0;
        int n;
        for(t3 = x3 % y3 ; t3 != 0 ; t3 = x3 % y3){
            n = x3 / y3;
            t1 = x1 ; t2 = x2;
            x1 = y1; x2 = y2 ; x3 = y3;
            y1 = t1 - n * y1 ; y2 = t2 - n * y2 ; y3 = t3;
        }
        if(1 == y3){
            return (y2%a+a)%a;
        }
        return -1;
    }
}

運行結果:
密文:WELCYLK
明文:SORCERY

多表代換

多表代換典型的有三種:Playfair、維吉尼亞密碼、Hill密碼
這裏給出維吉尼亞的代碼,其他的讀者可自行學習。

package Classical;

public class Vigenere {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        String c = enCry("cyber greatwall","iscbupt");
        System.out.println("密文:"+c);
        String m = deCry(c,"iscbupt");
        System.out.println("明文:"+m);
    }
    public static String enCry(String in , String key){
        in = in.replace(" ", "");
        in = in.toLowerCase();
        key = key.toLowerCase();
        StringBuilder out = new StringBuilder();
        for(int i =0 ; i < in.length() ;i++){
            out.append((char)((in.charAt(i)-97+key.charAt(i%key.length())-97)%26+97));
        }
        return String.valueOf(out);

    }
    public static String deCry(String in , String key){
        in = in.replace(" ", "");
        in = in.toLowerCase();
        key = key.toLowerCase();
        StringBuilder out = new StringBuilder();
        for(int i =0 ; i < in.length() ;i++){
            out.append((char)(((in.charAt(i)-key.charAt(i%key.length()))%26+26)%26+97));
        }
        return String.valueOf(out);
    }
}

運行結果:
密文:kqdflvkmsvxuae
明文:cybergreatwall

分析方法

統計分析法:某種語言各個字符出現的頻率不同,比如英語中 E 的出行頻率最高。可以根據字母密文中各個字符出現的頻率不同,分析出該密文字符代表的明文字符。對單表代換有用。
重合指數法:利用隨機文本和英文文本的統計概率差別分析密鑰長度
明文-密文對分析法:由於 Hill密碼 對重合指數法和統計分析法具有抵抗性,可使用明文-密文對分析法破譯。

至此,古典密碼介紹告一段落,接下來我們將進入現代密碼的學習。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章