数字签名在数据的交互中一直都占据着很重要的地位,所以,这篇文章对其原理进行整理总结一下。最后再给出代码的实现。java
1、简单认识算法
相信咱们都写过信,在写信的时候落款处老是要留下本身的名字,用来表示写信的人是谁。咱们签的这个字就是生活中的签名:安全
而数字签名呢?其实也是一样的道理,他的含义是:在网络中传输数据时候,给数据添加一个数字签名,表示是谁发的数据,并且还能证实数据没有被篡改。网络
OK,数字签名的主要做用就是保证了数据的有效性(验证是谁发的)和完整性(证实信息没有被篡改)。下面咱们就来好好的看一下他的底层实现原理是什么样子的。函数
2、基本原理加密
为了理解的清楚,咱们经过案例一步一步来说解。话说张三有俩好哥们A、B。因为工做缘由,张三和AB写邮件的时候为了安全都须要加密。因而张三想到了数字签名:spa
整个思路是这个样子的:3d
第一步:加密采用非对称加密,张三有三把钥匙,两把公钥,送给朋友。一把私钥留给本身。code
第二步:A或者B写邮件给张三:A先用公钥对邮件加密,而后张三收到邮件以后使用私钥解密。cdn
第三步:张三写邮件给A或者B:
(1)张三写完邮件,先用hash函数生成邮件的摘要,附着在文章上面,这就完成了数字签名,而后张三再使用私钥加密。就能够把邮件发出去了。
(2)A或者是B收到邮件以后,先把数字签名取下来,而后使用本身的公钥解密便可。这时候取下来的数字签名中的摘要若和张三的一致,那就认为是张三发来的,珊再对信件自己使用Hash函数,将获得的结果,与上一步获得的摘要进行对比。若是二者一致,就证实这封信未被修改过。
上面的流程咱们使用一张图来演示一下:
首先把公钥送给朋友A和B:
而后呢,就是朋友A或者B给张三发邮件:
还有就是最后一个比较麻烦的,张三给A或者B发邮件:
OK,上面的这几张图想必你应该可以理解清楚了,其实还有一些很复杂的状况,由于上面的数字签名是在理想状态下完成的,可是若是遇到了公钥错误,摘要不正确该如何处理呢?这里就涉及到数字证书了,咱们来分析一下。
3、数字证书
上面提到咱们对签名进行验证时,须要用到公钥。若是公钥是伪造的,那咱们没法验证数字签名了,也就根本不可能从数字签名肯定对方的合法性了。这时候证书就闪亮登场了。咱们可能都有考各类证书的经历,好比说普通话证书,四六级证书等等,可是归根结底,到任何场合咱们都能拿出咱们的证书来证实本身确实已经考过了普通话,考过了四六级。这里的证书也是一样的道理。
若是不理解证书的做用,咱们能够举一个例子,好比说咱们的毕业证书,任何公司都会认可。为何会认可?由于那是国家发的,你们都信任国家。也就是说只要是国家的认证机构,咱们都信任它是合法的。
那么这个证书是如何生成的呢?咱们再来看一张图:
此时即便张三的朋友A把公钥弄错了,张三也能够经过这个证书验证。
4、代码验证
经常使用的数字签名算法有:RSA、DSA、ECDSA。这里的代码参考了慕课网。下面给出三种方式的代码实现:
一、RSA
public static void jdkRSA() {
try {
//1.初始化密钥
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(512);
KeyPair keyPair = keyPairGenerator.generateKeyPair();
RSAPublicKey rsaPublicKey = (RSAPublicKey)keyPair.getPublic();
RSAPrivateKey rsaPrivateKey = (RSAPrivateKey)keyPair.getPrivate();
//2.执行签名
PKCS8EncodedKeySpec pkcs8EncodedKeySpec =
new PKCS8EncodedKeySpec(rsaPrivateKey.getEncoded());
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
Signature signature = Signature.getInstance("MD5withRSA");
signature.initSign(privateKey);
signature.update(src.getBytes());
byte[] result = signature.sign();
//3.验证签名
X509EncodedKeySpec x509EncodedKeySpec =
new X509EncodedKeySpec(rsaPublicKey.getEncoded());
keyFactory = KeyFactory.getInstance("RSA");
PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
signature = Signature.getInstance("MD5withRSA");
signature.initVerify(publicKey);
signature.update(src.getBytes());
boolean bool = signature.verify(result);
System.out.println("jdk rsa verify : " + bool);
} catch (Exception e) {
e.printStackTrace();
}
}
复制代码
二、DSA
public static void jdkDSA() {
try {
//1.初始化密钥
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("DSA");
keyPairGenerator.initialize(512);
KeyPair keyPair = keyPairGenerator.generateKeyPair();
DSAPublicKey dsaPublicKey = (DSAPublicKey) keyPair.getPublic();
DSAPrivateKey dsaPrivateKey = (DSAPrivateKey)keyPair.getPrivate();
//2.执行签名
PKCS8EncodedKeySpec pkcs8EncodedKeySpec =
new PKCS8EncodedKeySpec(dsaPrivateKey.getEncoded());
KeyFactory keyFactory = KeyFactory.getInstance("DSA");
PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
Signature signature = Signature.getInstance("SHA1withDSA");
signature.initSign(privateKey);
signature.update(src.getBytes());
byte[] result = signature.sign();
System.out.println("jdk dsa sign : " + Hex.encodeHexString(result));
//3.验证签名
X509EncodedKeySpec x509EncodedKeySpec =
new X509EncodedKeySpec(dsaPublicKey.getEncoded());
keyFactory = KeyFactory.getInstance("DSA");
PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
signature = Signature.getInstance("SHA1withDSA");
signature.initVerify(publicKey);
signature.update(src.getBytes());
boolean bool = signature.verify(result);
System.out.println("jdk dsa verify : " + bool);
} catch (Exception e) {
e.printStackTrace();
}
}
复制代码
三、ECDSA
public static void jdkECDSA() {
try {
//1.初始化密钥
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("EC");
keyPairGenerator.initialize(256);
KeyPair keyPair = keyPairGenerator.generateKeyPair();
ECPublicKey ecPublicKey = (ECPublicKey)keyPair.getPublic();
ECPrivateKey ecPrivateKey = (ECPrivateKey)keyPair.getPrivate();
//2.执行签名
PKCS8EncodedKeySpec pkcs8EncodedKeySpec =
new PKCS8EncodedKeySpec(ecPrivateKey.getEncoded());
KeyFactory keyFactory = KeyFactory.getInstance("EC");
PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
Signature signature = Signature.getInstance("SHA1withECDSA");
signature.initSign(privateKey);
signature.update(src.getBytes());
byte[] result = signature.sign();
System.out.println("jdk ecdsa sign : " + Hex.encodeHexString(result));
//3.验证签名
X509EncodedKeySpec x509EncodedKeySpec =
new X509EncodedKeySpec(ecPublicKey.getEncoded());
keyFactory = KeyFactory.getInstance("EC");
PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
signature = Signature.getInstance("SHA1withECDSA");
signature.initVerify(publicKey);
signature.update(src.getBytes());
boolean bool = signature.verify(result);
System.out.println("jdk ecdsa verify : " + bool);
} catch (Exception e) {
e.printStackTrace();
}
}
复制代码
代码已经在这里了,能够本身去实现一遍便可。