栅栏密码
实验目的:理解典型移位密码的加解密原理
实验原理:
栅栏密码属于古典密码中最经典的移项式密码,同之前讲到的凯撒密码等替 换式密码代表了密码学中最重要的两个概念(扩散和混淆)
我们以2栏栅栏密码为例来讲解它的加密和解密过程。
加密过程:
明文:THERE_IS_A_CIPHERK
两个一组,得到:(TH) (ER) (E_) (IS) (_A) (_C) (IP) (HE) (RK)
先每组中取出第一个字母:TEEI__IHR
再从每组中取出第二个字母:HR_SACPEK
连在一起得到密文:TEEI__IHRHR_SACPEK
解密过程:
而解密的时候,我们先把密文从中间分开,变为两行:
TEEI__IHR
HR_SACPEK
再按上下上下的顺序组合起来:
THERE_IS_A_CIPHERK
那么如何将2栏密码扩展到多栏呢?在之前的明文中,CIPHER这个单词之后加了一个下划线,目的就是为了让明文字符串的长度是2的倍数,栅栏密码的分栏的一个前提就是分的栏数需是明文长度的因数,这样才会使得分出来的每个栏长度都一样。
对于多栏,我们还是用上面的例子来讲解。
上面的明文字符串(THERE-IS_A_CIPHER-)的长度是18=233 ,所以我们可以把它分为2,3,4,6,9栏,这里我们以6栏为例。
以每个元素相隔6个字符分割出栅栏。
第一栏:TII
第二栏:HSP
第三栏:E_H
第四栏:RAE
第五栏:E_R
第六栏:-C-
连接在一起得到密文:TIIHSPE_HRAEE_R-C-
实验要求:
1.解密文本:_pry_iosncta_aguccropi_osieyghsrr_e-
2.将所有可能分的栏,均恢复出相应的明文
import java.util.ArrayList;
//栅栏密码
public class Demo {
public static void main(String[] args) {
String str = "_pry_iosncta_aguccropi_osieyghsrr_e-";
//通过字符长度的因数判断可设置的分栏数n
ArrayList<Integer> n = new ArrayList<>();
for(int x=2;x<str.length();x++) {
if(str.length()%x == 0) {
n.add(x);
}
}
//输出所有分栏可能
for(int i:n) {
System.out.println("可分为"+i+"栏:");
//设置二维字符数组分别存储各分栏字符
char[][] num = new char[i][str.length()/i];
//遍历打印i栏
for(int j=0;j<i;j++) {
//cut为各分栏字符串
String cut = str.substring(j*str.length()/i, j*str.length()/i+str.length()/i);
//num数组每行存储各分栏字符串cut
num[j] = cut.toCharArray();
System.out.println(cut);
};
//解密过程实现
//设置end集合存储存储Character对象取得解密结果
ArrayList<Character> end = new ArrayList<>();
//通过二维数组存储每个字符,使各字符可定位
for(int k = 0; k < num.length; k++) {
for(int j = 0; j <num[k].length; j++) {
for(int m = 0; m < num.length; m++) {
end.add(num[m][j]);
}
}
}
//输出结果
System.out.println("--------------------");
System.out.println(i+"分栏连接在一起得到密文为:");
//遍历截取解密结果并输出
for(int y=0;y<end.size()/i;y++) {
//字符不换行衔接打印
System.out.print(end.get(y));
}
System.out.println();
System.out.println("--------------------");
}
}
}