文章目錄
- 概述
- 應用
- 常用數字簽名算法
- Code
- DSA簽名
- ECDSA簽名
- 小結
概述
在非對稱加密中,使用私鑰加密、公鑰解密確實是可行的,而且有著特定的應用場景,即數字簽名。
數字簽名的主要目的是確保消息的完整性、真實性和不可否認性。通過使用私鑰加密消息,發送者相當于對消息進行了簽名,因為只有發送者擁有私鑰,所以只有發送者能夠生成正確的簽名。然后,其他人可以使用發送者的公鑰來驗證簽名,確保消息確實是由發送者簽署的。
這種方式確保了消息的真實性和不可否認性,因為只有私鑰的持有者才能夠生成正確的簽名,其他人無法偽造。同時,公鑰的持有者可以通過驗證簽名來確認消息的完整性和真實性。
因此,私鑰加密產生的密文通常被用作數字簽名,而公鑰則用于驗證簽名的有效性。這種方法在保護通信內容的完整性和發送方身份方面發揮著重要作用,是數字證書和加密通信中常用的技術手段之一。
私鑰加密得到的密文實際上就是數字簽名,要驗證這個簽名是否正確,只能用私鑰持有者的公鑰進行解密驗證。使用數字簽名的目的是為了確認某個信息確實是由某個發送方發送的,任何人都不可能偽造消息,并且,發送方也不能抵賴
應用
實際應用中,對消息的簽名不直接針對原始消息,而是對消息的哈希值進行簽名,以提高效率和安全性。這樣做的好處是,哈希值通常較短且固定長度,而且哈希值的簽名不會受到消息長度的影響,同時仍然能夠確保消息的完整性和真實性。
signature = encrypt(privateKey, sha256(message))
簽名驗證過程也是類似的,對簽名進行解密得到簽名的哈希值,然后與原始消息的哈希值進行比較,以確認簽名的有效性和消息的完整性。
hash = decrypt(publicKey, signature)
私鑰用于簽名,相當于用戶的身份標識,只有持有私鑰的用戶才能夠生成正確的簽名。公鑰用于驗證簽名,通過驗證簽名的有效性,可以確認消息確實是由具有對應私鑰的用戶簽名的。這種方式確保了消息的真實性、完整性和發送方的身份認證,是數字簽名在安全通信中的重要應用之一。
常用數字簽名算法
-
RSA with SHA-256(SHA256withRSA):結合了RSA非對稱加密算法和SHA-256哈希算法。SHA-256產生的哈希值長度為256位,提供了較高的安全性。
-
RSA with SHA-1(SHA1withRSA):同樣結合了RSA非對稱加密算法和SHA-1哈希算法。然而,由于SHA-1存在碰撞攻擊的漏洞,因此不推薦在新的應用中使用。
-
RSA with MD5(MD5withRSA):結合了RSA非對稱加密算法和MD5哈希算法。然而,MD5也存在碰撞攻擊的漏洞,因此也不推薦在安全性要求較高的應用中使用。
-
ECDSA with SHA-256:基于橢圓曲線數字簽名算法(ECDSA)和SHA-256哈希算法,提供了與RSA相當的安全性,但在相同安全級別下使用更短的密鑰。
-
ECDSA with SHA-1:同樣基于ECDSA和SHA-1哈希算法。然而,由于SHA-1的安全性問題,不推薦在新的應用中使用。
-
DSA with SHA-1:基于數字簽名算法(DSA)和SHA-1哈希算法。與ECDSA相比,DSA在相同安全級別下需要更長的密鑰長度。
在實際應用中,推薦使用RSA with SHA-256
或ECDSA with SHA-256
等結合了安全性和效率的數字簽名算法。同時,為了確保安全性,應選擇安全性較高的哈希算法,并定期更新密鑰以及使用更長的密鑰長度。
Code
以下是帶有中文注釋的代碼:
package com.artisan.securityalgjava.sig;import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.security.*;public class SignatureTest {public static void main(String[] args) throws Exception {// 生成RSA公鑰/私鑰:KeyPairGenerator kpGen = KeyPairGenerator.getInstance("RSA");kpGen.initialize(1024);KeyPair kp = kpGen.generateKeyPair();PrivateKey sk = kp.getPrivate(); // 獲取私鑰PublicKey pk = kp.getPublic(); // 獲取公鑰// 待簽名的消息:byte[] message = "Hello, I am Artisan!".getBytes(StandardCharsets.UTF_8);// 用私鑰簽名:Signature s = Signature.getInstance("SHA1WithRSA"); // 獲取SHA1WithRSA簽名算法的實例s.initSign(sk); // 初始化Signature對象,指定使用私鑰進行簽名s.update(message); // 更新要簽名的消息byte[] signed = s.sign(); // 對消息進行簽名System.out.println(String.format("signature: %x", new BigInteger(1, signed))); // 打印簽名結果// 用公鑰驗證:Signature v = Signature.getInstance("SHA1withRSA"); // 獲取SHA1withRSA簽名算法的實例v.initVerify(pk); // 初始化Signature對象,指定使用公鑰進行驗證v.update(message); // 更新要驗證的消息boolean valid = v.verify(signed); // 驗證簽名System.out.println("valid? " + valid); // 打印驗證結果}
}
使用了Java的Signature
類來進行數字簽名和驗證。它生成了RSA公鑰和私鑰,并使用私鑰對消息進行簽名,然后使用公鑰驗證簽名的有效性。簽名算法選擇了SHA1WithRSA
。
DSA簽名
DSA(Digital Signature Algorithm)是一種與RSA不同的數字簽名算法,它使用了ElGamal數字簽名算法的變種。DSA的設計目的是為了提供與RSA相當的安全性,同時在簽名和驗證速度上更快。
DSA常與SHA(Secure Hash Algorithm)哈希算法結合使用,常用的DSA算法有:
-
SHA1withDSA:使用SHA-1哈希算法和DSA進行數字簽名。
-
SHA256withDSA:使用SHA-256哈希算法和DSA進行數字簽名。
-
SHA512withDSA:使用SHA-512哈希算法和DSA進行數字簽名。
這些算法與RSA相比,具有更快的簽名速度。因此,在對性能要求較高的場景中,可以考慮使用DSA算法進行數字簽名。
但由于SHA-1存在安全性問題,因此不推薦使用SHA1withDSA。在現代應用中,推薦使用更安全的哈希算法,例如SHA-256或SHA-512結合DSA進行數字簽名。
ECDSA簽名
ECDSA(Elliptic Curve Digital Signature Algorithm)
是一種基于橢圓曲線的數字簽名算法,它與DSA類似,但使用了橢圓曲線來提供相同或更高的安全性。
ECDSA的特點包括:
-
基于橢圓曲線:與RSA和DSA相比,ECDSA使用橢圓曲線算法來實現數字簽名,這使得它能夠在保持相同安全級別的情況下使用更短的密鑰長度。
-
私鑰推出公鑰:與RSA不同,ECDSA的私鑰可以推導出對應的公鑰,這使得密鑰管理更加靈活。
-
高效性能:ECDSA在簽名和驗證過程中具有較高的性能表現,尤其適用于資源受限的環境。
在加密貨幣領域,比特幣等加密貨幣通常使用ECDSA算法進行數字簽名。比特幣采用的橢圓曲線標準是secp256k1,這是一種特定的橢圓曲線參數集。
BouncyCastle
庫提供了ECDSA
的完整實現,可以用于生成密鑰對、簽名和驗證操作。利用BouncyCastle
,開發者可以輕松地在Java應用程序中使用ECDSA算法進行數字簽名。
小結
數字簽名是一種基于非對稱加密算法的技術,用于確保數據的完整性、真實性和不可否認性。發送方使用私鑰對原始數據進行簽名,而接收方使用發送方的公鑰來驗證簽名的有效性。
數字簽名的主要作用包括:
-
防止偽造:由于只有發送方擁有私鑰,因此只有發送方能夠生成正確的簽名。這樣,接收方可以通過驗證簽名來確認數據的來源,從而防止偽造。
-
防止抵賴:由于數字簽名是由發送方的私鑰生成的,因此發送方不能夠抵賴曾經生成過的簽名。接收方可以利用簽名來證明數據確實是由發送方發送的,從而防止發送方否認其責任。
-
檢測篡改:數字簽名還可以用于檢測數據的篡改。如果數據在傳輸過程中發生了篡改,那么其簽名也會失效,因為簽名是基于原始數據生成的。接收方可以通過驗證簽名來確定數據是否經過了篡改。
常用的數字簽名算法包括MD5withRSA、SHA1withRSA、SHA256withRSA、SHA1withDSA、SHA256withDSA、SHA512withDSA、ECDSA
等。這些算法結合了哈希算法(如MD5、SHA-1、SHA-256等)和非對稱加密算法(如RSA、DSA、ECDSA等),用于生成和驗證數字簽名,以實現數據的安全傳輸和驗證。