title: 椭圆曲线加密
date: 2021-04-12 12:17:45
categories:

  • 算法
    tags:
  • go

通过椭圆曲线加密实现数字签名

私钥公钥如何产生?

随机生成一个256位的二进制数

11011100111110101100101010000100111100101000011…

dcfaca84f325f65a…,… 16进制

一、为什么叫椭圆曲线

圆锥曲线可以用二次方程表示。椭圆曲线是用三次方程表示,如下:

其中,a 和 b 的取值不同,椭圆曲线的形状会有所改变,经典的形状如下图所示:

椭圆曲线有以下两个特点:

  • 画一条直线跟椭圆曲线相交,它们最多有三个交点;
  • 关于 X 轴对称。

A(x,y) k* A

二、椭圆曲线运算法则

1. 椭圆曲线加法

根据上面介绍的椭圆曲线的特性“画一条直线跟椭圆曲线相交,它们最多有三个交点”,可以进行以下定义:

  • 假设椭圆曲线上有 P、Q 两个点,经过这两个点做一条直线和椭圆曲线相交于第三点 R,然后做关于 x 轴的对称点 -R,-R 即是 R 的逆元,根据阿贝尔群的定义,-R 也一定在椭圆曲线上。定义 P+Q = -R,也就是说椭圆曲线上任意两点的和也在椭圆曲线上,同样可以引申出椭圆曲线上任意三点的和为 0 即 P+Q+R = 0。如图:

  • 假如 P=Q,则作椭圆曲线在 P 点的切线,与曲线相交于 R,则 R = P+P = 2P

2. 椭圆曲线乘法

根据上面椭圆曲线的加法可以得出下列等式:P+P = 2P(过点 P 切线作一条直线)P+2P = 3P(过点 P 和 2P 作一条直线)P+3P = 4P(过点 P 和 3P 作一条直线)假设 P 是椭圆曲线上的一个点,正整数 K 乘以 P 可以总结成公式为:(k-1) * P + P = k * P如果把 k 看作是两个数相乘即 k = m * n,则可以得出满足以下性质(在椭圆曲线密钥交换中会用到):(m * n) * P = m * (n * P) = (n * m)p = n * (m*P)

s * P =K (公钥)

三、椭圆曲线的难题

定义在质数阶的有限域上

满足下面公式的曲线,其中 p 是质数,x、y、a、b 都是小于 p 的非负整数:y^2 = x^3 + ax + b (mod p) { (4a^3 + 27b^2!)=0 }

来看一下 y^2 = x^3 - x 这个公式取模后的的图像(p=71):

可以看出,虽然很散乱,但是仔细看这些点都是关于一条直线对称的,这条直线就是 y=71/2 这条水平直线,并且原来椭圆曲线上定义的加法和乘法都可用。

假如选择一个点 P(4,8) 为基点,按照椭圆曲线的加法去运算 2P、3P… 这样的话,最后得到一个 k 次加法后的结果 kP(44,44),请问 k 是多少?

这时看一下上面的散点图,找到 (4,8) 和(44,44)这两个点,很难找出来通过几次椭圆曲线加法转变过去的,更何况这个是在公式中取模的那个质数等于 71 的情况下,如果把这个质数取得很大,难度就更大了,比特币中使用的 Secp256k1 这条曲线中取模的质数 p 等于:

p = 2^256 - 2^32 - 2^9 - 2^8 - 2^7 - 2^6 - 2^4 - 1

这样一个数,要逐一算出可能性取匹配几乎是不可能的。

G(79BE667E F9DCBBAC…)16进制

总结一下椭圆曲线的数学依据:

K = kG

  • G 为椭圆曲线上的一个点,叫基点;
  • k 为正整数;
  • 如果给定小 k 和 G,通过椭圆曲线加法法则去计算 K 很容易;
  • 如果给定 K 和 G,求小 k 就非常困难。

一般规定大 K 为公开密钥,小 k 为私钥

公钥P=K * G

非对称加密

“非对称加密也叫公钥密码: 使用公钥加密, 使用私钥解密”

数据加密

A:

B:

数字签名

数字签名是一种将相当于现实世界中的盖章、签字的功能在计算机世界中进行实现的技术。使用数字签名可以识别篡改和伪装,还可以防止否认。

通过数字签名解决问题

M 对M进行签名

M X K = N 签名数据

M X P =M X K X G 验证签名

四、 非对称加密和数字签名

对称加密与数字签名之间的关系。

非对称加密包括一个由公钥和私钥组成的密钥对,其中公钥用于加密,私钥用于解密。

数字签名中也同样会使用公钥和私钥组成的密钥对,不过这两个密钥的用法和非对称加密是相反的,即用私钥加密相当于生成签名,而用公钥解密则相当于验证签名。

那么为什么加密相当于生成签名,而解密相当于验证签名呢?

用公钥加密所得到的密文,只能用与该公钥配对的私钥才能解密:同样地,用私钥加密所得到的密文,也只能用与该私钥配对的公钥才能解密。也就是说,如果用某个公钥成功解密了密文,那么就能够证明这段密文是用与该公钥配对的私钥进行加密所得到的。

用私钥进行加密这一行为只能由持有私钥的人完成,正是基于这一事实,我们才可以将用私钥加密的密文作为签名来对待。

由于公钥是对外公开的,因此任何人都能够用公钥进行解密,这就产生了一个很大的好处,即任何人都能够对签名进行验证。

数字签名的方法

下面我们来具体介绍两种生成和验证数字签名的方法。

  • 直接对消息签名的方法
  • 对消息的散列值签名的方法

直接对消息签名的方法比较容易理解,但实际上并不会使用;对消息的散列值签名的方法稍微复杂一点,但实际中我们一般都使用这种方法。

使用直接对消息签名的方法,需要对整个消息进行加密,非常耗时,这是因为非对称加密算法本来就非常慢。那么,我们能不能生成一条很短的数据来代替消息本身呢?这就是单向散列函数。

于是我们不必再对整个消息进行加密(即对消息签名),而是只要先用单向散列函数求出消息的散列值,然后再将散列值进行加密(对散列值签名)就可以了。无论消息有多长,散列值永远都是这么短,因此对其进行加密(签名)是非常轻松的。

(1)A用单向散列函数计算消息的散列值。

(2)A用自己的私钥对散列值进行加密。

  用私钥加密散列值所得到的密文就是A对这条散列值的签名,由于只有A才持有自己的私钥因此,除了A以外,其他人是无法生成相同的签名(密文)的。

(3)A将消息和签名发送给B。

(4)B用A的公钥对收到的签名进行解密。

  如果收到的签名确实是用A的私钥进行加密而得到的密文(签名),那么用A的公钥应该能够正确解密,解密的结果应该等于消息的散列值。如果收到的签名不是用A的私钥进行加密而得到的密文,那么就无法用A的公钥正确解密(解密后得到的数据看起来是随机的)。

(5)B将签名解密后得到的散列值与A直接发送的消息的散列值进行对比。

   如果两者一致,则签名验证成功;如果两者不一致,则签名验证失败。

我们将数字签名中生成签名和验证签名的过程整理成一张时间流程图 。

五 使用椭圆曲线进行数字签名

椭圆曲线在go中对应的包: import “crypto/elliptic”

使用椭圆曲线在go中进行数字签名: import “crypto/ecdsa”

美国FIPS186-2标准, 推荐使用5个素域上的椭圆曲线, 这5个素数模分别是:

P192 = 2192 - 264 - 1

P224 = 2224 - 296 + 1

P256 = 2256 - 2224 + 2192 - 296 -1

P384 = 2384 - 2128 - 296 + 232 -1

P512 = 2512 - 1

  1. 秘钥对称的生成, 并保存到磁盘

    1. 使用ecdsa生成密钥对

      func GenerateKey(c elliptic.Curve, rand io.Reader) (priv *PrivateKey, err error)
      
    2. 将私钥写入磁盘

      • 使用x509进行序列化

        func MarshalECPrivateKey(key *ecdsa.PrivateKey) ([]byte, error)
        
      • 将得到的切片字符串放入pem.Block结构体中

        block := pem.Block{

        Type : “描述…”,

        Bytes : MarshalECPrivateKey返回值中的切片字符串,

        }

      • 使用pem编码

        pem.Encode();

    3. 将公钥写入磁盘

      • 从私钥中得到公钥

      • 使用x509进行序列化

        func MarshalPKIXPublicKey(pub interface{}) ([]byte, error)
        
      • 将得到的切片字符串放入pem.Block结构体中

        block := pem.Block{

        Type : “描述…”,

        Bytes : MarshalECPrivateKey返回值中的切片字符串,

        }

      • 使用pem编码

        pem.Encode();

  2. 使用私钥进行数字签名

    1. 打开私钥文件, 将内容读出来 ->[]byte

    2. 使用pem进行数据解码 -> pem.Decode()

    3. 使用x509, 对私钥进行还原

      func ParseECPrivateKey(der []byte) (key *ecdsa.PrivateKey, err error)
      
    4. 对原始数据进行哈希运算 -> 散列值

    5. 进行数字签名

      func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err error)
      - 得到的r和s不能直接使用, 因为这是指针应该将这两块内存中的数据进行序列化 -> []bytefunc (z *Int) MarshalText() (text []byte, err error)
      
  3. 使用公钥验证数字签名

    1. 打开公钥文件, 将里边的内容读出 -> []byte

    2. pem解码 -> pem.Decode()

    3. 使用x509对公钥还原

      func ParsePKIXPublicKey(derBytes []byte) (pub interface{}, err error)
      
    4. 将接口 -> 公钥

    5. 对原始数据进行哈希运算 -> 得到散列值

    6. 签名的认证 - > ecdsa

      func Verify(pub *PublicKey, hash []byte, r, s *big.Int) bool
      - 参数1: 公钥
      - 参数2: 原始数据生成的散列值
      - 参数3,4: 通过签名得到的连个点func (z *Int) UnmarshalText(text []byte) error
      

六、Go语言使用椭圆曲线签名认证实现

package main
import ("crypto/ecdsa""crypto/elliptic""crypto/rand""crypto/sha1""crypto/x509""encoding/pem""fmt""math/big""os"
)func main() {GenerateEccKey()src := []byte("使用x509对pem.Block中的Bytes变量中的数据进行解析 ->  得到一接口")rText, sText := EccSignature(src, "eccPrivate.pem")bl := EccVerify(src, rText, sText, "eccPublic.pem")fmt.Println(bl)
}
// 1. 生成密钥对
func GenerateEccKey() {//1. 使用ecdsa生成密钥对privateKey, err := ecdsa.GenerateKey(elliptic.P521(), rand.Reader)if err != nil {panic(err)}//2. 将私钥写入磁盘//- 使用x509进行序列化derText, err := x509.MarshalECPrivateKey(privateKey)if err != nil {panic(err)} //返回私钥//- 将得到的切片字符串放入pem.Block结构体中block := pem.Block{Type : "ecdsa private key",Bytes : derText,}//- 使用pem编码file, err := os.Create("eccPrivate.pem")if err != nil {panic(err)}pem.Encode(file, &block)file.Close()//3. 将公钥写入磁盘//- 从私钥中得到公钥publicKey := privateKey.PublicKey//- 使用x509进行序列化derText, err = x509.MarshalPKIXPublicKey(&publicKey)if err != nil {panic(err)}//- 将得到的切片字符串放入pem.Block结构体中block = pem.Block{Type : "ecdsa public key",Bytes : derText,}//- 使用pem编码file, err = os.Create("eccPublic.pem")if err != nil {panic(err)}pem.Encode(file, &block)file.Close()
}// ecc签名 - 私钥
func EccSignature(plainText []byte, privName string)  (rText, sText []byte){//1. 打开私钥文件, 将内容读出来 ->[]bytefile, err := os.Open(privName)if err != nil {panic(err)}info, err := file.Stat()if err != nil {panic(err)}buf := make([]byte, info.Size())file.Read(buf)file.Close()//2. 使用pem进行数据解码 -> pem.Decode()block, _ := pem.Decode(buf)//3. 使用x509, 对私钥进行还原privateKey, err := x509.ParseECPrivateKey(block.Bytes)if err != nil {panic(err)}//4. 对原始数据进行哈希运算 -> 散列值hashText := sha1.Sum(plainText)//5. 进行数字签名r, s, err := ecdsa.Sign(rand.Reader, privateKey, hashText[:])if err != nil {panic(err)}// 6. 对r, s内存中的数据进行格式化 -> []byterText, err = r.MarshalText()if err != nil {panic(err)}sText, err = s.MarshalText()if err != nil {panic(err)}return
}// ecc签名认证
func EccVerify(plainText, rText, sText []byte, pubFile string) bool {//1. 打开公钥文件, 将里边的内容读出 -> []bytefile, err := os.Open(pubFile)if err != nil {panic(err)}info, err := file.Stat()if err != nil {panic(err)}buf := make([]byte, info.Size())file.Read(buf)file.Close()//2. pem解码 -> pem.Decode()block, _ := pem.Decode(buf)//3. 使用x509对公钥还原pubInterface, err := x509.ParsePKIXPublicKey(block.Bytes)if err != nil {panic(err)}//4. 将接口 -> 公钥publicKey := pubInterface.(*ecdsa.PublicKey)//5. 对原始数据进行哈希运算 -> 得到散列值hashText := sha1.Sum(plainText)// 将rText, sText -> int数据var r, s big.Intr.UnmarshalText(rText)s.UnmarshalText(sText)//6. 签名的认证 - > ecdsa  (问题,api的设计为什么在这个地方要传地址,直接传值比较不是更好吗?)bl := ecdsa.Verify(publicKey, hashText[:], &r, &s)return bl
}

2021-04-12-椭圆曲线加密相关推荐

  1. xp sp3系统连接华为手机,显示mtp驱动无法安装 2021/04/12

    安装windows media player11 在C:\WINDOWS\inf 找到wpdmtp.inf 更改为: [Generic.NTx86] %GenericMTP.DeviceDesc%=M ...

  2. 学习Go之前你应该知道的10件事 | Gopher Daily (2021.04.21) ʕ◔ϖ◔ʔ

    每日一谚:Don't use an interface if it's not clear how the interface makes the code better. Go技术生态 编写好的单元 ...

  3. 2021年 第12届 蓝桥杯 Java B组 省赛真题详解及小结【第1场省赛 2021.04.18】

    蓝桥杯 Java B组 省赛决赛 真题详解及小结汇总[题目下载.2013年(第4届)~2020年(第11届)] CSDN 蓝桥杯 专栏 2013年 第04届 蓝桥杯 Java B组 省赛真题详解及小结 ...

  4. 《安富莱嵌入式周报》第209期:2021.04.19--2021.04.25

    往期周报汇总地址:http://www.armbbs.cn/forum.php?mod=forumdisplay&fid=12&filter=typeid&typeid=104 ...

  5. python椭圆曲线加密算法_ECC椭圆曲线加密学习笔记

    0x00 前言 之前做题的时候遇到一个ECC相关的题目,学习了好几篇大佬的文章ECC的剖析文章,学习之后也记录一下,写一遍加强自己的巩固. 此文章严格意义上来讲应该算是读书笔记,在总结过程中观摩了很多 ...

  6. 椭圆曲线加密(ECC)

    什么是椭圆曲线加密(ECC)? 比特币使用椭圆曲线算法生成公钥和私钥,选择的是secp256k1曲线.与RSA(Ron Rivest,Adi Shamir,Len Adleman三位天才的名字)一样, ...

  7. 2021年12月中国A股上市企业股价涨幅排行榜:三羊马涨幅最大,从事传媒行业的企业最多(附月榜TOP100详单)

        榜单解读:     2021年12月中国A股市场共有2714家上市企业的股价有着不同程度的上涨,其中929家企业股价涨幅不低于10%,股价涨幅最大的前100家企业涨幅均超过36%,涨幅排名第1 ...

  8. 椭圆曲线加密和签名算法

    简述 椭圆曲线密码学,简称ECC.是一种建立公开加密的算法,也就是非对称加密.和RSA类似.被公认在给定密钥长度下最安全的加密算法.应用范围很广,主要的三个技术TLS.PGP.SSH都在使用它,特别是 ...

  9. 离散对数和椭圆曲线加密原理

    为什么是椭圆曲线加密? 椭圆曲线加密(以下简称ECC)实际上已经应用到了各个网站的HTTPS连接中.你平常访问的网站,大部分都是基于椭圆曲线加密,比如你现在正在浏览的CSDN.如果你用的是chrome ...

  10. 椭圆曲线加密概览(二)

    椭圆曲线配对是包括确定性阈值签名,zk-SNARK和其他更简单形式的零知识证明在内的各种构造背后的关键密码原语 椭圆曲线配对(或更确切地说,我们将在此处探讨的配对的具体形式:尽管其逻辑相当相似,也存在 ...

最新文章

  1. AgileEAS.NET SOA 中间件2013第四季度发布部分功能开源预告
  2. 外链对网站SEO优化起什么作用?
  3. 安卓 sharedpreferences可以被其它activity读取_【安卓逆向】“一份礼物”之我要o泡逆向分析...
  4. hbase组合rowkey_「从零单排HBase 11」HBase二级索引解决方案
  5. C语言挂载文件夹,使用autofs 按需挂载共享目录
  6. HTML5清爽博客自媒体网站模板
  7. java 获取调用者方法_java获取调用当前方法的方法名和行数
  8. “明年AI会如何?”英伟达问了13位不同行业的专家
  9. VirtualBox开发环境的搭建详解
  10. photoshop智能参考线
  11. python透视表画图_透视表、交叉表、matplotlib作图
  12. Java程序员面试全集(上)
  13. safari浏览器的一些兼容性问题总结
  14. 60分钟搞定JAVA加解密
  15. .Net6.0系列-6 .Net 6LinQ(二)常用扩展方法
  16. 什么是Linkerd
  17. java 算出下一个工作日_如何计算JAVA中两个不同日期之间的工作日(不包括周末)?...
  18. CVPR2019目标检测方法进展
  19. RSA加密算法加密与解密过程解析
  20. C语言基础:函数的声明与定义

热门文章

  1. 【exe4j】如何利用exe4j把java桌面程序生成exe文件
  2. 互联网与信息安全 ——云计算及其安全
  3. php webmail,10个基于Ajax的PHP Webmail客户端
  4. xampp linux教程,xampp for linux
  5. 音视频基础知识——素材理解
  6. 追逐梦想,意味你要牺牲一切,这就是代价!!!----蔡赟
  7. hexo搭建博客的几种方式(入门级)
  8. gorm增删查改json_go基于echo、gorm实现增删改查,从请求到落库
  9. Linux下文件增删改查定位压缩操作与权限所属用户
  10. 【BZOJ3144】【HNOI2013】切糕(网络流)