密码学(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密码 对重合指数法和统计分析法具有抵抗性,可使用明文-密文对分析法破译。

至此,古典密码介绍告一段落,接下来我们将进入现代密码的学习。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值