自学内容网 自学内容网

DSA 和 ECDSA 签名算法

基本介绍

DSA 是一种基于离散对数问题的数字签名算法。它使用私钥和公钥对来进行签名和验证操作。
ECDSA 是基于椭圆曲线密码体制(ECC)的数字签名算法。它利用椭圆曲线上的点的运算来实现签名和验证功能。同样也是使用非对称密钥对进行签名、验签。
它们底层都是基于hash进行一系列运算

虽然这两算法在实际工作种还没用到,但是RSA的签名都用过。虽然在实现算法上天差地别,但对于开发者使用角度而言。
到道理都类似,私钥签名、公钥验签

Java实现

算法聚合名称:

  • SHA256withECDSA
  • SHA256withDSA
    其他hash算法名类似。看起来类似RSA的签名名称风格。其实使用也是类似的

DSA

创建密钥对
KeyPairGenerator pairGenerator = KeyPairGenerator.getInstance("DSA");
pairGenerator.initialize(2048);
KeyPair keyPair = pairGenerator.genKeyPair();
签名
byte[] plain = "Hello World".getBytes(StandardCharsets.UTF_8);
Signature signature = Signature.getInstance("SHA256withDSA");
signature.initSign(keyPair.getPrivate());
signature.update(plain);
byte[] sign = signature.sign();
System.out.println("签名:" + Base64.getEncoder().encodeToString(sign));
验签
Signature signature = Signature.getInstance("SHA256withDSA");
signature.initSign(keyPair.getPrivate());
signature.update(plain);
byte[] sign = signature.sign();
System.out.println("签名:" + Base64.getEncoder().encodeToString(sign));

// 验签
signature.initVerify(keyPair.getPublic());
signature.update(plain);
boolean verify = signature.verify(sign);
System.out.println("验签结果:" + verify);

ECDSA

创建密钥对
KeyPairGenerator pairGenerator = KeyPairGenerator.getInstance("EC");
// 基于椭圆的复杂度,并不是直接指定长度,而是指定不同的曲线类型
// 同样后面的数字代表密钥位数常用的有【secp256r1、secp384r1、secp521r1】
ECGenParameterSpec ecGenParameterSpec = new ECGenParameterSpec("secp256r1");
pairGenerator.initialize(ecGenParameterSpec);
KeyPair keyPair = pairGenerator.genKeyPair();
签名
Signature signature = Signature.getInstance("SHA256withECDSA");
signature.initSign(keyPair.getPrivate());
signature.update(plain);
byte[] sign = signature.sign();
System.out.println("签名:" + Base64.getEncoder().encodeToString(sign));
验签
byte[] plain = "Hello World".getBytes(StandardCharsets.UTF_8);
Signature signature = Signature.getInstance("SHA256withECDSA");
signature.initSign(keyPair.getPrivate());
signature.update(plain);
byte[] sign = signature.sign();
System.out.println("签名:" + Base64.getEncoder().encodeToString(sign));

// 验签
signature.initVerify(keyPair.getPublic());
signature.update(plain);
boolean verify = signature.verify(sign);
System.out.println("验签结果:" + verify);

Go实现

Go种的API并没有像Java一样封装度很高,在实际使用种虽然没有那么简单。但可以了解一些更偏本质的东西。

ECDSA

创建密钥对
p256 := elliptic.P256()
privateKey, _ := ecdsa.GenerateKey(p256, rand.Reader)
签名

签名对象先进行hash运算

message := "Hello World"
// 进行hash运算
plain := sha256.Sum256([]byte(message))
r, s, _ := ecdsa.Sign(rand.Reader, privateKey, plain[:])
// r,s拼接在一起构成签名,同样在验签的时候,以相同规则解析【只要双方规则一致,随便怎么拼】
sign := append(r.Bytes(), s.Bytes()...)
p("ECDSA签名:", base64.StdEncoding.EncodeToString(sign))
验签

签名对象先进行hash运算

// 对明文消息进行SHA256哈希计算
hash := sha256.Sum256([]byte(message))
// 从签名字节切片中拆分出r和s部分,并转换为big.Int类型【r s 长度是一致的,直接按中间分可以分别解析出 r s】
r2 := new(big.Int).SetBytes(sign[:len(sign)/2])
s2 := new(big.Int).SetBytes(sign[len(sign)/2:])
// 利用公钥和消息hash切片以及 r  s  进行验签
verify := ecdsa.Verify(&privateKey.PublicKey, hash[:], r2, s2)
p("验签结果:", verify)

DSA

创建密钥对
privateLey := &dsa.PrivateKey{}
dsa.GenerateParameters(&privateLey.Parameters, rand.Reader, dsa.L2048N256)
err := dsa.GenerateKey(privateLey, rand.Reader)
if err != nil {
panic(err)
}
签名

我们这里还是将 r s 直接拼在一起

plain := []byte("Hello World")
plainHash := sha256.Sum256(plain)

r, s, err := dsa.Sign(rand.Reader, privateLey, plainHash[:])
signBytes := append(r.Bytes(), s.Bytes()...)
p("签名:", base64.StdEncoding.EncodeToString(signBytes))
验签

new(big.Int).SetBytes(r1) :字节切片构建成big.Int

// 按照签名拼接规则,分别取出 r s
r1 := signBytes[:len(signBytes)/2]
s1 := signBytes[len(signBytes)/2:]

// 使用 new(big.Int).SetBytes(r1) 将字节切片构建为big.Int对象
verify := dsa.Verify(&privateLey.PublicKey, plainHash[:], new(big.Int).SetBytes(r1), new(big.Int).SetBytes(s1))
p("验签结果:", verify)

原文地址:https://blog.csdn.net/tergou/article/details/144303622

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!