使用数字签名验证文件是否被修改

本文详细介绍了数字签名的基本原理及其实现过程。发送方通过生成密钥对、为文件内容创建签名并将其发送给接收方;接收方则利用公钥验证签名的真实性,确保文件未被篡改。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

基本原理:

发送方:

1.     生成公钥和私钥并保存至文件public.key和private.key。

2.     根据要发送的文件内容生成签名并写入文件signature.dtx。

3.     将公钥文件、签名文件和要发送的文件一起发送给接受方。

接受方:

1.     读取发送方发送的公钥文件

2.     读取发送方发送的签名文件。

3.     读取发送方发送的文件。

4.     根据发送方发送的公钥对发送方发送的文件进行签名。

5.     对比生成的签名和发送方发送的签名是否一致。

 

代码:

package com.security.example.example1;

 

import java.io.File;

import java.io.FileInputStream;

import java.io.FileNotFoundException;

import java.io.FileOutputStream;

import java.io.IOException;

import java.io.ObjectInputStream;

import java.io.ObjectOutputStream;

import java.security.InvalidKeyException;

import java.security.KeyPair;

import java.security.KeyPairGenerator;

import java.security.NoSuchAlgorithmException;

import java.security.PrivateKey;

import java.security.PublicKey;

import java.security.Signature;

import java.security.SignatureException;

 

import org.apache.log4j.Logger;

 

/**

 * 发送方。

 * @author lucky star

 *

 */

public class Sender {

         private static Logger log = Logger.getLogger(Sender.class);

        

         public void writeKeysToFiles(String privateFileName,String publicFileName)throws NoSuchAlgorithmException, FileNotFoundException, IOException {

                   KeyPairGenerator keygen = KeyPairGenerator.getInstance("DSA");

                   keygen.initialize(1024);

                   KeyPair kp = keygen.generateKeyPair();

                   PrivateKey privateKey = kp.getPrivate();

                   PublicKey publicKey = kp.getPublic();

                   ObjectOutputStream out_private = new ObjectOutputStream(new FileOutputStream(privateFileName));

                   out_private.writeObject(privateKey);

                   out_private.close();

                  

                   ObjectOutputStream out_public = new ObjectOutputStream(new FileOutputStream(publicFileName));

                   out_public.writeObject(publicKey);

                   out_public.close();

                  

                   log.debug("已生成私钥文件:" + privateFileName +",公钥文件:" + publicFileName);

         }

        

         /**

          * 读取私钥文件得到私钥,并根据文件内容生成签名并写入签名文件。

          * @param privateFile:私钥文件。

          * @param f:要发送的文件

          * @throws FileNotFoundException:如果文件未找到

          * @throws IOException:如果出现读写异常

          * @throws ClassNotFoundException:如果类未找到

          * @throws NoSuchAlgorithmException:如果没有此算法

          * @throws InvalidKeyException:如果私钥不可用

          * @throws SignatureException:如果签名失败

          */

         public void send(File privateFile,File sigendFile,File f) throws FileNotFoundException, IOException, ClassNotFoundException, NoSuchAlgorithmException, InvalidKeyException, SignatureException {

                   if (privateFile==null) {

                            thrownew FileNotFoundException("没有找到私钥文件!");

                   }

                   if (f ==null) {

                            thrownew FileNotFoundException("没有找到要加密的文件!");

                   }

                   // 读取文件,得到私钥

                   ObjectInputStream in = new ObjectInputStream(new FileInputStream(privateFile));

                   PrivateKey privateKey = (PrivateKey) in.readObject();

                   in.close();

                  

                   // 根据文件生成签名,并保存到文件signature.dxt

                   byte[] data =new byte[(int) f.length()];

                   FileInputStream fis = new FileInputStream(f);

                   fis.read(data);

                   fis.close();

                  

                   Signature sign = Signature.getInstance("DSA");

                   sign.initSign(privateKey);

                   sign.update(data);

                   // 生成签名

                   byte[] signedBytes = sign.sign();

                   // 将签名写入文件

                   FileOutputStream fos = new FileOutputStream(sigendFile);

                   fos.write(signedBytes,0,signedBytes.length);

                   fos.close();

                  

                   log.debug("根据文件内容生成签名并写入签名文件完毕!");

                   log.debug("签名文件写入到" + sigendFile.getName());

         }

        

         public static void main(String[] args) {

                   // 私钥文件

                                     String privateFileName = "private.key";

                                     // 公钥文件

                                     String publicFileName = "public.key";

                                     // 签名文件

                                     String signedFileName = "signature.dtx";

                                     // 发送方要发送的文件。

                                     File f = new File("d:/test.xml");

                                     File privateFile = new File(privateFileName);

                                     File sigendFile = new File(signedFileName);

                                    

                                     try {

                                               Sender sender = new Sender();

                                               // 发送方将公钥和私钥保存到文件private.keypublic.key

                                               sender.writeKeysToFiles(privateFileName, publicFileName);

                                               // 发送方根据文件内容生成签名并写入signature.dtx

                                               sender.send(privateFile,sigendFile,f);

                                     } catch (NoSuchAlgorithmException e) {

                                               // TODO Auto-generated catch block

                                               e.printStackTrace();

                                     } catch (FileNotFoundException e) {

                                               // TODO Auto-generated catch block

                                               e.printStackTrace();

                                     } catch (IOException e) {

                                               // TODO Auto-generated catch block

                                               e.printStackTrace();

                                     } catch (InvalidKeyException e) {

                                               // TODO Auto-generated catch block

                                               e.printStackTrace();

                                     } catch (SignatureException e) {

                                               // TODO Auto-generated catch block

                                               e.printStackTrace();

                                     } catch (ClassNotFoundException e) {

                                               // TODO Auto-generated catch block

                                               e.printStackTrace();

                                     }

         }

}

 

 

接受方:

package com.security.example.example1;

 

import java.io.File;

import java.io.FileInputStream;

import java.io.FileNotFoundException;

import java.io.IOException;

import java.io.ObjectInputStream;

import java.security.InvalidKeyException;

import java.security.NoSuchAlgorithmException;

import java.security.PublicKey;

import java.security.Signature;

import java.security.SignatureException;

 

import org.apache.log4j.Logger;

 

/**

 * 接受方。

 * @author lucky star

 *

 */

public class Receiver {

         private static Logger log = Logger.getLogger(Receiver.class);

         /**

          * 接受方读取发送方的公钥文件得到公钥,并以公钥验证签名。

          * @param publicKeyFile:公钥文件。

          * @param f:发送方发送的文件。

          * @return:签名是否验证OK

          * @throws NoSuchAlgorithmException:如果没有此算法。

          * @throws FileNotFoundException:如果文件未找到。

          * @throws IOException:如果读写异常

          * @throws ClassNotFoundException:如果类未找到

          * @throws InvalidKeyException:如果公钥不可用

          * @throws SignatureException:如果签名失败

          */

         public boolean receive(File publicKeyFile,File signedFile,File f) throws NoSuchAlgorithmException, FileNotFoundException, IOException, ClassNotFoundException, InvalidKeyException, SignatureException {

                   if (publicKeyFile ==null) {

                            thrownew FileNotFoundException("公钥文件未找到!");

                   }

                   if (f ==null) {

                            thrownew FileNotFoundException("发送方没有发送文件!");

                   }

                   // 读取公钥文件得到公钥

                   ObjectInputStream in = new ObjectInputStream(new FileInputStream(publicKeyFile));

                   PublicKey pk = (PublicKey) in.readObject();

                   in.close();

                  

                   // 读取发送方发送的文件,读入字节数组

                   byte[] data =new byte[(int) f.length()];

                   FileInputStream fis = new FileInputStream(f);

                   fis.read(data);

                  

                   // 读取发送方的签名文件

                   byte[] signData =new byte[(int) signedFile.length()];

                   FileInputStream fis2 = new FileInputStream(signedFile);

                   fis2.read(signData);

                   fis2.close();

                  

                   // 使用发送方的公钥验证签名

                   Signature sign = Signature.getInstance("DSA");

                   sign.initVerify(pk);

                   sign.update(data);

                   return sign.verify(signData);

         }

        

         public static void main(String[] args) {

                                     // 公钥文件

                                     String publicFileName = "public.key";

                                     // 签名文件

                                     String signedFileName = "signature.dtx";

                                     // 发送方发送的文件。

                                     File f = new File("d:/test.xml");

                                     File publicFile = new File(publicFileName);

                                     File sigendFile = new File(signedFileName);

                                    

                                     try {

                                               Receiver recv = new Receiver();

                                               // 接受方读取发送方提供的公钥文件验证签名是否一致

                                               boolean isOk = recv.receive(publicFile,sigendFile, f);

                                               if (isOk) {

                                                        log.info("接受方验证文件无篡改!");

                                               }

                                               else {

                                                        log.info("接受方验证文件被篡改!");

                                               }

                                     } catch (NoSuchAlgorithmException e) {

                                               // TODO Auto-generated catch block

                                               e.printStackTrace();

                                     } catch (FileNotFoundException e) {

                                               // TODO Auto-generated catch block

                                               e.printStackTrace();

                                     } catch (IOException e) {

                                               // TODO Auto-generated catch block

                                               e.printStackTrace();

                                     } catch (InvalidKeyException e) {

                                               // TODO Auto-generated catch block

                                               e.printStackTrace();

                                     } catch (SignatureException e) {

                                               // TODO Auto-generated catch block

                                               e.printStackTrace();

                                     } catch (ClassNotFoundException e) {

                                               // TODO Auto-generated catch block

                                               e.printStackTrace();

                                     }

         }

}

 

 

1.     运行Sender.java,生成公钥和私钥、签名写入文件。

2.     运行Receiver.java,使用发送方的公钥验证签名。

 

测试:执行1,生成3个文件:

调试信息:

DEBUG [main] - 已生成私钥文件:private.key,公钥文件:public.key

DEBUG [main] - 根据文件内容生成签名并写入签名文件完毕!

DEBUG [main] - 签名文件写入到signature.dtx

 

执行2,输出结果:

INFO [main] - 接受方验证文件无篡改!

 

现在修改文件d:/test.xml,再次执行2,输出结果:

INFO [main] - 接受方验证文件被篡改!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值