在上篇文章中,講述了一些加密解密的概念以及Caesar、單表替換密碼、Playfair密碼。在這篇文章中主要涉及Hill密碼,Vigenere密碼,Vernam密碼,置換技術。java
希爾密碼(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 用行向量和矩陣表示以下: android
這裏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)密鑰決定給定變換的具體規則。bash
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密碼屬於流密碼,其加密過程是明文與密鑰按位異或,解密過程是密文與密鑰按位異或。 app
其中:pi是明文第i個二進制位,ki是密鑰第i個二進制位,ci是密文第i個二進制位。代碼以下:dom
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 一個更復雜的置換技術的例子:把消息一行一行地寫成矩形塊,而後按列讀 出 ,可是把列的次序打亂。列的次序就是算法的密鑰。 爲了安全,通常對明文進行屢次置換來保護信息。ui
要說的內容就這麼多,若是文中有不對的地方,麻煩指出,若是喜歡個人文章,能夠動動手指關注一下,贊一下,我會有更大的動力寫出更多的文章,轉載請註明出處:http://blog.csdn.net/android_jiangjun/article/details/79131386this
《密碼編碼學與網絡安全》第六版