传统加密技术续-Hill Vigenere Vernam

12 篇文章 0 订阅
9 篇文章 3 订阅

在上篇文章中,讲述了一些加密解密的概念以及Caesar、单表替换密码、Playfair密码。在这篇文章中主要涉及Hill密码,Vigenere密码,Vernam密码,置换技术。

Hill密码

希尔密码(Hill Cipher)是运用基本矩阵论原理的替换密码,由Lester S.Hill在1929年发明。该加密算法将m个连续的明文字母替换成m个密文字母,这是由m个线性等式决定的,在等式里每个字母被指定为一个数值(a=0,b=1,….,z=25)。例如m=3,系统可以描述为:
c1=(k11p1+k21p2+k31p3)mod26
c2=(k12p1+k22p2+k32p3)mod26
c3=(k13p1+k23p2+k33p3)mod26
用行向量和矩阵表示如下:
这里写图片描述

这里C和P是长度为3的行向量,分别代表密文和明文,K是一个3*3矩阵,代表加密密钥。运算按模26执行。相应的解密公式为P=CK-1mod26。

代码如下:

package com.general.encryanddecode;

import java.util.Arrays;
import java.util.Random;

/**
* Hill算法
* 希尔密码(Hill Cipher)是运用基本矩阵论原理的替换密码,由Lester S.Hill在1929年发明.下面实现简单的Hill算法的加密解密
*
* @author generalandroid
* **/
public class HillTest {
    private int[][] k= new int[3][3];//{17,17,5,21,18,21,2,2,19};
    /**逆矩阵**/
    private int[][] d_k=new int[3][3];//{4,9,15,15,17,6,24,0,17}
    private String table="ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    private int p_length;
    private String pContent;
    private String cContent;
    private int[] p_int;
    private int[] c_int;
    public HillTest(String cotent){
        System.out.println("原文:"+cotent);
        pContent=cotent;
        p_length=pContent.length();
        initKAndDK();
        initPContent();
    }
    private void initKAndDK(){
        //正向矩阵
        k[0][0]=17;k[0][1]=17;k[0][2]=5;
        k[1][0]=21;k[1][1]=18;k[1][2]=21;
        k[2][0]=2; k[2][1]=2; k[2][2]=19;
        //逆向矩阵
        d_k[0][0]=4; d_k[0][1]=9; d_k[0][2]=15;
        d_k[1][0]=15;d_k[1][1]=17;d_k[1][2]=6;
        d_k[2][0]=24;d_k[2][1]=0; d_k[2][2]=17;
    }
    //对明文做初始处理
    private void initPContent(){
        if(p_length%3==2){
            pContent=pContent+"Z";
        }else if(p_length%3==1){
            pContent=pContent+"ZZ";
        }
        if(p_int==null){

            p_int=new int[pContent.length()];
        }
        int i=0;
        System.out.println(pContent.toCharArray());
        for(char c:pContent.toCharArray()){
            p_int[i]=table.indexOf(c);
            i++;
        }
        System.out.println("p_int="+Arrays.toString(p_int));
    }
    private void encrypt(){
        if (c_int==null){
            c_int=new int[pContent.length()];
        }
        for(int i=0;i<p_int.length;i=i+3){
            c_int[i]=(p_int[i]*k[0][0]+p_int[i+1]*k[1][0]+p_int[i+2]*k[2][0])%26;
            c_int[i+1]=(p_int[i]*k[0][1]+p_int[i+1]*k[1][1]+p_int[i+2]*k[2][1])%26;
            c_int[i+2]=(p_int[i]*k[0][2]+p_int[i+1]*k[1][2]+p_int[i+2]*k[2][2])%26;
        }
        System.out.println("c_int="+Arrays.toString(c_int));
        StringBuilder c_content=new StringBuilder();
        for(int c:c_int){
            c_content.append(table.charAt(c));
        }
        cContent=c_content.toString();
        System.out.println("密文:"+cContent);

    }
    private void decrypt(){

        for(int i=0;i<p_int.length;i=i+3){
            p_int[i]=(c_int[i]*d_k[0][0]+c_int[i+1]*d_k[1][0]+c_int[i+2]*d_k[2][0])%26;
            p_int[i+1]=(c_int[i]*d_k[0][1]+c_int[i+1]*d_k[1][1]+c_int[i+2]*d_k[2][1])%26;
            p_int[i+2]=(c_int[i]*d_k[0][2]+c_int[i+1]*d_k[1][2]+c_int[i+2]*d_k[2][2])%26;
        }

        StringBuilder p_content=new StringBuilder();
        for(int c:p_int){
            p_content.append(table.charAt(c));
        }
        pContent=p_content.toString();
        System.out.println("明文:"+pContent.substring(0,p_length));
    }

    public static void main(String[] args){

        HillTest hillTest= new HillTest("GENERALANDROIDGEEKAXYEN");
        hillTest.encrypt();
        hillTest.decrypt();
    }

}
/**
原文:GENERALANDROIDGEEKAXYEN
GENERALANDROIDGEEKAXYENZ
p_int=[6, 4, 13, 4, 17, 0, 11, 0, 13, 3, 17, 14, 8, 3, 6, 4, 4, 10, 0, 23, 24, 4, 13, 25]
c_int=[4, 18, 23, 9, 10, 13, 5, 5, 16, 20, 21, 14, 3, 20, 9, 16, 4, 8, 11, 20, 3, 1, 14, 14]
密文:ESXJKNFFQUVODUJQEILUDBOO
明文:GENERALANDROIDGEEKAXYEN

* **/

多表代替密码

对简单单表代替的改进方法是在明文消息中采用不同的单表代替。这种方法一般称之为多表代替密码 。所有这些方法都有以下的共同特征:(1)采用相关的单表代替规则集(2)密钥决定给定变换的具体规则。

Vigenere密码

Vigenere密码:多表代替密码中最著名的和最简单的是Vigenere密码。它的代替规则集由26个Caesar密码的代替表组成,其中每一个代替表是对明文字母表移位0~25次后得到的代替单表。每个密码由一个密钥字母来表示,这个密钥字母用来代替明文字母a,故移位3次的Caesar密码由密钥值3来代表。
代码如下:

package com.general.encryanddecode;

import java.util.Arrays;

/***
 * 多表代替密码-Vigenere
 * 它的代替规则集由26个Caesar密码的代替表组成,其中每一个代替表是对明文字母表移位0~25次后得到的代替单表。每个密码由一个密钥字母来表示
 * ,这个密钥字母用来代替明文字母a,故移位3次的Caesar密码由密钥值3来代表。
 * @author generalandroid
 */
public class VigenereTest {

    private String key;
    private String pContent;
    private String cContent;
    private int[] key_index;
    private char[] p_content;
    private char[] c_key;
    private char[] c_content;
    public VigenereTest(String key,String content){
        this.key=key;
        this.pContent=content;
        System.out.println("密钥:"+key);
        System.out.println("原文:"+pContent);
        this.key_index=new int[pContent.length()];
        this.p_content=pContent.toCharArray();
        this.c_content=new char[p_content.length];
        initKey();

    }

    public static void main(String[] args){


        VigenereTest vigenereTest=new VigenereTest("GEAKAAZEN","GENERALANDROIDGEAKAAZEN");
        vigenereTest.encrypt();
        vigenereTest.decrypt();

    }
    /**重新构建密钥词**/
    private void initKey(){
        key=key+pContent.substring(0,pContent.length()-key.length());
        System.out.println("转换之后的key:"+key);
        c_key=key.toCharArray();
        for(int i=0;i<c_key.length;i++){
            key_index[i]=c_key[i]-'A';
        }
        System.out.println("Caesar 代替集:"+ Arrays.toString(key_index));


    }

    public void encrypt(){
        for(int i=0;i<p_content.length;i++){
            int p_index=p_content[i]+key_index[i];
           if(p_index>90){
               p_index=p_index-90+'A';
               //System.out.println("p_index:"+p_index);
           }
            c_content[i]=(char)p_index;
        }
        System.out.println("密文:"+new String (c_content));
    }
    public void decrypt(){
        char []t=new char[p_content.length];
        for(int i=0;i<c_content.length;i++){
            int c_index=c_content[i]-key_index[i];
           if(c_index<65){
               c_index=c_index+90-'A';
               //System.out.println("c_index:"+c_index);
           }
            t[i]=(char)c_index;
        }
        System.out.println("明文:"+new String (t));
    }

}
/**
 *
 密钥:GEAK
 原文:GENERALANDROIDGEAKAAZEN
 转换之后的key:GEAKGENERALANDROIDGEAKA
 Caesar 代替集:[6, 4, 0, 10, 6, 4, 13, 4, 17, 0, 11, 0, 13, 3, 17, 14, 8, 3, 6, 4, 0, 10, 0]
 密文:MINOXEYEFDDOVGXSINGEZON
 明文:GENERALANDROIDGEAKAAZEN



 密钥:GEAKAAZEN
 原文:GENERALANDROIDGEAKAAZEN
 转换之后的key:GEAKAAZENGENERALANDROID
 Caesar 代替集:[6, 4, 0, 10, 0, 0, 25, 4, 13, 6, 4, 13, 4, 17, 0, 11, 0, 13, 3, 17, 14, 8, 3]
 密文:MINORALEBJVCMUGPAXDROMQ
 明文:GENERALANDROIDGEAKAAAEN

 *
 * **/

Vernam密码

Vernam密码:Vernam密码属于流密码,其加密过程是明文与密钥按位异或,解密过程是密文与密钥按位异或。
这里写图片描述
其中:pi是明文第i个二进制位,ki是密钥第i个二进制位,ci是密文第i个二进制位。

代码如下:

package com.general.encryanddecode;

import org.omg.Messaging.SYNC_WITH_TRANSPORT;

import java.util.Arrays;

/**
 *
 * Vernam密码:Vernam密码属于流密码,其加密过程是明文与密钥按位异或,解密过程是密文与密钥按位异或。
 * @author generalandroid
 * **/
public class VernamTest {
    private String key;
    private String pContent;
    private String cContent;
    private char[] c_key;
    private char[] c_content;
    private char[] p_content;
    public VernamTest(String key,String content){
        this.key=key;
        this.pContent=content;
        System.out.println("密钥:"+key);
        System.out.println("原文:"+pContent);
        initKey();
        c_key=this.key.toCharArray();
        c_content=new char[pContent.length()];
        p_content=pContent.toCharArray();
    }

    public  static void main(String[] args){
        VernamTest vernamTest=new VernamTest("GEEK","GENERALANDROID");
        vernamTest.encrypt();
        vernamTest.decrypt();
    }
    /**重新构建密钥词**/
    private void initKey(){
        key=key+pContent.substring(0,pContent.length()-key.length());
        System.out.println("转换之后的key:"+key);
    }
    public void encrypt(){
        for(int i=0;i<p_content.length;i++){
            c_content[i]=(char) (c_key[i]^p_content[i]);
        }
        System.out.println("密文:"+new String(c_content));
    }
    public void decrypt(){
        char[] t=new char[c_content.length];
        for(int i=0;i<c_content.length;i++){
            t[i]=(char) (c_key[i]^c_content[i]);
        }
        System.out.println("明文:"+new String(t));
    }

}

置换技术

前面几种简单的加密技术都是使用的代替技术,即将明文的内容代替为其他内容 ,这里面会出现明文中没有的元素,而置换技术强调的是对明文的重排列,故不会出现明文中没有的元素。
栅栏技术:最简单的置换技术例子是栅栏技术,按照对角线的顺序写出明文,
而按行的顺序读出作为密文。举个例子:GENERALANDROID写成如下
GNRLNRI
EEAADOD
则密文就为:GNRLNRIEEAADOD
一个更复杂的置换技术的例子:把消息一行一行地写成矩形块,然后按列读
出 ,但是把列的次序打乱。列的次序就是算法的密钥。
为了安全,一般对明文进行多次置换来保护信息。

要说的内容就这么多,如果文中有不对的地方,麻烦指出,如果喜欢我的文章,可以动动手指关注一下,赞一下,我会有更大的动力写出更多的文章,转载请注明出处:http://blog.csdn.net/android_jiangjun/article/details/79131386

更多文章

对于加密解密的初步了解
传统加密技术

参考资料

《密码编码学与网络安全》第六版

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值