数字签名应用

  • 引言

    数字签名可以确保文件数据的完整性以及不可抵赖性。本次将使用Java语言来实现对文件的数字签名及验证,Java语言的JDK提供了丰富的密码学类库。本次采用了椭圆曲线ECDSA数字签名算法及SHA256散列算法,也可以通过简单的参数选取,使用SHA或其他签名算法。

  • 环境及设备

    Windows计算机一台,Java虚拟机 JDK 1.6 及以上版本。

  • 步骤

    1. 将一个计算机中的文件中的所有内容读取到字节数组bytes中,需要保证计算机中存在这个文件。

      byte[] bytes = {};
      try {
      	//获取计算机中文件名 d:\\test.txt的路径
      	Path path = Paths.get("d:\\test.txt");
      			
      	//从文件读取内容到字节数组byte[]中
      	bytes = Files.readAllBytes(path);
      }catch(Exception e){
      	System.out.println("文件读取错误" + e);
      }
      
    2. 使用椭圆曲线签名算法,需要先得到椭圆曲线签名算法 EC 的生成密钥类 KeyPairGenerator 的一个实例 keyPairGen, 然后初始化 keyPairGen,对于椭圆曲线算法,密钥长度最低为112,生成一对密钥,其中包括了公钥和私钥,存入对象 pair 中,并以十六进制方式输出私钥的内容。

      //使用椭圆曲线签名算法,需要得到椭圆曲线算法的密钥生成一个实例keyPairGen
      KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("EC");
      		
      //初始化密钥对生成器,对椭圆曲线算法,参数最低为112
      keyPairGen.initialize(112);
      		
      //生成一对密钥,其中包括公钥和私钥,存入对象pair中;
      KeyPair pair = keyPairGen.generateKeyPair();
      		
      //从pair中获取私钥
      PrivateKey privKey = pair.getPrivate();
      		
      //输出私钥内容
      byte[] bytePrivKey = privKey.getEncoded();
      String strPrivKey = DatatypeConverter.printHexBinary(bytePrivKey);
      System.out.printf("私钥:0x%s\n",strPrivKey);
      
    3. 从对象pair中获取公钥,以十六进制方式输出公钥的内容。

      //从pair中获取公钥
      PublicKey pubKey = pair.getPublic();
      //输出公钥字节内容
      byte[] bytePubKey = pubKey.getEncoded();
      String strPubKey = DatatypeConverter.printHexBinary(bytePubKey);
      System.out.printf("公钥:0x%s\n",strPubKey);
      
    4. 创建一个签名对象 sign。使用 SHA256 算法作为散列函数,椭圆曲线签名算法 ECDSA 作为签名算法。用私钥 pairKry 来初始化签名对象 sign。然后使用签名对象 sign 的 update 方法加载需要签名的字节数组的内容 bytes,再使用 sign 方法生成签名;以十六进制字节方法打印 bytes 的签名值。

      //创建一个签名对象sign,使用SHA256算法作为散列函数,椭圆曲线签名算法ECDSA作为签名算法
      Signature sign = Signature.getInstance("SHA256withECDSA");
      		
      //用私钥privKey来初始化签名对象sign
      sign.initSign(privKey);
      		
      //签名对象sign加载需要签名的字节数组内容bytes
      sign.update(bytes);
      		
      //生成签名
      byte[] signature = sign.sign();
      		
      //以十六进制字节方式打印出bytes的签名值
      String strSign = DatatypeConverter.printHexBinary(signature);
      System.out.printf("签名内容:0x%s\n",strSign);
      
    5. 使用公钥 pubKey 对签名进行验证。创建一个签名对象 veriSign ,使用 SHA256 算法作为散列函数,椭圆曲线签名算法 ECDSA 作为签名算法。使用公钥 pubKey 来初始化签名对象 VeriSign ,签名对象VeriSign 加载需要验证签名的字节数组内容 bytes。VeriSign 使用公钥 pubKey 对 bytes 进行验证。

      //使用公钥pubKey对签名进行验证
      System.out.println("正在验证,请稍等------");
      		
      //创建一个签名对象veriSign,使用SHA256算法作为散列函数,椭圆曲线签名算法ECDSA作为签名算法
      Signature veriSign = Signature.getInstance("SHA256withECDSA");
      		
      //使用公钥pubKey来初始化签名对象VeriSign
      veriSign.initVerify(pubKey);
      		
      //签名对象veriSign加载需要验证签名的字节数组的内容bytes
      veriSign.update(bytes);;
      		
      //签名对象veriSign使用公钥pubKey对bytes的签名signature进行验证
      boolean ok = veriSign.verify(signature);
      if(ok)
      	System.out.println("验证成功,签名正确!");
      else
      	System.out.println("验证失败,签名不正确!");
      
    6. 若签名验证成功,则打印 “验证成功,签名正确!”,否则打印出 “验证失败,签名不正确!”。

  • 实现

    package digitalsignature;
    
    import java.nio.file.Files;
    import java.nio.file.Path;
    import java.nio.file.Paths;
    import java.security.KeyPair;
    import java.security.KeyPairGenerator;
    import java.security.PrivateKey;
    import java.security.PublicKey;
    import java.security.Signature;
    import javax.xml.bind.DatatypeConverter;
    
    /** 
    * @author renhongchang
    * @version 创建时间:2021年5月31日 下午2:57:08 
    * @blog https://rhc-rgb.github.io
    * 
    * 随计算机中的一个文件使用椭圆曲线算法生成数字签名
    * 然后对该文件的数字签名进行验证
    */
    public class DigitalSignature {
    
    	public static void main(String[] args) throws Exception {
    		byte[] bytes = {};
    		try {
    			//获取计算机中文件名 d:\\test.txt的路径
    			Path path = Paths.get("d:\\test.txt");
    			
    			//从文件读取内容到字节数组byte[]中
    			bytes = Files.readAllBytes(path);
    		}catch(Exception e){
    			System.out.println("文件读取错误" + e);
    		}
    		
    		
    		//使用椭圆曲线签名算法,需要得到椭圆曲线算法的密钥生成一个实例keyPairGen
    		KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("EC");
    		
    		//初始化密钥对生成器,对椭圆曲线算法,参数最低为112
    		keyPairGen.initialize(112);
    		
    		//生成一对密钥,其中包括公钥和私钥,存入对象pair中;
    		KeyPair pair = keyPairGen.generateKeyPair();
    		
    		//从pair中获取私钥
    		PrivateKey privKey = pair.getPrivate();
    		
    		//输出私钥内容
    		byte[] bytePrivKey = privKey.getEncoded();
    		String strPrivKey = DatatypeConverter.printHexBinary(bytePrivKey);
    		System.out.printf("私钥:0x%s\n",strPrivKey);
    		
    		
    		//从pair中获取公钥
    		PublicKey pubKey = pair.getPublic();
    		//输出公钥字节内容
    		byte[] bytePubKey = pubKey.getEncoded();
    		String strPubKey = DatatypeConverter.printHexBinary(bytePubKey);
    		System.out.printf("公钥:0x%s\n",strPubKey);
    		
    		
    		//创建一个签名对象sign,使用SHA256算法作为散列函数,椭圆曲线签名算法ECDSA作为签名算法
    		Signature sign = Signature.getInstance("SHA256withECDSA");
    		
    		//用私钥privKey来初始化签名对象sign
    		sign.initSign(privKey);
    		
    		//签名对象sign加载需要签名的字节数组内容bytes
    		sign.update(bytes);
    		
    		//生成签名
    		byte[] signature = sign.sign();
    		
    		//以十六进制字节方式打印出bytes的签名值
    		String strSign = DatatypeConverter.printHexBinary(signature);
    		System.out.printf("签名内容:0x%s\n",strSign);
    		
    		//使用公钥pubKey对签名进行验证
    		System.out.println("正在验证,请稍等------");
    		
    		//创建一个签名对象veriSign,使用SHA256算法作为散列函数,椭圆曲线签名算法ECDSA作为签名算法
    		Signature veriSign = Signature.getInstance("SHA256withECDSA");
    		
    		//使用公钥pubKey来初始化签名对象VeriSign
    		veriSign.initVerify(pubKey);
    		
    		//签名对象veriSign加载需要验证签名的字节数组的内容bytes
    		veriSign.update(bytes);;
    		
    		//签名对象veriSign使用公钥pubKey对bytes的签名signature进行验证
    		boolean ok = veriSign.verify(signature);
    		if(ok)
    			System.out.println("验证成功,签名正确!");
    		else
    			System.out.println("验证失败,签名不正确!");
    	}
    }
    
  • 实现结果

    私钥:0x302C020100301006072A8648CE3D020106052B8104000604153013020101040EAE0831C7D9E7F76ADF8A0B08D1DF
    公钥:0x3032301006072A8648CE3D020106052B81040006031E0004050A0BCE147FF9BFDDA2FD06BD748B983B600DD605296822BD59E317
    签名内容:0x3020020E3CBFF953DC7C15041DDC01A56704020E51949B5868C2123534E39ABA2F03
    正在验证,请稍等------
    验证成功,签名正确!
    
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值