数字签名应用
-
引言
数字签名可以确保文件数据的完整性以及不可抵赖性。本次将使用Java语言来实现对文件的数字签名及验证,Java语言的JDK提供了丰富的密码学类库。本次采用了椭圆曲线ECDSA数字签名算法及SHA256散列算法,也可以通过简单的参数选取,使用SHA或其他签名算法。
-
环境及设备
Windows计算机一台,Java虚拟机 JDK 1.6 及以上版本。
-
步骤
-
将一个计算机中的文件中的所有内容读取到字节数组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); }
-
使用椭圆曲线签名算法,需要先得到椭圆曲线签名算法 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);
-
从对象pair中获取公钥,以十六进制方式输出公钥的内容。
//从pair中获取公钥 PublicKey pubKey = pair.getPublic(); //输出公钥字节内容 byte[] bytePubKey = pubKey.getEncoded(); String strPubKey = DatatypeConverter.printHexBinary(bytePubKey); System.out.printf("公钥:0x%s\n",strPubKey);
-
创建一个签名对象 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);
-
使用公钥 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("验证失败,签名不正确!");
-
若签名验证成功,则打印 “验证成功,签名正确!”,否则打印出 “验证失败,签名不正确!”。
-
-
实现
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 正在验证,请稍等------ 验证成功,签名正确!
上一篇: Scala MD5加密类
下一篇: 从文件路径获得文件名