Java 实现 RSA、DSA、ECDSA 算法的签名与验签

4,158 阅读4分钟
原文链接: congcong.us

签名算法重要性简介

作为支付等安全性较高要求性的行业来说,签名与验签是必不可少的。一般均会双方约定一定的算法,将上送的参数进行拼接,通过MD5key拼接后摘要,或者其他的如RSA、DSA、ECDSA中的私钥进行签名。 同理对方拿到之后,会按照相同算法进行拼接,通过MD5Key拼接进行摘要或者公钥进行验签操作,来保证双方传输的数据没有被篡改。

总结:签名和验签的目的是什么呢?保证信息不被篡改!

将常用的RSA、DSA、ECDSA采用公私钥进行签名与验签,相较于其他,更安全的保护了私钥不因对方而泄露,现总结了一下,使用Java语言进行实现,以作留档。

三种算法简单比较

RSA

既可以做签名,又可以做加密。安全性基于大数分解。

DSA

主要用作签名验签,安全性依赖于判断乘方阶速度较慢。

ECDSA椭圆曲线签名算法

比特币协议里使用了这种算法,协议框架与DSA基本一致。只不过ECDSA使用的椭圆函数域,而DSA使用普通乘法域

共性:

签名者持有私钥,对应公钥向全世界公开。当需要对信息签名时,签名者用私钥对信息签名,然后将签名信息和信息原文发给对方(RSA协议中,信息原文不需要发给对方,签名信息解密后就是信息原文),验证者可用签名者公开的公钥对签名信息和信息原文验证签名。由于信息长度可能比较长,在实际操作中,大家通常在信息的HASH摘要上进行签名。

下载实现代码

其中签名和验签算法对JDK没有过高的要求,测试中有使用JDK1.8的方法,所以建议使用JDK1.8环境,demo项目是maven工程,使用Junit4进行测试,可以直接运行mvn compile test

下载地址:https://git.oschina.net/accacc/java_demos.git

签名算法实现

实现签名算法最终实现了什么呢?其实就是提取摘要,双方校验摘要是否一致。

RSA签名与验签过程

//构建秘钥,这里选择RSA方式;initialize(512)RSA秘钥位数,这里需要注意

KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("DSA");
keyPairGenerator.initialize(512);
KeyPair keyPair = keyPairGenerator.generateKeyPair();

byte[] privateKey = keyPair.getPrivate().getEncoded();
byte[] publicKey = keyPair.getPublic().getEncoded();

进行调用

byte[] sign = DSAUtils.sign(content.getBytes(), privateKey);
System.out.println("dsa sign:"+Base64.getEncoder().encodeToString(sign));
assertTrue(sign.length==64);

Boolean flag = DSAUtils.verify(content.getBytes(), sign, publicKey);
System.out.println("dsa verify:"+flag);
assertTrue(flag);

签名算法实现细节

//单例获取key工厂类,将拿到的privateKey创建PKCS8EncodedKeySpec对象,通过其获取PrivateKey对象
KeyFactory keyFactory = KeyFactory.getInstance("RSA");  
PrivateKey priKey = keyFactory.generatePrivate(new PKCS8EncodedKeySpec(privateKey));

//获取Signature对象,签名算法为SHA1WithRSA,此处还有较多可选择比如MD2withRSA/MD5withRSA/SHA1withRSA/SHA256withRSA等
Signature signature = Signature.getInstance("SHA1WithRSA");
signature.initSign(priKey);
signature.update(content);
byte[] encodeResult = signature.sign();

return encodeResult;

验签算法实现细节

//单例获取key工厂类,将拿到的publicKey创建X509EncodedKeySpec对象,通过其获取PublicKey对象
KeyFactory keyFactory = KeyFactory.getInstance("RSA");  
PublicKey pubKey = keyFactory.generatePublic(new X509EncodedKeySpec(publicKey));      

//获取Signature对象,签名算法为SHA1WithRSA,此处还有较多可选择比如MD2withRSA/MD5withRSA/SHA1withRSA/SHA256withRSA等
Signature signature = Signature.getInstance("SHA1WithRSA");     
signature.initVerify(pubKey);  
signature.update( content );   
boolean bverify = signature.verify( sign );  

return bverify;  

DSA签名与验签过程

//构建秘钥,这里选择DSA方式;initialize(512)DSA秘钥位数,这里需要注意

KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("DSA");
keyPairGenerator.initialize(512);
KeyPair keyPair = keyPairGenerator.generateKeyPair();

byte[] privateKey = keyPair.getPrivate().getEncoded();
byte[] publicKey = keyPair.getPublic().getEncoded();

进行调用

byte[] sign = DSAUtils.sign(content.getBytes(), privateKey);
System.out.println("dsa sign:"+Base64.getEncoder().encodeToString(sign));
assertTrue(sign.length==64);

Boolean flag = DSAUtils.verify(content.getBytes(), sign, publicKey);
System.out.println("dsa verify:"+flag);
assertTrue(flag);

签名算法实现细节

//单例获取key工厂类,将拿到的privateKey创建PKCS8EncodedKeySpec对象,通过其获取PrivateKey对象
KeyFactory keyFactory = KeyFactory.getInstance("DSA");  
PrivateKey priKey = keyFactory.generatePrivate(new PKCS8EncodedKeySpec(privateKey));

//获取Signature对象,签名算法为SHA1WithRSA
Signature signature = Signature.getInstance("SHA1withDSA");
signature.initSign(priKey);
signature.update(content);
byte[] encodeResult = signature.sign();

验签算法实现细节

//单例获取key工厂类,将拿到的publicKey创建X509EncodedKeySpec对象,通过其获取PublicKey对象
KeyFactory keyFactory = KeyFactory.getInstance("DSA");  
PublicKey pubKey = keyFactory.generatePublic(new X509EncodedKeySpec(publicKey));      

//获取Signature对象,签名算法为SHA1withDSA
Signature signature = Signature.getInstance("SHA1withDSA");     
signature.initVerify(pubKey);  
signature.update( content );   
boolean bverify = signature.verify( sign ); 

DSA签名与验签过程

//构建秘钥,这里选择DSA方式;initialize(512)DSA秘钥位数,这里需要注意

KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("DSA");
keyPairGenerator.initialize(512);
KeyPair keyPair = keyPairGenerator.generateKeyPair();

byte[] privateKey = keyPair.getPrivate().getEncoded();
byte[] publicKey = keyPair.getPublic().getEncoded();

进行调用

byte[] sign = DSAUtils.sign(content.getBytes(), privateKey);
System.out.println("dsa sign:"+Base64.getEncoder().encodeToString(sign));
assertTrue(sign.length==64);

Boolean flag = DSAUtils.verify(content.getBytes(), sign, publicKey);
System.out.println("dsa verify:"+flag);
assertTrue(flag);

签名算法实现细节

//单例获取key工厂类,将拿到的privateKey创建PKCS8EncodedKeySpec对象,通过其获取PrivateKey对象
KeyFactory keyFactory = KeyFactory.getInstance("EC");  
PrivateKey priKey = keyFactory.generatePrivate(new PKCS8EncodedKeySpec(privateKey));

//获取Signature对象,签名算法为SHA1withDSA,此处还有较多可选择比如MD5withDSA等
Signature signature = Signature.getInstance("SHA1withECDSA");
signature.initSign(priKey);
signature.update(content);
byte[] encodeResult = signature.sign();

验签算法实现细节

//单例获取key工厂类,将拿到的publicKey创建X509EncodedKeySpec对象,通过其获取PublicKey对象
KeyFactory keyFactory = KeyFactory.getInstance("EC");  
PublicKey pubKey = keyFactory.generatePublic(new X509EncodedKeySpec(publicKey));      

//获取Signature对象,签名算法为SHA1withDSA,此处还有较多可选择比如MD5withDSA等
Signature signature = Signature.getInstance("SHA1withECDSA");     
signature.initVerify(pubKey);  
signature.update( content );   
boolean bverify = signature.verify( sign );  

以上即为三种算法的原生实现。