文章目录
- 概述
- 应用
- 常用数字签名算法
- 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等),用于生成和验证数字签名,以实现数据的安全传输和验证。