數字簽名在數據的交互中一直都佔據着很重要的地位,所以,這篇文章對其原理進行整理總結一下。最後再給出代碼的實現。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();
}
}
複製代碼
代碼已經在這裏了,能夠本身去實現一遍便可。