您的位置:首页 > 其它

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

2013-01-28 22:30 351 查看
基本原理:

发送方:

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.key和public.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] - 接受方验证文件被篡改!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: