Go 实现:椭圆曲线数字签名算法ECDSA
一、ECDSA概述
椭圆曲线数字签名算法(ECDSA)是使用椭圆曲线密码(ECC)对数字签名算法(DSA)的模拟。它基于椭圆曲线离散对数问题(ECDLP)的难解性,具有密钥短、速度快和安全性高的优点。与传统的离散对数问题(DLP)和大数分解问题(IFP)不同,椭圆曲线离散对数问题没有亚指数时间的解决方法,因此椭圆曲线密码的安全性更高。
二、ECDSA工作原理
ECDSA的签名过程包括以下步骤:
- 选择一条椭圆曲线Ep(a,b)和基点G;
- 选择私有密钥k(k<n,n为G的阶),利用基点G计算公开密钥K=kG;
- 产生一个随机整数r(r<n),计算点R=rG;
- 将原数据和点R的坐标值x,y作为参数,计算SHA1做为hash,即Hash=SHA1(原数据,x,y);
- 计算s≡r−Hash∗k(modn);
- r和s做为签名值,如果r和s其中一个为0,重新从第3步开始执行。
验证过程如下:
- 接受方在收到消息m和签名值r,s后,进行以下运算;
- 计算sG+H(m)P=(x1,y1),r1≡x1modp;
- 验证等式:r1≡rmodp;
- 如果等式成立,接受签名,否则签名无效。
三、Go实现
1. 生成私钥和公钥,生成的私钥为结构体ecdsa.PrivateKey的指针
func NewKeyPair()(ecdsa.PrivateKey,[]byte){
//生成secp256椭圆曲线
curve := elliptic.P256()
//产生的是一个结构体指针,结构体类型为ecdsa.PrivateKey
private,err := ecdsa.GenerateKey(curve, rand.Reader)
if err != nil{
log.Panic(err)
}
fmt.Printf("私钥:%x\n", private)
fmt.Printf("私钥X:%x\n", private.X.Bytes())
fmt.Printf("私钥Y:%x\n", private.Y.Bytes())
fmt.Printf("私钥D:%x\n", private.D.Bytes())
//x坐标与y坐标拼接在一起生成公钥
pubKey := append(private.X.Bytes(),private.Y.Bytes()...)
//打印公钥,公钥用16进制打印出来长度为128,包含了x轴坐标与y轴坐标。
fmt.Printf("公钥:%x \n", pubKey)
return *private, pubKey
}
2.生成签名的DER格式
func MakeSignatureDerString(r,s string)string{
//获取R和S的长度
lenSigR := len(r)/2
lenSigS := len(s)/2
//计算DER序列的总长度
lenSequence := lenSigR + lenS