一、椭圆曲线概述
椭圆曲线密码学(Elliptic curve cryptography),简称ECC,其和RAS类似属于公开秘钥的加密算法体系。ECC被公认为在给定密钥长度下最安全的加密算法。近年来由于比特币以太币等区块链应用ECC加密算法,业界也普遍看好ECC。
我们说过现代密码学是基于数学难题构建的,如RSA基于大数分解,ECC则基于椭圆曲线的椭圆曲线上的离散对数问题。
椭圆曲线是代数几何中一类重要的曲线,至今已有 100 多年的研究历史。而应用于密码学中的椭圆曲线是基于有限域上的,通过引入无穷远点,将椭圆曲线上的所有点和无穷远点组成一个集合,并在该集合上定义一个运算,从而该集合和运算构成了群。在有限域上的椭圆曲线群有两种,分别基于GF(p)以及GF(2m),它们各自有不同的群元素和群运算,然而对于群上的 ECDLP 问题,都认为是一个指数级的困难问题。基于这个困难问题,构建了ECC算法,包括==公钥加密、私钥解密、数字签名、签名验证、DH交换==等。
二、Go中使用ECDSA数字签名及签名验证
ECDSA 算法是目前使用最为广泛的标准算法,它是以 ECDLP 困难问题为基础,采用ELGamal体制构建的一个签名算法,它包含一个签名算法和一个验证算法。ECDSA算法如下:
首先选择好系统参数,如有限域类型和表示方法,曲线参数a,b,以及一个曲线上的基点G以及G的阶n,要求n必须为一个大素数(相关的系统参数的选择可见文献[23])。
参数确定以后,ECDSA 算法分为如下 3 个模块分别执行不同的功能,即密钥产生模块、数字签名模块以及签名验证模块。另外介绍一个基于ECC的Diffie-Hellman交换型算法以及公钥加密算法。
密钥产生:
1.在区间[1,n−1]上随机产生一个整数d(当然d不能太小)。
2.计算标量乘法Q=dG。
3.公开Q为公钥,保留d为私钥。
数字签名:
1.使用安全散列函数H对需要签名的消息M进行杂凑计算e=H(M)。
2.随机生成一个区间[1,n−1]上的本地秘密随机数k,并计算kG=(x1,y1)。
3.计算r=x1 mod n。
4.计算s=k−1(e+dr)mod n。
5.则数据r||s即为ECDSA算法下对消息M的签名(其中||表示两个比特串的串接)。
签名验证:
1.使用与签名一样的散列算法H计算e=H(M)。
2.计算c=s−1 mod n。
3.计算u1=ec mod n,u2=rc mod n。
4.计算(x1,y1)=u1G+uQ2。
5.计算v=x1mod n。若v=r,则为一个合法签名,否则验证不通过。
DH交换:
1.A随机生成一个区间[1,n−1]上的本地秘密随机数k,计算并发送kG到B。
2.B随机生成一个区间[1,n−1]上的本地秘密随机数l,计算并发送lG到A。
3.最后A计算k(lG)同时B计算l(kG)作为双方的共享密钥。
公钥加密算法:
1.公钥加密:随机生成一个区间[1,n-1]上的本地秘密随机数k,并计算,对需要加密的消息M。计算的密文C=kG||kQ+M(其中+为XOR运算)。
2.私钥解密:M=(kQ+M)−d(kG)。
1.生成密钥对
import (
"crypto/ecdsa"
"crypto/elliptic"
"time"
"crypto/x509"
"encoding/pem"
"errors"
mathRand "math/rand"
"os"
"strings"
)
const (
PRIVATEFILE = "src/cryptography/myECDSA/privateKey.pem"
PUBLICFILE = "src/cryptography/myECDSA/publicKey.pem"
)
//生成指定math/rand字节长度的随机字符串
func GetRandomString(length int) string {
str := "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ~!@#$%^&*()_+?=-"
bytes := []byte(str)
result := []byte{}
r := mathRand.New(mathRand.NewSource(time.Now().UnixNano()))
for i := 0; i < length; i++ {
result = append(result, bytes[r.Intn(len(bytes))])
}
return string(result)
}
//生成ECC算法的公钥和私钥文件
//根据随机字符串生成,randKey至少36位
func GenerateKey(randKey string) error {
var err error
var privateKey *ecdsa.PrivateKey
var publicKey ecdsa.PublicKey
var curve elliptic.Curve
//一、生成私钥文件
//根据随机字符串长度设置curve曲线
length := len(randKey)
//elliptic包实现了几条覆盖素数有限域的标准椭圆曲线,Curve代表一个短格式的Weierstrass椭圆曲线,其中a=-3
if length < 224/8 {
err = errors.New("私钥长度太短,至少为36位!")
return err
}
if length >= 521/8+8 {
//长度大于73字节,返回一个实现了P-512的曲线
curve = elliptic.P521()
} else if length >= 384/8+8 {
//长度大于56字节,返回一个实现了P-384的曲线
curve = elliptic.P384()
} else if length >= 256/8+8 {
//长度大于40字节,返回一个实现了P-256的曲线
curve = elliptic.P256()
} else if length &g