WinRAR压缩文件解密实验
使用ARPR工具对WinRaR加密文件进行破解
掌握WinRar加密原理及破解软件的使用。
步骤1:使用WinRAR工具对文件进行口令加密
1.1进入到本实验路径下解压工具,然后右键选择“添加到压缩文件”,在“常规”选项卡中点击“设置密码”按钮,在设置完密码之后点击“确定”完成配置。
这里我们设置的密码为:123
1.2打开新建的rar文件,可以发现,需要密码才能够访问压缩包中的文件。
步骤2:使用ARPR工具对WinRaR加密文件进行破解
2.1找到本实验相关的安装包,安装ARPR工具,在过程中输入注册码“ARCHPRP-LEHKE-58253-RHCZW-73269”。之后点击“install”,直至安装完成。
2.2通过配置软件破解选项,对文件口令密码进行破解。可以选择不同的攻击方式:暴力破解、字典攻击等方式,对所使用的字符集、密码长度进行配置,以及选择合适的字典。
2.3 进行ARCHPR配置界面进行配置
指定字典攻击所使用的字典
2.4打开所需要解压的文件,在soft文件夹中,有本实验所需要的加密文件:要压缩的文件.rar,该文件的默认密码为“123”,在配置好破解选项之后,用ARCHPR打开该文件,自动开始进行破解。
破解结果出来了,这里我们的密码是123.
试验结束后关闭虚拟机。我们可以看到使用本地工具例如ARCHPR进行破解,需要确定正确的密码长度,除了一些比较简单的情况,一般需要的时间可能会比较长。如果密码太过于复杂的话,比如又有大小写英文,又有数字,又不知道长度的话,那么破解起来就相对要时间长一点了,因此需要结合除了文件本身之外的相关信息,选择合适的破解策略,以减少其所消耗的时间。
1.Winrar加密步骤
Winrar加密文件时,总的分两个步骤:
(1):先把源文件压缩,压成一段数据段。
(2):再将压缩完的数据段加密。
对于同一个源文件来说,不进行加密,压缩完,其rar文件中的数据段是一模一样的。但是如果对同一个源文件来说,即使使用同一个密码,加密完rar文件中的数据段是不一样的,这是由于加密的密钥是依赖于一个Salt(8个字节的密钥,用来加密时使用,存放在rar文件头中里)
加密的流程:
(1)获取密钥:
将明文的密码与Salt一起,通过HASH算法,生成两个16字节的密钥。(一个是KEY(AES算法的参数),一个是initVector)
(2)以Key和initVector来加密压缩数据:
这里,是一个循环加密的结构,每16字节作为一个块,进行加密(这可能正是为什么加密完的文件长度总为16倍数的原因)。加密采用AES算法(RAR采用的是AES的rijndael的标准应用)。这里注意:AES加密前,有一个异或运算,是先将每16字节块与上一个16字节块加密结果进行异或,然后再进行AES算法的。用一个简单的示意代码看说明:
packblock[0]=packblock^initVector
encryptBlock[0]=AES(packblock[0]) ;(KEY为AES的密钥)
for i=1 to 块数量-1
packblock=packblock^encryptBlock[i-1]
encryptBlock=AES(packblock) ;(KEY为AES的密钥)
next
;packblock表示压缩完的每16字节数据
;encryptBlock表示加密完的每16字节数据
;===============================================
2.WinRAR解密
由于AES算法是对称的,所以解密的过程,是加密过程的逆运算。但解密时AES算法过程与加密所用的不一样(是因为解密过程中由KEY生成的子密钥表不一样)。仍然需要我们将密码输入,与salt一起生成两个16字节密钥,KEY和initVector。
;===============================================
packblock[0]=AES1(encryptBlock[0]) ;(KEY为AES的密钥)
packblock[0]=packblock^initVector
for i=1 to 块数量-1
packblock=AES1(encryptBlock) ;(KEY为AES的密钥)
packblock=packblock^encryptBlock[i-1]
next
;===============================================
解密的过程是解密后的数据块进行解压缩,然后解成源文件,对该文件进行CRC校验,存在RAR文件中的源文件CRC校验码比较,相同则密码正确,不相同则密码错误。
通过这次试验,我基本掌握了WinRAR的基本使用,并亲自动手运用ARCHPR破解了一个压缩文件并得到了他的密码,这让我认识到简单的密码是不足以保护人们的信息安全的,有时候自己设置的压缩包密码常常会忘记,如果简单密码,可以在网上找些破解软件破解掉,主流的破解方法多是暴力和字典的破解。
这提示我们为了安全要设置复杂且很长的密码,那么从常规的暴力或跑字典方式进行破解,估计是破解不了的,何况有的密码中带有中文汉字,更加大了破解的难度,如果用暴力或跑字典无法在短时间内破解成功。
图像秘密共享和安全存储系统
系统功能要求:
1)将一幅图像,利用门限秘密共享方法,分解成N份并通过网络发送;当接收方收到其中K份的时候,就可以恢复该图像;
2)可以实现在局域网或云平台下的安全传输和管理;
3)尽量考虑并防范秘密共享系统的相关安全攻击
3.1、实验原理
秘密共享技术是密码学和信息安全的一个重要研究内容,Shamir密钥分享算法最早是由Shamir和Blackly在1970年基于Lagrange插值和矢量方法提出的,其基本思想是分发者通过秘密多项式,将秘密s分解为n个秘密分发个持有者,其中任意不少于k个秘密均能恢复密文,而任意少于k个秘密均无法得到密文的任何信息。
基于 Shamir 多项式的秘密分享和恢复方案利用了传统解方程组的基本思想。影子信息由下多项式获取。
理论上系数 (s0 , a1 , a2 ,.., ak -1 ) 都可以作为秘密信息进行分享。由方程组的一般知识可以知道当有 k 个线性无关的方程时可以唯一的解出这一组秘密信息。然而由于安全的考虑,Shamir 秘密分享方案仅将 s 设为待秘密的信息。在本文中我 们利用 Lagrange 插值法恢复秘密信息,插值拟合后的多项式在 x = 0 的取值即为秘密信息 s。
需要指出的是 Shamir 给出原始方案时,为了保持影子图片和秘密图片的大 小一致性,在有限域 GF(253)中进行测试。Shamir 在提出分享方案时在有限与 GF(253)上对秘密信息进行了分享。这样可以保证影子文件与原始文件大小上的一致性。在其给出的实现方案中存在一步秘密信息的预处理过程:将秘密信息中大于 253 的像素点全部替换成 252,然后进行逐像素的分享和恢复操作。由于受人眼敏感度限制,这种改变在视觉效果上是可行的。
加密
对于待加密的明文s∈ Zp(p为大素数),在有限群GF(p)任取k−1个随机数a1,a2,…,ak−1,并令a0=s,从而构造如下的多项式:
对于这个多项式,任取n个数x1,x2,x3,…,xn分别带入多项式得到n个密钥对:
分发给n个持有者。
解密
假设得到了k个密钥对{x1,y1}{x2,y2}…{xk,yk},我们可以得到方程(运算均在GF(p)),由矩阵乘法或者Lagrange插值法均可求的a0即为明文s。
3.2、程序结构描述
图3-1 类间关系示意图
3.3、各主要函数形参及返回值
表3-1 程序主要函数形参、返回值及功能描述
函数名称及调用格式返回类型 |
参数含义 |
返回值描述 |
函数功能 |
public void encrypt(String file, String destFile) |
@param file 要加密的文件 如c:/test/srcFile.txt @param destFile 加密后存放的文件名 如c:/加密后文件.txt |
无 |
文件file进行加密并保存目标文件destFile中 |
public void decrypt(String file, String dest) |
@param file 已加密的文件 如c:/加密后文件.txt @param destFile 解密后存放的文件名 如c:/test/解密后文件.txt |
无 |
文件采用DES算法解密文件 |
restore.addActionListener(e -> { … }; |
无 |
无 |
门限分割按钮的监听器,n个逐个操作,每个像素算出(1,f(1))、(2,f(2))、(3,f(3))、(4,f(4))、(5,f(5))... |
public void getKey(String strKey) |
参数strKey |
无 |
根据参数生成KEY |
upload.addActionListener(e -> { … }; |
无 |
无 |
上传按钮对应的监听器,向服务端传送文件 |
restore.addActionListener(e ->{ … }; |
无 |
无 |
恢复按钮对应的监听器,根据接收到的影子文件恢复原图 |
public ImageDialog (String path) |
图片路径path |
无 |
读取路径图片并将其显示再ImageDialog上 |
3.4、详细的算法描述
本次实验,一种基于Shamir门限的提供数据安全传输的局域网安全方法,包括以下步骤:
步骤一、初始化配置阶段
为客户端服务器端同步配置会话密钥,为远程服务设备预先配置端口号及IP地址以及对应的各个共享秘密信息;
步骤二、通信建立阶段
该阶段分为两个部分,第一部分是在开始数据传输的时间周期中,客户端和服务器要进行身份认证,认证通过后,建立通信,传输已经加密的用户数据。第二部分是在服务器收到客户端加密的信息后,与客户端进行身份认证,认证通过后,建立通信,发送所有的已经进行数据融合后加密的数据信息。
步骤三、信息加密发送阶段
客户端将数据分别用各个对应的会话密钥解密,从密文剥离出指定数量的秘密碎片,采用Shamir门限方案,重新计算出与远程服务设备之间的共享秘密,该秘密作为对称密钥,将其他的解密数据重新加密,与服务器进行身份认证后发送给服务器。
1、Shamir门限分割
图3-2 门限分割流程图
步骤 1:提示用户输入参数(k, n)。
步骤 2:打开待分享文件,打开影子文件(没有则创建)。
步骤 3:读取秘密信息的单个字节进入临时缓冲区。
步骤 4:利用多项式对秘密信息进行分享,分享后产生的n个字节写入n个 影子文件中,每个文件写入 1 个字节。
步骤 5:判断秘密文件是否分享完毕,如果没有分享完毕,则转向步骤 3; 如若结束转向步骤 6。
步骤 6:关闭输入输出流,删除对象。
步骤 7:结束。
for(int pow = 1; pow < k; pow++){ //门限分割多项式计算
red += random_numbers.get(pow-1) * Math.pow(x, pow);
green += random_numbers.get(pow-1) * Math.pow(x, pow);
blue += random_numbers.get(pow-1) * Math.pow(x, pow);
}
2、Lagrange插值法的秘密恢复
步骤 1:输入恢复阈值 k。
步骤 2:打开恢复后的文件,用户输入影子文件序列号。
步骤 3:从影子文件读取信息到缓冲区,将对应的信息与文件序列形成插值信息对。
步骤 4:利用步骤 3 得到的插值信息对进行 Lagrange 插值,将恢复的秘密 信息写入文件。
步骤 5:判断是否尚有信息等待恢复,如果有跳回步骤 3 否则执行下一步。 步骤 6:关闭输入输出文件流,销毁对象。
步骤 7:结束。
图3-3 基于 Lagrange 插值法的秘密恢复流程图
3、客户端与服务器通信
网络上的两个程序通过一个双向的通讯连接实现数据的交换,这个双向链路的一端称为一个Socket。Socket通常用来实现客户方和服务方的连接。Socket是TCP/IP协议的一个十分流行的编程界面,一个Socket由一个IP地址和一个端口号唯一确定。
但是,Socket所支持的协议种类也不光TCP/IP一种,因此两者之间是没有必然联系的。在Java环境下,Socket编程主要是指基于TCP/IP协议的网络编程。
Server 端Listen(监听)某个端口是否有连接请求,Client端向Server端发出Connect(连接)请求,Server端向Client端发回 Accept(接受)消息。一个连接就建立起来了。Server端和Client端都可以通过Send,Write等方法与对方通信。
对于Socket,包含以下基本结构,其工作过程包含以下四个基本的步骤:
(1) 创建Socket;
(2) 打开连接到Socket的输入/出流;
(3) 按照一定的协议对Socket进行读/写操作;
(4) 关闭Socket.
图3-4 Socket通信模型
关于创建Socket,java在包java.net中提供了两个类Socket和ServerSocket,分别用来表示双向连接的客户端和服务端。这是两个封装得非常好的类,使用很方便。其构造方法如下:
Socket(InetAddress address, int port);
在创建socket时如果发生错误,将产生IOException,在程序中必须对之作出处理。所以在创建Socket或ServerSocket是必须捕获或抛出例外。
运行结果说明:先启动服务器端,在客户端连接,客户端Shamir门限分割后上传k份影子文件至服务器端,服务器端恢复。
界面:
门限分割结果:
客户端本地目录下:
服务器端本地目录下:
算法的安全性:
由伽罗华域以及矩阵运算的性质可知:Shamir的方案满足秘密共享方案的安全需求,即:
①任意不少于k个影子秘密能恢复出主秘密;
②少于k个影子秘密不能得到主秘密的任何信息。
文件传输过程的安全性:
对于文件传输过程中的安全问题,本次实验采用DES对影子文件进行了加密。DES算是发明最早的最广泛使用的分组对称加密算法,它需要三个参数来完成加解密的工作,分别是Key、Data以及Mode,其中Key是加密密钥(因为DES是一种对称加密算法,所以解密的密钥也是它了),Data是待加密或解密的数据,Mode则用来指定到底是加密还是解密。
public void encrypt(String file, String destFile)
cipher.init(Cipher.ENCRYPT_MODE, this.key);
另在Socket传输过程中用Base64编码编码了消息,虽然不是加密,但也提供了一定的隐蔽性。
防止欺骗:
早期的秘密共享方案中影子秘密主要存储于参与者中,这样会存在安全问题。 如果分发者分发无效的影子秘密给参与者,这样秘密就不能被正确地恢复。即使分发者诚实的情形下,在Shamir的(n,k)门限秘密共享方案的秘密恢复过程中,可 能存在持有无效影子秘密的参与者去骗取其他参与成员的有效影子秘密,导致欺 骗者得到真正的秘密,而诚实参与成员恢复的是无效秘密。这些欺骗行为使得秘 密共享过程不安全,进而影响秘密共享方案的实际应用。
我这次运用了DES加密方案:分发者使用DES将影子文件进行加密后分发给参与者,参与者在收到影子秘密后可利用密钥进行验证或解密,可检测影子秘密的真实性
1、通过此次课程设计更加熟悉了Socket通信和文件流读写,还会使用ImageIO类进行图片的读写及更改像素操作,更加熟悉了Java语法和DES加密解密的流程,了解了Java的密码操作包。
2、解密的时候报错: “javax.crypto.BadPaddingException: Given final block not properly padded” 总是解决不了,该异常是在解密的时候抛出的,加密的方法没有问题。
后来我通过查找资料得知两个方法的唯一差别是Cipher对象的模式不一样,这就排除了程序写错的可能性。再看一下异常的揭示信息,大概的意思是:提供的字块不符合填补的。在用DES加密的时候,最后一位长度不足64的,它会自动填补到64,那么在我们进行字节数组到字串的转化过程中,可以把它填补的不可见字符改变了,所以引发系统抛出异常。
3、此次课程设计,锻炼了我综合运用所学信息安全、计算机类知识进行分析、设计和实现的能力。同时让我对于设计有了系统而全面的认知,锻炼了我分析、解决实际信息安全问题的能力。虽然安排课程设计时间是一周,但是由于期末了,我们考试和复习占用了时间,真正用于可时间只有几天,课程设计过程中由于经验的匮乏在这过程中遇到困难和问题是必然的。经过这次密码学的课程设计,我们学到了很多关于密码学的知识。让我深层次的了解我们生活中通信的原理,了解了保密信息系统通信的设计步骤和通信过程。
代码部分:
Client_GUI.java
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.TextField;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import javax.swing.JLabel;
import javax.swing.JTextField;
import javax.imageio.ImageIO;
import javax.swing.JButton;
import javax.swing.JTextArea;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Base64;
import java.util.LinkedList;
import java.util.Random;
import java.awt.event.ActionEvent;
public class Client_GUI extends JFrame {
private static final long serialVersionUID = 1L;
public static int red, green, blue;
//此链表存储k-1个随机数做多项式系数
public static LinkedList random_numbers = new LinkedList();
static int n;
static int k;
private JPanel contentPane;
private JTextField textField_IP;
private JTextField textField_Port;
//Base64编码
final Base64.Encoder encoder = Base64.getEncoder();
FileEncAndDec td = new FileEncAndDec("aaa");
//IO流
private DataOutputStream toServer;
private DataInputStream fromServer;
private FileInputStream fis;
JTextArea txtMessage;
Socket socket;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
Client_GUI frame = new Client_GUI();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the frame.
*/
public Client_GUI() {
setTitle("Client");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(1000, 100, 450, 450);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
contentPane.setLayout(null);
JPanel panel = new JPanel();
panel.setBounds(12, 5, 415, 100);
contentPane.add(panel);
panel.setLayout(null);
JLabel lblip = new JLabel("服务器IP:");
lblip.setBounds(12, 12, 65, 15);
panel.add(lblip);
textField_IP = new JTextField();
textField_IP.setText("localhost");
textField_IP.setBounds(82, 10, 114, 19);
panel.add(textField_IP);
textField_IP.setColumns(10);
JLabel label = new JLabel("端口:");
label.setBounds(214, 12, 49, 15);
panel.add(label);
textField_Port = new JTextField();
textField_Port.setText("8000");
textField_Port.setBounds(265, 10, 114, 19);
panel.add(textField_Port);
textField_Port.setColumns(10);
JButton button = new JButton("连接");
button.setBounds(80, 50, 80, 20);
panel.add(button);
JButton button_1 = new JButton("断开");
button_1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
try {
toServer.close();
fromServer.close();
socket.close();
fis.close();
txtMessage.append("连接已断开");
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
});
button_1.setBounds(270, 50, 80, 20);
panel.add(button_1);
JPanel panel_1 = new JPanel();
panel_1.setBounds(12, 100, 415, 118);
contentPane.add(panel_1);
txtMessage = new JTextArea();
txtMessage.setBackground(Color.LIGHT_GRAY);
txtMessage.setColumns(40);
txtMessage.setRows(30);
txtMessage.setTabSize(6);
panel_1.add(txtMessage);
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
String ip = textField_IP.getText();
int port = Integer.parseInt(textField_Port.getText());
try {
socket = new Socket(ip, port);
Client3_thread client3_thread = new Client3_thread();
Thread thread = new Thread(client3_thread);
thread.start();
txtMessage.append("连接成功...");
} catch (IOException e1) {
txtMessage.append(e1.toString() + '\n');
}
}
});
//标签
JLabel l1 = new JLabel("Shamir门限分割N、K值");
l1.setBounds(20,275,150,20);
contentPane.add(l1);
/**
* N、K文本域
*/
TextField narea = new TextField();
narea.setText("5"); //缺省值
narea.setBounds(20, 300, 40, 20);
contentPane.add(narea);
TextField karea = new TextField();
karea.setText("3"); //缺省值
karea.setBounds(80, 300, 40, 20);
contentPane.add(karea);
//门限分割按钮
JButton restore = new JButton("Shamir分割");
restore.addActionListener(e -> {
try {
Random rand = new Random();
File secret = new File("E:/TEST_Client/test.bmp"); //原图像
BufferedImage image = ImageIO.read(secret);
// (n,k) shamir门限方案
int n = Integer.valueOf(narea.getText()).intValue();
int k = Integer.valueOf(karea.getText()).intValue();
String share = "E:/TEST_Client/share";
// creates BufferedImages for the encrpyted images
BufferedImage encryptedImage = new BufferedImage(image.getWidth(), image.getHeight(), image.getType());
//reads the input image
encryptedImage = ImageIO.read(secret);
for(int i = 1; i < k; i++){
int number = rand.nextInt(252) + 1; //产生随机数
random_numbers.add(number);
}
for(int x = 1; x <= n; x++){ //n个share(1,2,3,4,5)
//n个逐个操作,每个像素算出(1,f(1))、(2,f(2))、(3,f(3))、(4,f(4))、(5,f(5))...
for(int i = 0; i < encryptedImage.getWidth(); i++){
for(int j = 0; j < encryptedImage.getHeight(); j++){
Color c = new Color(encryptedImage.getRGB(i,j));//获得该点的像素RGB值
red = c.getRed();
if(red > 252)
red = 252;
green = c.getGreen();
if(green > 252)
green = 252;
blue = c.getBlue();
if(blue > 252)
blue = 252;
for(int pow = 1; pow < k; pow++){ //门限分割多项式计算
red += random_numbers.get(pow-1) * Math.pow(x, pow);
green += random_numbers.get(pow-1) * Math.pow(x, pow);
blue += random_numbers.get(pow-1) * Math.pow(x, pow);
}
red %= 253;
green %= 253;
blue %= 253;
Color color = new Color(red, green, blue);
encryptedImage.setRGB(i, j, color.getRGB());
}
}
//n个逐个保存
String shareNumber = Integer.toString(x);
share += (shareNumber + ".bmp");
File encrypted = new File(share); //加起来就是share1.bmp、share2.bmp ...
ImageIO.write(encryptedImage, "bmp", encrypted);
encryptedImage = ImageIO.read(secret);
share = "E:/TEST_Client/share"; //再恢复 share 字符串
}
txtMessage.append("成功将目标文件门限分割成" + n + "份...\n");
}catch(Exception e1) {
e1.printStackTrace();
}
});
restore.setBounds(240, 290, 170, 30);
contentPane.add(restore);
//标签
JLabel l2 = new JLabel("选择要上传的文件:");
l2.setBounds(20, 330,170,20);
contentPane.add(l2);
TextField selectarea = new TextField();
selectarea.setText("1"); //缺省值
selectarea.setBounds(20, 360, 100, 20);
contentPane.add(selectarea);
//上传按钮
JButton upload = new JButton("上传");
upload.addActionListener(e -> {
//连接服务器
try {
String scan = selectarea.getText().trim();
td.encrypt("E:/TEST_Client/share"+scan+".bmp", "E:/TEST_Client/enshare"+scan+".bmp");//(new File("E:/TEST_Client/share"+scan+".bmp"), new File("E:/TEST_Client/enshare"+scan+".bmp"));
//向服务端传送文件
File file =new File("E:/TEST_Client/enshare" + scan + ".bmp");
fis =new FileInputStream(file);
//文件名和长度encoder.encodeToString(file.getName().getBytes("UTF-8"))
toServer.writeUTF(encoder.encodeToString(file.getName().getBytes("UTF-8")));
toServer.flush();
toServer.writeLong(file.length());
toServer.flush();
//传输文件
byte[] sendBytes =new byte[1024];
int length =0;
//2.往输出流里面投放数据
while ((length = fis.read(sendBytes)) != -1)
{
toServer.write(sendBytes,0,length);
}
txtMessage.append("上传share" + selectarea.getText() + ".bmp成功 \n");
} catch (UnknownHostException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (Exception e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
});
upload.setBounds(240, 350, 170, 30);
contentPane.add(upload);
}
//消息收发线程
public class Client3_thread implements Runnable{
public void run(){
try {
fromServer = new DataInputStream(socket.getInputStream());
toServer = new DataOutputStream(socket.getOutputStream());
while(true){
String fromStr = fromServer.readUTF();
txtMessage.append("服务端发来消息:" +fromStr);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
FileEncAndDec.java
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.Key;
import java.security.SecureRandom;
import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.CipherOutputStream;
import javax.crypto.KeyGenerator;
public class FileEncAndDec {
Key key;
public FileEncAndDec(String str) {
getKey(str);// 生成密匙
}
/**
* 根据参数生成KEY
*/
public void getKey(String strKey) {
try {
KeyGenerator _generator = KeyGenerator.getInstance("DES");
_generator.init(new SecureRandom(strKey.getBytes()));
this.key = _generator.generateKey();
_generator = null;
} catch (Exception e) {
throw new RuntimeException("Error initializing SqlMap class. Cause: " + e);
}
}
/**
* 文件file进行加密并保存目标文件destFile中
*
* @param file 要加密的文件 如c:/test/srcFile.txt
* @param destFile 加密后存放的文件名 如c:/加密后文件.txt
*/
public void encrypt(String file, String destFile) throws Exception {
Cipher cipher = Cipher.getInstance("DES");
// cipher.init(Cipher.ENCRYPT_MODE, getKey());
cipher.init(Cipher.ENCRYPT_MODE, this.key);
InputStream is = new FileInputStream(file);
OutputStream out = new FileOutputStream(destFile);
CipherInputStream cis = new CipherInputStream(is, cipher);
byte[] buffer = new byte[1024];
int r;
while ((r = cis.read(buffer)) > 0) {
out.write(buffer, 0, r);
}
cis.close();
is.close();
out.close();
}
/**
* 文件采用DES算法解密文件
*
* @param file 已加密的文件 如c:/加密后文件.txt
* @param destFile 解密后存放的文件名 如c:/test/解密后文件.txt
*
*/
public void decrypt(String file, String dest) throws Exception {
Cipher cipher = Cipher.getInstance("DES");
cipher.init(Cipher.DECRYPT_MODE, this.key);
InputStream is = new FileInputStream(file);
OutputStream out = new FileOutputStream(dest);
CipherOutputStream cos = new CipherOutputStream(out, cipher);
byte[] buffer = new byte[1024];
int r;
while ((r = is.read(buffer)) >= 0) {
System.out.println();
cos.write(buffer, 0, r);
}
cos.close();
out.close();
is.close();
}
}
Server_GUI.java
import java.awt.EventQueue;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import javax.swing.JLabel;
import javax.swing.JTextField;
import javax.imageio.ImageIO;
import javax.swing.JButton;
import javax.swing.JTextArea;
import java.awt.Color;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Base64;
import java.util.Date;
import java.util.LinkedList;
import java.awt.event.ActionEvent;
public class Server_GUI extends JFrame {
private static final long serialVersionUID = 1L;
private JPanel contentPane;
private JTextField textField;
private JTextArea textMessage;
public static int red, green, blue;
LinkedList shareFiles = new LinkedList(); //文件列表shareFiles
LinkedList shareNumbers = new LinkedList(); //选择k个文件
static int k = 0;
LinkedList images = new LinkedList();//BufferedImage列表
static BufferedImage decryptedImage = new BufferedImage(800, 600, BufferedImage.TYPE_INT_ARGB);
//Base64解码
final Base64.Decoder decoder = Base64.getDecoder();
FileEncAndDec td = new FileEncAndDec("aaa");
//IO流
private DataInputStream inputFromClient;
private DataOutputStream outputToClient;
private FileOutputStream fos;
ServerSocket serverSocket;
Socket socket;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
Server_GUI frame = new Server_GUI();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the frame.
*/
public Server_GUI() {
setTitle("Server");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 450, 380);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
contentPane.setLayout(null);
JPanel panel = new JPanel();
panel.setBounds(0, 0, 426, 57);
contentPane.add(panel);
panel.setLayout(null);
JLabel label = new JLabel("端口:");
label.setBounds(12, 12, 39, 15);
panel.add(label);
textField = new JTextField();
textField.setText("8000");
textField.setBounds(55, 10, 50, 19);
panel.add(textField);
textField.setColumns(10);
JButton button = new JButton("启动");
button.setBounds(200, 7, 70, 25);
panel.add(button);
button.addActionListener(new buttonListener());
JButton button_1 = new JButton("停止");
button_1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
try {
inputFromClient.close();
outputToClient.close();
socket.close();
fos.close();
textMessage.append("连接已断开");
} catch (Exception e2) {
// TODO: handle exception
e2.printStackTrace();
}
}
});
button_1.setBounds(300, 7, 70, 25);
panel.add(button_1);
JPanel panel_1 = new JPanel();
panel_1.setBounds(0, 69, 416, 170);
contentPane.add(panel_1);
textMessage = new JTextArea();
textMessage.setTabSize(4);
textMessage.setRows(11);
textMessage.setColumns(35);
textMessage.setBackground(Color.LIGHT_GRAY);
textMessage.setText("");
panel_1.add(textMessage);
JPanel panel_2 = new JPanel();
panel_2.setBounds(10, 240, 428, 89);
contentPane.add(panel_2);
panel_2.setLayout(null);
//按钮一 恢复按钮
JButton restore = new JButton("恢复");
restore.addActionListener(e -> {
System.out.println(shareNumbers.get(0)+" " +shareNumbers.get(1)+" "+shareNumbers.get(2));
try {
for(int i = 0; i < k; i++){
decryptedImage = ImageIO.read(shareFiles.get(i));
images.add(decryptedImage);
}
BigInteger mod = new BigInteger("253");
for(int x = 0; x < decryptedImage.getWidth(); x++){
for(int y = 0; y < decryptedImage.getHeight(); y++){
BigInteger foundRed = BigInteger.ZERO;
BigInteger foundGreen = BigInteger.ZERO;
BigInteger foundBlue = BigInteger.ZERO;
for(int i = 0; i < k; i++){
BigInteger num = BigInteger.ONE;
BigInteger den = BigInteger.ONE;
for(int j = 0; j < k; j++){
if(j != i){
//分子 (0-shareNumbers.get(j))*...
num = num.multiply(BigInteger.valueOf(shareNumbers.get(j) * -1));
//分母
den = den.multiply(BigInteger.valueOf(shareNumbers.get(i) - shareNumbers.get(j)));
}
}
Color c = new Color(images.get(i).getRGB(x,y)); //第i张图片的x、y坐标的像素值
red = c.getRed();
green = c.getGreen();
blue = c.getBlue();
//f(x)
BigInteger bigRed = new BigInteger(Integer.toString(red));
BigInteger bigGreen = new BigInteger(Integer.toString(green));
BigInteger bigBlue = new BigInteger(Integer.toString(blue));
//该方法返回一个BigInteger对象的值是 this-1 mod m.
// num/den*f(x)
BigInteger tmpRed = (bigRed.multiply(num.multiply(den.modInverse(mod)))).mod(mod);
BigInteger tmpGreen = (bigGreen.multiply(num.multiply(den.modInverse(mod)))).mod(mod);
BigInteger tmpBlue = (bigBlue.multiply(num.multiply(den.modInverse(mod)))).mod(mod);
//各个多项式相加
foundRed = foundRed.add(tmpRed).mod(mod);
foundGreen = foundGreen.add(tmpGreen).mod(mod);
foundBlue = foundBlue.add(tmpBlue).mod(mod);
}
Color color = new Color(foundRed.intValue(), foundGreen.intValue(), foundBlue.intValue());
decryptedImage.setRGB(x, y, color.getRGB());
}
}
File decrypted = new File("E:/TEST_Server/decrypted.bmp");
textMessage.append("恢复完成,已保存在服务器目录下");
ImageIO.write(decryptedImage, "bmp", decrypted);
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
});
restore.setBounds(50, 10, 80, 30);
panel_2.add(restore);
//按钮二 显示按钮
JButton show = new JButton("显示");
show.addActionListener(e -> {
try {
new ImageDialog("E:/TEST_Server/decrypted.bmp");
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
});
show.setBounds(250, 10, 80, 30);
panel_2.add(show);
}
private class buttonListener implements ActionListener{
@Override
public void actionPerformed(ActionEvent e) {
int port = Integer.parseInt(textField.getText());
try {
serverSocket = new ServerSocket(port);
textMessage.append("服务器已启动 启动时间:" + new Date() +'\n');
//监听连接请求
socket = serverSocket.accept();
textMessage.append("连接成功..." + '\n');
Server_thread server3_thread = new Server_thread();
Thread thread = new Thread(server3_thread);
thread.start();
} catch (IOException e1) {
System.out.println(e1);
}
}
}
//输入输出线程
private class Server_thread implements Runnable{
public Server_thread(){
}
public void run(){
try {
//IO流
inputFromClient = new DataInputStream(socket.getInputStream());
outputToClient = new DataOutputStream(socket.getOutputStream());
while(true){
String fileName = new String(decoder.decode(inputFromClient.readUTF()), "UTF-8");
int fileLength = (int)inputFromClient.readLong();
fos = new FileOutputStream(new File("E:/TEST_Server/" + fileName));
shareNumbers.add(fileName.charAt(7)-'0');
byte[] sendBytes =new byte[fileLength];
textMessage.append("开始接收文件 " + fileName +" ,文件大小为 " + fileLength +" \n");
int passedLen = 0;
int len = 0;
while(passedLen < fileLength){
len = inputFromClient.read(sendBytes, passedLen, fileLength - passedLen);
if (len > 0) {
passedLen += len;
} else
break;
}
fos.write(sendBytes);
fos.flush();
textMessage.append("接收文件< " + fileName +"> 成功 \n");
td.decrypt("E:/TEST_Server/" + fileName, ((("E:/TEST_Server/" + fileName).replaceAll("en", ""))));
//(new File("E:/TEST_Server/" + fileName), new File((("E:/TEST_Server/" + fileName).replaceAll("en", ""))));
//("E:/TEST_Server/" + fileName, (("E:/TEST_Server/" + fileName).replaceAll("en", "")));
shareFiles.add(new File((("E:/TEST_Server/" + fileName).replaceAll("en", ""))));
k++;
}
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
//显示图片的小框框
class ImageDialog extends JFrame {
private static final long serialVersionUID = 1L;
static BufferedImage image = null;
public ImageDialog (String path) throws IOException {
image = ImageIO.read(new File(path));
setSize(400,400);
setTitle(path);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
}
public void paint(Graphics g) {
super.paint(g);
g.drawImage(image , 0 , 0 , null);
}
}
qq:1827742534 可随时联系,我也不会鸟你的~ 0.0