网络信息安全 古典密码(仿射、PlayFair)DES RSA

 

网络信息安全实验报告

课程名称

网络信息安全

实验项目名称

古典密码、对称密码、非对称密码

实验时间

(日期及节次)

周五三、四节

专业

软件工程

学生所在学院

软件学院

年级

2020

学号

哈哈

姓名

指导教师

我老师

实验室名称

计算机专业实验室(4-138)

实验成绩

预习情况

操作技术

实验报告

附加:综合创新能力

实验

综合成绩

         

教师签字

 

 

黑龙江大学计算机科学技术学院、软件学院

目录

实验一 古典算法 4

实验要求 4

实验环境 4

实验步骤 4

仿射算法 4

PLAYFAIR算法 6

核心代码讲解 8

仿射算法 8

PLAYFAIR算法 8

代码演示 11

仿射算法 11

PLAYFAIR算法 12

实验二 DES 13

实验要求 13

实验环境 13

实验步骤 / 核心代码讲解 13

DES 13

代码演示 18

DES 18

实验三 RSA 19

实验要求 19

实验环境 19

实验步骤 19

RSA 19

核心代码讲解 20

代码演示 22

附录 24

代码总览 24

实验一源代码 24

仿射 24

PLAYFAIR 28

实验二源代码 37

实验三源代码 49

实验一 古典算法

实验要求

掌握古典密码中的单表代替和多表代替的加密解密过程。

在单表代替中可以实现使用密钥的加密方法(或仿射密码);

在多表代替中可以实现PlayFair密码。

实验环境

Windows11

IDEA

实验步骤

仿射算法

仿射密码是一种替换密码。它是利用加密函数一个字母对一个字母的加密。加密函数是E(x)= (ax + b) (mod m),其中,a和m互质,m是字符集的大小。(例如,26即是以26个字母作为编码,当m是26时,a必须是1,3,5,7,9,11,15,17,19,21,23,25其中之一)解密函数为D(x) = a-1(x - b) (mod m),其中a-1是a在Zm群的乘法逆元。

乘法逆元即在G中任意一个元素a,都有唯一逆元存在于G中,具有性质aa` = a`a = e。乘法逆元通过拓展的欧几里得算法求得。

PLAYFAIR算法

Playfair算法基于一个5*5的字母矩阵,该矩阵使用一个关键词构造,方法是按从左到右、从上到下顺序,填入关键词的字母(去除重复字母)后,将字母表其作余字母填入。

例如: 关键词取:monarchy时,字母矩阵为下图如示(矩阵只能放25个字母,I与J视为同一个字母)

加密规则如下所示:

最后根据图表查找的办法两个两个进行加密和解密。解密的过程就是将加密的方法反过来进行即可。

IMG_256

核心代码讲解

仿射算法

加密过程中首先将输入的明文转化为小写字母后并去掉空格,目的是作为下一步的输入避免字符串的空出使代码出现错误;再将明文转化为字符串数组,通过强制转换成int类型的数组,这样就可以用数字表示需要加密的字符,最后将得到的数组数组转化为字符后拼接在一起,就形成了密文。

PLAYFAIR算法

构建矩阵的基本思路就是一句话:判断之前的数组中是否包含该字符,已经包含了就不加入,不包含就按序加入即可,只需要在if条件里加i和j视为一个就好。

通过明文和前面构造出的加密矩阵,可以经过查找后得到密文,查找的过程首先要获取行和列,其次分为三种情况,相同行、相同列、不同行列,同一行中还分为第一个字母在最后一个(操作是直接将第一个字母转化为该行第一个)和第二个字母在最后一个(操作是直接将第二个字母转化为该行第一个),同一列同理,如果不同行不同列直接交换即可。

代码演示

仿射算法

PLAYFAIR算法

实验二 DES

实验要求

掌握DES加密解密流程

完成DES中的每个模块:

扩展模块

压缩模块

子密钥产生模块

等,并将各个模块组合在一起完成相应的加密的功能,并进行相应的解密。

实验环境

Windows11

IDEA

实验步骤 / 核心代码讲解

DES

DES算法为密码体制中的对称密码体制,又被称为美国数据加密标准,2000年以前一直是业界的标准。DES是一个分组加密算法,以64位为分组对数据加密(每次处理固定长度的数据段,称之为分组)。如果加密的数据长度不是64位的倍数,可以按照某种具体的规则来填充位。

DES的明文长为64位,密钥长64位,但密钥事实上是56位参与DES运算(第8、16、24、32、40、48、56、64位是校验位,使得每个密钥都有奇数个1),分组后的明文组和56位的密钥按位替代或交换的方法形成密文组。DES算法具体通过对明文进行一系列的排列和替换操作来将其加密。DES 解密算法与加密算法完全相同,只需要将子密钥的使用顺序反过来就行了。

DES加密过程:

IMG_256

IP置换:原来的58位现在排在第一位,50位排在第二位…以此类推,在DES算法中会用到很多很多很多很多次置换,都是这个思路。该过程输入是64位的分组,IP置换以后得到的是一个 64 位的输出。

子密钥获取:根据密钥选择置换表RT_Key,将 64 位输入密钥变成 56 位。(去掉了奇偶校验位)将RT_Key置换得到的 56 位密钥(其实这也是一种压缩置换,特指去掉了奇偶校验位的过程),分为前28位 C0 和后28位 D0,分别对它们进行循环左移,C0左移得到 C1,D0 左移得到 D1。将 C1 和 D1 合并,然后通过RT_Compress表进行压缩置换,得到当前这一轮的 48 位子密钥 K1 。然后对 C1 和 D1 进行左移和压缩置换,获取下一轮的子密钥……一共进行16轮,得到 16 个 48 位的子密钥。

IMG_256

在子密钥获取的部分中最后一段代码的编写是为了表明所运行的是加密还是解密,利用三元表达式,如果是加密就顺序使用16个密钥,如果是解密就将密钥倒序然后使用。

F密码函数:

IMG_256

密码函数f(R, K)接受两个输入:32 位的R数据(明文的右半部分)和 48 位的子密钥(Ki)。然后通过表 E 进行扩展置换,将输入的 32 位数据扩展为 48 位;将扩展后的 48 位数据与 48 位的子密钥进行异或运算;将异或得到的 48 位数据分成 8 个 6 位的块,每一个块通过对应的一个 S 表产生一个 4 位的输出。其中,每个 S 表都是 4 行 16 列。具体的置换过程如下:把 6 位输入中的第 1 位和第 6 位取出来行成一个两位的二进制数 x ,作为 Si 表中的行数(0~3);把 6 位输入的中间 4 位构成另外一个二进制数 y,作为 Si 表的列数(0~15);查出 Si 表中 x 行 y 列所对应的整数,将该整数转换为一个 4 位的二进制数。把通过 S 表置换得到的 8 个 4 位连在一起,形成一个 32 位的数据。然后将该 32 位数据通过表 P 进行置换(称为P-置换),置换后得到一个仍然是 32 位的结果数据,这就是f(R, K)函数的输出。

代码演示

DES

实验三 RSA

实验要求

掌握RSA的加密过程和解密过程。

实现求逆的算法(扩展的欧几里德算法)。

使用随机函数产生随机数,并进行加密和解密。

加密过程:私有密钥随机产生,公开密钥利用求逆算法给出,明文键盘输入,密文利用RSA算法输出。

解密过程:密文键盘输入,私有密钥键盘输入,利用RSA解密算法输出明文。

实验环境

Windows11

IDEA

实验步骤

RSA

RSA加密是一种非对称加密。可以在不直接传递密钥的情况下,完成解密。这能够确保信息的安全性,避免了直接传递密钥所造成的被破解的风险。是由一对密钥来进行加解密的过程,分别称为公钥和私钥。两者之间有数学相关,该加密算法的原理就是对一极大整数做因数分解的困难性来保证安全性。通常个人保存私钥,公钥是公开的。

进行RSA的准备工作,生成公钥和私钥:

IMG_256

得到公钥和私钥以后,通过输入明文(字符需要转换为数字),利用模运算的性质进行加密:y=x^e mod n ,y即为加密后的密文(数字)。再通过私钥可以进行解密,同样是进行模运算,计算明文为: x=y^d mod n。

核心代码讲解

在最开始,需要将字符明文转换为数字,首先定义泛型为Int的动态数组,再将明文的编码转换为UTF-8编码,进而进行迭代循环,将字符逐个转换为int型后加入定义的动态数组。

然后随机选取两个素数,判断素数就是遍历到该数字的所有数字看是否能被整除,由于根据算法要求的数字必须大,所以条件加上了需要大于1000。

加密过程如下:通过公式BigInteger ^ E % N 计算每个数字的转化后的密文,返回到主函数后,将逐个添加到密文的动态数组中。

在加密的主函数中,运用了不同于FOR循环迭代器循环方法,思路和效率别无二致,就是想试一下可不可以用,首先定义密文的动态数组,然后定义明文的迭代器,将明文和公钥进行加密,循环条件使用的是迭代器中的hasNext()方法,作用是判断集合中是否有元素,与while循环使用正好可以达到for的效果。

代码演示


附录

代码总览

实验一源代码

仿射

package 古典.仿射;

import java.util.Scanner;

/**
* 仿射密码的加密和解密
* n = 26
*/
public class Affine {

// n
public static final int n = 26;

public static void main(String[] args) {
Scanner input1 = new Scanner(System.in);
System.out.println("请输入密钥K1:");
int k1 = input1.nextInt();
System.out.println("请输入密钥K2:");
int k2 = input1.nextInt();

Scanner input2 = new Scanner(System.in);
System.out.println("请输入明文:");
String plaintext = input2.nextLine();

//加密过程
String ciphertext;
ciphertext = encryptionOperation(k1, k2, plaintext);
System.out.println("\n密文:" + ciphertext);

System.out.println("--------------------------");

//解密过程
String decrypttext = Decrypt(k1, k2, ciphertext);
System.out.println("解密结果:" + decrypttext);

}

/*
* 加密:C= Ek(m)=(k1m+k2) mod n
*/
public static String encryptionOperation(int k1, int k2, String express){
//转化成小写并去除空格
String express2 = express.toLowerCase().replaceAll(" ", "");
System.out.println("转化以后的明文:" + express2);
char[] expressChar = express2.toCharArray(); //转化为字符串数组
int[] jiamiChar = new int[express2.length()]; //加密以后的数字数组

//将字母转换成数字表示
System.out.print("转换之前的数字密文:");
for (int i=0;i<express2.length();i++){
jiamiChar[i] = ((expressChar[i] - 97) * k1 + k2) % n; //97 = a
System.out.print(jiamiChar[i] + " ");
}

//将数字转换成密文拼接在一起
StringBuffer miwen = new StringBuffer();
for(int j=0;j<jiamiChar.length;j++){
miwen = miwen.append((char)(jiamiChar[j] + 65));
}
return miwen.toString();
}

/*
* 解密 E(x) = k1-1(x-k2) (mod n)
*/
public static String Decrypt(int k1, int k2, String ciphertext){

//1.求出k3 { (k3 * k1) mod 26 = 1 } 乘法逆元
int k3 = 0;
for (int i = 2;;i++){
if((i*k1) % n == 1){
k3 = i;
break;
}
}
System.out.println("k3为k1模26的乘法逆元:" + k3);

//求出明文 { M= Dk(c)=k3(c- k2) mod n }
StringBuffer mingwen = new StringBuffer();
for (int j=0;j<ciphertext.length();j++){
int c = ((k3 * (ciphertext.charAt(j) - 65 - k2))) % 26; //A = 65
if (c < 0){
c = c + 26;
}
mingwen.append((char)( c + 65));
}

return mingwen.toString();
}
}

// 7 3 china

 

PLAYFAIR

package 古典.Playfair;

import java.nio.CharBuffer;


public class PlayFair {
/*
* 加密算法
*/
public static char[] encode(char[] plain, char[] key, char replace){
// 构造矩阵
char[][] matrix = constructMatrix(key);
// 为缓冲区分配空间
CharBuffer xplain = CharBuffer.allocate(plain.length * 2);
// 重新生成明文
int len = 0;
int i;
for(i = 0; i < plain.length - 1; i++){
xplain.append(plain[i]);
if(i != plain.length - 1){
//如果 前后两个字母相同
if(plain[i] == plain[i + 1]){
xplain.append(replace);
}else{
xplain.append(plain[i + 1]);
i++;
}
}else{
xplain.append(replace);
}
len += 2;
}
//如果 剩余最后一个字符是单个的
if(i == plain.length - 1){
xplain.append(plain[i]);
xplain.append(replace);
len += 2;
}
char[] xxplain = new char[len];
xplain.position(0);
xplain.get(xxplain);
System.out.println("整理后的明文: " + new String(xxplain));

//加密过程
char[] cipher = getCipher(xxplain, matrix);
return cipher;
}


/*
* 根据密文和密钥解密密文并返回生成的明文
*/
public static char[] decode(char[] cipher, char[] key){
// 构造解密矩阵
char[][] matrix = constructMatrix(key);
//解密过程
char[] plain = getPlain(cipher, matrix);
return plain;
}


/*
* 根据密文和解密矩阵返回明文
*/
private static char[] getPlain(char[] cipher, char[][] matrix){
char[] plain = new char[cipher.length];
int index = 0;
for(int i = 0; i < cipher.length; i += 2){
int row1, row2, col1, col2;
String[] pos1, pos2;
pos1 = getPosition(matrix, cipher[i]);
pos2 = getPosition(matrix, cipher[i + 1]);
if(pos1 == null || pos2 == null){
throw new RuntimeException("密文中包含无效字符!");
}
row1 = Integer.parseInt(pos1[0]);
col1 = Integer.parseInt(pos1[1]);
row2 =Integer.parseInt(pos2[0]);
col2 = Integer.parseInt(pos2[1]);
if(row1 == row2){
// 同一行的情况
if(col1 == 0){
plain[index++] = matrix[row1][matrix[0].length - 1];
plain[index++] = matrix[row1][col2 - 1];
}else if(col2 == 0){
plain[index++] = matrix[row1][col1 - 1];
plain[index++] = matrix[row1][matrix[0].length - 1];
}else{
plain[index++] = matrix[row1][col1 - 1];
plain[index++] = matrix[row1][col2 - 1];
}

}else if(col1 == col2){
// 同一列的情况
if(row1 == 0){
plain[index++] = matrix[matrix.length - 1][col1];
plain[index++] = matrix[row2 - 1][col1];
}else if(row2 == 0){
plain[index++] = matrix[row1 - 1][col1];
plain[index++] = matrix[matrix.length - 1][col1];
}else{
plain[index++] = matrix[row1 - 1][col1];
plain[index++] = matrix[row2 - 1][col2];
}
}else{
//不同行不同列
plain[index++] = matrix[row1][col2];
plain[index++] = matrix[row2][col1];
}
}
return plain;
}


/*
* 根据明文和加密矩阵得到密文
*/
private static char[] getCipher(char[] plain, char[][] matrix){
char[] cipher = new char[plain.length];
int index = 0;
for(int i = 0; i < plain.length - 1; i += 2){ //每隔两个字符取一次
int row1, row2, col1, col2;
String[] pos1, pos2;
pos1 = getPosition(matrix, plain[i]);
pos2 = getPosition(matrix, plain[i + 1]);
if(pos1 == null || pos2 == null){
throw new RuntimeException("明文中包含无效字符!");
}
// row 获取行 col 获取列
row1 = Integer.parseInt(pos1[0]);
col1 = Integer.parseInt(pos1[1]);
row2 =Integer.parseInt(pos2[0]);
col2 = Integer.parseInt(pos2[1]);
// System.out.println(row1+"-"+row2);
// System.out.println(col1+"-"+col2);
// System.out.println("====");
if(row1 == row2){
// 同一行的情况

//1在最后一个
if(col1 == matrix[0].length - 1){
cipher[index++] = matrix[row1][0];
cipher[index++] = matrix[row1][col2 + 1];
}
//2在最后一个
else if(col2 == matrix[0].length - 1){
cipher[index++] = matrix[row1][col1 + 1];
cipher[index++] = matrix[row1][0];
}else{
cipher[index++] = matrix[row1][col1 + 1];
cipher[index++] = matrix[row1][col2 + 1];
}
}else if(col1 == col2){
//同一列的情况
if(row1 == matrix.length - 1){
cipher[index++] = matrix[0][col1];
cipher[index++] = matrix[row2 + 1][col1];
}else if(col2 == matrix.length - 1){
cipher[index++] = matrix[row1 + 1][col1];
cipher[index++] = matrix[0][col1];
}else{
cipher[index++] = matrix[row1 + 1][col1];
cipher[index++] = matrix[row2 + 1][col2];
}
}else{
cipher[index++] = matrix[row1][col2];
cipher[index++] = matrix[row2][col1];
}
}
return cipher;
}


/*
* 返回字符在矩阵中的位置
*/
private static String[] getPosition(char[][] matrix, char ch){
String[] pos = new String[]{null, null};
for(int i = 0; i < matrix.length; i++){
for(int j = 0; j < matrix[0].length; j++){
if((matrix[i][j] == ch) || (matrix[i][j] == 'j' && ch == 'i') || (matrix[i][j] == 'i' && ch == 'j')){
pos[0] = i + "";
pos[1] = j + "";
return pos;
}
}
}
return null;
}


/*
*用密钥构造矩阵
*/
private static char[][] constructMatrix(char[] key){
char[][] matrix = new char[5][5];
CharBuffer buf = CharBuffer.allocate(25); //分配新可变char缓冲区
buf.append(key[0]);
System.out.println(key[0]);
// 移除密钥中重复的字符
for(int i = 1; i < key.length; i++){
if(exists(buf.array(), key[i])){
buf.append(key[i]);
// System.out.println(key[i]);
}
}
// 将字母表中剩余的字符加入
for(int i = 0; i < 26; i++){
char ch = (char) ('a' + i);
if(exists(buf.array(), ch)){
buf.append(ch);
}
}

//构造矩阵过程
int index = 0;
buf.position(0);
System.out.println("5*5矩阵:");
for(int i = 0; i < matrix.length; i++){
for(int j = 0; j < matrix[0].length; j++){
if(index != buf.length()){
matrix[i][j] = buf.get(index++);
System.out.print(matrix[i][j] + "\t");
}
}
System.out.println();
}
buf.clear();
return matrix;
}


/*
* 判断是否包含字符
*/
private static boolean exists(char[] buf, char c) {
for(int i = 0; i < buf.length; i++){
//如果当前字符存在就不加入(将i和j视为同一个字符)
if(buf[i] == c || (c == 'j' && buf[i] == 'i') || (c == 'i' && buf[i] == 'j'))
return false;
}
return true;
}
}

package 古典.Playfair;

import java.util.Scanner;

public class PFtest {
public static void main(String[] args) {

Scanner input = new Scanner(System.in);

System.out.println("请输入明文:");
String strming = input.nextLine();
String plain = strming.replaceAll(" ", ""); // 明文,去掉空格

System.out.println("请输入密钥:");
String strkey = input.nextLine();
String key = strkey.replaceAll(" ", ""); // 密钥,去掉空格

char replace = 'x'; // 填充字符
System.out.println("明文: " + plain + " \n密钥: " + key + "\n填充字符: " + replace);

System.out.println("-------------------------------");

//加密过程
System.out.println("加密:");
char[] cipher = PlayFair.encode(plain.toLowerCase().toCharArray(), key.toLowerCase().toCharArray(), replace);

//给字符串每两个字符添加一个空格
String regex = "(.{2})";
String UP =new String(cipher).toUpperCase();
System.out.println("加密密文: " + UP.replaceAll(regex,"$1 "));

System.out.println("-------------------------------");

//解密过程
System.out.println("解密:");
char[] plain1 = PlayFair.decode(cipher, key.toLowerCase().toCharArray()); // 输入密文和密钥解密
System.out.println("解密结果:" + new String(plain1));

}
}

// playfair cipher
// PLAYFAIR IS A DIGRAM CIPHER

 

实验二源代码

package DES;


public class DES {

/**/
// Replacement Table(RT)IP置换表 输入64位的分组 IP置换后得到64位的输出
final static int[] RT_IP = { 58, 50, 42, 34, 26, 18, 10, 2,
60, 52, 44, 36, 28, 20, 12, 4,
62, 54, 46, 38, 30, 22, 14, 6,
64, 56, 48, 40, 32, 24, 16, 8,
57, 49, 41, 33, 25, 17, 9, 1,
59, 51, 43, 35, 27, 19, 11, 3,
61, 53, 45, 37, 29, 21, 13, 5,
63, 55, 47, 39, 31, 23, 15, 7 };

// 密钥置换表,64位密钥去掉校验位,选择剩下的56位作为新的密钥 去掉校验位的同时还打乱了顺序
final static int[] RT_Key = {57, 49, 41, 33, 25, 17, 9,
1, 58, 50, 42, 34, 26, 18,
10, 2, 59, 51, 43, 35, 27,
19, 11, 3, 60, 52, 44, 36,
63, 55, 47, 39, 31, 23, 15,
7, 62, 54, 46, 38, 30, 22,
14, 6, 61, 53, 45, 37, 29,
21, 13, 5, 28, 20, 12, 4};

// 压缩置换,将56位密钥压缩成48位子密钥
final static int[] RT_Compress = {14, 17, 11, 24, 1, 5,
3, 28, 15, 6, 21, 10,
23, 19, 12, 4, 26, 8,
16, 7, 27, 20, 13, 2,
41, 52, 31, 37, 47, 55,
30, 40, 51, 45, 33, 48,
44, 49, 39, 56, 34, 53,
46, 42, 50, 36, 29, 32};

// 每轮左移的位数
final static int[] leftshiftBits = {1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1};

// 扩展置换表 RT_E,将32位扩展至48位
final static int[] RT_E = {32, 1, 2, 3, 4, 5,
4, 5, 6, 7, 8, 9,
8, 9, 10, 11, 12, 13,
12, 13, 14, 15, 16, 17,
16, 17, 18, 19, 20, 21,
20, 21, 22, 23, 24, 25,
24, 25, 26, 27, 28, 29,
28, 29, 30, 31, 32, 1};

// S盒,每个S盒Si是4x16的置换表,6位 -> 4位
final static int[][][] S_BOX ={
{
{14,4,13,1,2,15,11,8,3,10,6,12,5,9,0,7},
{0,15,7,4,14,2,13,1,10,6,12,11,9,5,3,8},
{4,1,14,8,13,6,2,11,15,12,9,7,3,10,5,0},
{15,12,8,2,4,9,1,7,5,11,3,14,10,0,6,13}
},
{
{15,1,8,14,6,11,3,4,9,7,2,13,12,0,5,10},
{3,13,4,7,15,2,8,14,12,0,1,10,6,9,11,5},
{0,14,7,11,10,4,13,1,5,8,12,6,9,3,2,15},
{13,8,10,1,3,15,4,2,11,6,7,12,0,5,14,9}
},
{
{10,0,9,14,6,3,15,5,1,13,12,7,11,4,2,8},
{13,7,0,9,3,4,6,10,2,8,5,14,12,11,15,1},
{13,6,4,9,8,15,3,0,11,1,2,12,5,10,14,7},
{1,10,13,0,6,9,8,7,4,15,14,3,11,5,2,12}
},
{
{7,13,14,3,0,6,9,10,1,2,8,5,11,12,4,15},
{13,8,11,5,6,15,0,3,4,7,2,12,1,10,14,9},
{10,6,9,0,12,11,7,13,15,1,3,14,5,2,8,4},
{3,15,0,6,10,1,13,8,9,4,5,11,12,7,2,14}
},
{
{2,12,4,1,7,10,11,6,8,5,3,15,13,0,14,9},
{14,11,2,12,4,7,13,1,5,0,15,10,3,9,8,6},
{4,2,1,11,10,13,7,8,15,9,12,5,6,3,0,14},
{11,8,12,7,1,14,2,13,6,15,0,9,10,4,5,3}
},
{
{12,1,10,15,9,2,6,8,0,13,3,4,14,7,5,11},
{10,15,4,2,7,12,9,5,6,1,13,14,0,11,3,8},
{9,14,15,5,2,8,12,3,7,0,4,10,1,13,11,6},
{4,3,2,12,9,5,15,10,11,14,1,7,6,0,8,13}
},
{
{4,11,2,14,15,0,8,13,3,12,9,7,5,10,6,1},
{13,0,11,7,4,9,1,10,14,3,5,12,2,15,8,6},
{1,4,11,13,12,3,7,14,10,15,6,8,0,5,9,2},
{6,11,13,8,1,4,10,7,9,5,0,15,14,2,3,12}
},
{
{13,2,8,4,6,15,11,1,10,9,3,14,5,0,12,7},
{1,15,13,8,10,3,7,4,12,5,6,11,0,14,9,2},
{7,11,4,1,9,12,14,2,0,6,10,13,15,3,5,8},
{2,1,14,7,4,10,8,13,15,12,9,0,3,5,6,11}
}
};

// P置换,32位 -> 32位
final static int[] RT_P = {16, 7, 20, 21,
29, 12, 28, 17,
1, 15, 23, 26,
5, 18, 31, 10,
2, 8, 24, 14,
32, 27, 3, 9,
19, 13, 30, 6,
22, 11, 4, 25 };

// 逆IP置换表
final static int[] RT_InverseIP = {40, 8, 48, 16, 56, 24, 64, 32,
39, 7, 47, 15, 55, 23, 63, 31,
38, 6, 46, 14, 54, 22, 62, 30,
37, 5, 45, 13, 53, 21, 61, 29,
36, 4, 44, 12, 52, 20, 60, 28,
35, 3, 43, 11, 51, 19, 59, 27,
34, 2, 42, 10, 50, 18, 58, 26,
33, 1, 41, 9, 49, 17, 57, 25};

/* DES算法过程 */

//生成 16个子密钥
public static StringBuffer[] GenerateSubKey(StringBuffer str, boolean flag) throws Exception{
//判断长度是否为64位
if(str.length()!=64){
throw new Exception("输入密钥长度不是64位!");
}
else {
//选择密钥
StringBuffer choosedKey = new StringBuffer();
for (int i = 0; i < RT_Key.length; i++) { //通过使用密钥置换表
choosedKey.append(str.charAt(RT_Key[i]-1));
}
//拆分密钥 分成左28和右28
StringBuffer leftString = new StringBuffer(choosedKey.substring(0,28));
StringBuffer rightString = new StringBuffer(choosedKey.substring(28,56));

//16次循环得到 16个子密钥
StringBuffer[] res = new StringBuffer[16];
for (int i = 0; i < 16; i++) {
int LeftshiftBit = leftshiftBits[i]; //左移位数
//两部分密钥分别左移
StringBuffer temp_left=new StringBuffer(leftString);
StringBuffer temp_right=new StringBuffer(rightString);

String temp1_left = temp_left.substring(0,LeftshiftBit);
String temp2_left = temp_left.substring(LeftshiftBit,temp_left.length());
String templeft = temp2_left+temp1_left;

String temp1_right = temp_right.substring(0,LeftshiftBit);
String temp2_right = temp_right.substring(LeftshiftBit,temp_right.length());
String tempright = temp2_right+temp1_right;

//压缩置换
StringBuffer temp = new StringBuffer(templeft);
StringBuffer input = temp.append(tempright);
StringBuffer subKey = new StringBuffer();
for (int k = 0; k < RT_Compress.length; k++) {
subKey.append(input.charAt(RT_Compress[k]-1)); //压缩置换表 将56压缩48位
}
res[i]=subKey;
}

//取 加密还是解密 密钥顺序相反
StringBuffer[] res_reverse = new StringBuffer[16];
for (int i = 0; i < res.length; i++) {
res_reverse[i]=res[res.length-i-1];
}
return flag?res:res_reverse;
}
}

//IP置换
public static StringBuffer IPReplacement(StringBuffer str){
StringBuffer res = new StringBuffer();
for (int i = 0; i < RT_IP.length; i++) {
res.append(str.charAt(RT_IP[i]-1)); // 进64输出64
}
return res;
}

//F密码函数
public static StringBuffer function(StringBuffer subKey, StringBuffer R) throws Exception { //子密钥和右铭文
//1.扩展置换(通过表 E 进行扩展置换,将输入的 32 位数据扩展为 48 位)
StringBuffer extendedString = new StringBuffer();
for (int i = 0; i < RT_E.length; i++) {
extendedString.append(R.charAt(RT_E[i]-1));
}
//2.异或操作(扩展后的 48 位数据与 48 位的子密钥)
StringBuffer xor = XOR(extendedString, subKey);
if(xor.length()!=48){
throw new Exception("异或结果不等于48位!");
}else{
//3.S盒
StringBuffer S_output =new StringBuffer();
for (int i = 0; i < 8; i++) {
//3.1 拆分为6位子串substring
String substring = xor.substring(6 * i, 6 * (i+1));
//3.2 将substring取0,5位为x;中间4位为y(二进制转换十进制)
int x=binaryToDecimal(substring.substring(0,1)+substring.substring(5,6));
int y=binaryToDecimal(substring.substring(1,5));
//3.3 从S盒取S[i][x][y]转化为4位输出
String s = Integer.toBinaryString(S_BOX[i][x][y]);
StringBuffer stringBuffer = new StringBuffer(s);
//3.4 输出未达到4位则在前补0,直到补齐4位
while(4-stringBuffer.length()!=0){
stringBuffer.insert(0,'0');
}
S_output.append(stringBuffer);
}
//4.P盒 (将该 32 位数据S_output通过表 P 进行置换)
StringBuffer res = new StringBuffer();
for (int i = 0; i < RT_P.length; i++) {
res.append(S_output.charAt(RT_P[i]-1));
}
return res;
}
}

//执行异或操作
public static StringBuffer XOR(StringBuffer L, StringBuffer output) throws Exception{

if(L.length()!=output.length()){
throw new Exception("两者长度不同,不能进行异或运算!");
}else{
StringBuffer res = new StringBuffer(L.length());
for (int i = 0; i < L.length(); i++) {
int temp =0;
if(L.charAt(i)!=output.charAt(i)){temp=1;}
res.append(temp);
}
return res;
}
}

//逆IP置换
public static StringBuffer ReverseIPReplacement(StringBuffer str){
StringBuffer res = new StringBuffer();
for (int i = 0; i < RT_InverseIP.length; i++) {
res.append(str.charAt(RT_InverseIP[i]-1));
}
return res;
}

//二进制转化为10进制
public static int binaryToDecimal(String str){
int len = str.length();
int res=0;
for (int i = 0; i < len; i++) {
res+=Integer.parseInt(String.valueOf(str.charAt(len-i-1)))*Math.pow(2,i);
}
return res;
}

//加密过程
public static StringBuffer Encryption(StringBuffer Plaintext, StringBuffer Key) throws Exception {
//1.IP置换
StringBuffer stringBuffer = IPReplacement(Plaintext);
StringBuffer Leftstring = new StringBuffer(stringBuffer.substring(0, 32));
StringBuffer Rightstring = new StringBuffer(stringBuffer.substring(32,64));
//2.获取子密钥
StringBuffer[] subKeys =GenerateSubKey(Key,true);
//3.for循环16轮
for (int i = 0; i < 16; i++) {
//3.1 f函数
StringBuffer f_output=function(subKeys[i],Rightstring);
//3.2 异或
StringBuffer temp=XOR(Leftstring,f_output);
//3.3 更新Li和Ri
Leftstring=Rightstring;
Rightstring=temp;
}
//4.左右互换
StringBuffer res = Rightstring.append(Leftstring);
//5.逆IP置换
res=ReverseIPReplacement(res);
return res;
}

//解密过程
public static StringBuffer Decryption(StringBuffer Ciphertext, StringBuffer Key) throws Exception {
//1.获取子密钥
StringBuffer[] subKeys =GenerateSubKey(Key,false);
//2.IP置换
StringBuffer stringBuffer = IPReplacement(Ciphertext);
StringBuffer Leftstring = new StringBuffer(stringBuffer.substring(0, 32));
StringBuffer Rightstring = new StringBuffer(stringBuffer.substring(32,64));
//3.for循环16轮
for (int i = 0; i < 16; i++) {
//3.1 f函数
StringBuffer f_output=function(subKeys[i],Rightstring);
//3.2 异或
StringBuffer temp=XOR(Leftstring,f_output);
//3.3 更新Li和Ri
Leftstring=Rightstring;
Rightstring=temp;
}
//4.左右互换
StringBuffer res = Rightstring.append(Leftstring);
//5.逆IP置换
res=ReverseIPReplacement(res);
return res;
}

/* 主函数 */
public static void main(String[] args) throws Exception {

String plaintext ="10000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000";
StringBuffer Plaintext= new StringBuffer(plaintext.replaceAll(" ","")); //正则匹配去掉空格

String key ="00100010 10010110 01001000 11000100 00111000 00110000 00111000 01100100";
StringBuffer Key= new StringBuffer(key.replaceAll(" ",""));

System.out.println("DES:");
StringBuffer Ciphertext = Encryption(Plaintext, Key);
StringBuffer Plaintexts = Decryption(Ciphertext, Key);
System.out.println("明文:"+Plaintext);
System.out.println("密钥:"+Key);
System.out.println("");
System.out.println("加密后密文:"+Ciphertext);
System.out.println("再解密后明文:"+Plaintexts);
}

}

 

实验三源代码

package RSA;

import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.util.*;

public class RSA {

/**
* 将明文转化为数字
*/
public static List<Integer> setInformation(String str) {
List<Integer> list = new ArrayList(); //定义动态数组 泛型 Integer
try {
byte[] bytes = str.getBytes("utf-8"); //将明文转化为 UTF-8的编码
//迭代循环
for (byte byt : bytes) {
list.add((int)(byt));
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return list;
}

/**
* 判断是否为素数
*/
public static boolean isPrime(int n) {
boolean flag = true;
for (int i = 2; i < n; i++) { //从2到该数字都无法被数字整除
if (n % i == 0) {
flag = false;
break;
}
}
return flag;
}

/**
* 随机选取两个素数
*/
public static int[] getTwoPrime() {
int prime[] = new int[2];
int a;
int i = 0;
while (i < 2) {
a = new Random().nextInt(2000); //生成0-2000的随机数
if (isPrime(a) && a > 1000) {
prime[i] = a;
i++;
}

}
return prime;
}

/**
* 获得N和M
*/
public static HashMap<Character, Integer> get_N_And_M(int[] twoPrime) {
HashMap<Character, Integer> map = new HashMap<Character, Integer>();
int N = twoPrime[0] * twoPrime[1];
int M = (twoPrime[0] - 1) * (twoPrime[1] - 1);
System.out.println("素数1:" + twoPrime[0] + "\t\t素数2:" + twoPrime[1]);
System.out.println("M:" + M + "\t\tN:" + N);
map.put('N', N);
map.put('M', M);
return map; //返回键值
}

/**
* 随机选取 e使得和 m互质
*/
public static int mANDprime(int M) {
//生成一个处于 1和 M之间的质数,该质数一定和 M互质
int E;
while (true) {
E = new Random().nextInt(2000);
if (isPrime(E) && E > 0 && E < M){
System.out.println("生成的E是 :"+E);
break;
}
}
return E;
}

/**
* 计算 D
*/
public static int getD(int M,int E){
int D=1;
while(true){
if((D*E)%M==1){
break;
}
D++;
}
return D;
}


/**
* 加密过程
*/
public static BigInteger encryption(int msg,int E,int N){ //明文 公钥(E N)
BigInteger bigInteger = new BigInteger(msg+"");
// bigInteger^E%N
BigInteger encryptedText = bigInteger.modPow(new BigInteger(E+""), new BigInteger(N+"")); //大数快速幂取模
System.out.println("密文:"+encryptedText);
return encryptedText;
}

/**
* 解密过程
*/
public static BigInteger decrypt(BigInteger encryptedText,int D,int N){ //密文 私钥(D N)
// encryptedText^D%N
BigInteger plainText = encryptedText.modPow(new BigInteger(D+""), new BigInteger(N+""));
System.out.println("明文:"+plainText);
return plainText;
}

/**
* 将数字转化为char型
*/
public static String getInformation(List<BigInteger> list){
String sad = ""; //定义静态空串
Iterator<BigInteger> iterator = list.iterator(); //定义迭代器
while(iterator.hasNext()){ //逐个转换
BigInteger next = iterator.next(); //获取当前游标并返回下一个
Integer Next = new Integer(next + "");
char a = (char)Next.byteValue(); //将这个整数的值作为一个字节返回
sad+=a;
}
return sad;
}
}

package RSA;

import java.math.BigInteger;
import java.util.*;

public class RSAtest {
public static void main(String[] args) {
System.out.println("----------获取密钥----------");
//随机获取两个较大的素数
int[] twoPrime = RSA.getTwoPrime();
//计算 M N E D
HashMap<Character, Integer> n_and_m = RSA.get_N_And_M(twoPrime); //散列表存储 键值对:char 和 int
int N = n_and_m.get('N');
int M = n_and_m.get('M');
int E = RSA.mANDprime(M);
int D = RSA.getD(M,E);
System.out.println("生成的D是 :"+D);
System.out.println("******************公钥******************");
System.out.println("公钥\t:("+E+","+N+")");
System.out.println("私钥\t:("+D+","+N+")");

System.out.println("-------------------明文-------------------");
System.out.print("请输入要加密的信息:");
String str = new Scanner(System.in).nextLine();
//将char类型的明文转换为byte类型
List<Integer> information = RSA.setInformation(str);
System.out.println("转码后的明文:"+ information);



System.out.println("-------------------加密-------------------");
List<BigInteger> encryptionList = new ArrayList<BigInteger>(); //动态数组 泛型 BigInteger
Iterator<Integer> iterator = information.iterator(); //迭代器 转码后明文
while(iterator.hasNext()){ //判断集合中是否还有元素
encryptionList.add(RSA.encryption(iterator.next(), E, N)); //加密过程
}
System.out.println("公钥加密后的信息(byte):"+encryptionList.toString());



System.out.println("-------------------解密-------------------");
List<BigInteger> decryptList = new ArrayList<BigInteger>();
for (int i = 0; i < encryptionList.size(); i++) {
decryptList.add(RSA.decrypt(encryptionList.get(i),D,N));//解密过程
}
System.out.println("私钥解密后的信息(byte):"+decryptList.toString());

System.out.println("-------------------解密后的信息-------------------");
//将int型转换为char型(去数字化)
String s = RSA.getInformation(decryptList);
System.out.println("解密后的明文:"+s);
}

}

 

posted @ 2022-12-18 09:40  王回甘  阅读(328)  评论(0编辑  收藏  举报