Go-ecc加密解密详解与代码

本文涉及的产品
密钥管理服务KMS,1000个密钥,100个凭据,1个月
简介: Go-ecc加密解密详解与代码

Ecc概述

ECC的主要优势是在某些情况下它比其他的算法(比如RSA加密算法)使用更小的密钥并提供相当的或更高等级的安全。ECC的另一个优势是可以定义群之间的双线性映射,基于Weil对或是Tate对;双线性映射已经在密码学中发现了大量的应用,例如基于身份的加密。

比特币也是用的这个。

历史

椭圆曲线在代数学和几何学上已广泛研究了150多年之久,有丰富而深厚的理论积累。

1985年,Koblitz和Miller提出椭圆曲线密码体制(EllipticCurve Cryptosystem,简称ECC)椭圆曲线并不是椭圆,之所以称为椭圆曲线是因为它们是用三次方程来表示的,它的一般形式:

20201204182323419.gif,其中a,b,c,d和e是满足某些条件的实数。

大多数的椭圆曲线密码系统是在模p或F2下运算。

椭圆曲线密码已经逐渐被采用,已成为公钥密码的一个重要发展方向。

密钥对生成

选择一个椭圆曲线E:20201204182323419.gif,构造一个椭圆群Ep(a,b)。

在Ep(a,b)中挑选生成元点G=(x1,y1),G应使得满足nG=O最小的n是一个非常大的素数。

选择一个小于n的整数作为其私钥,然后产生其公钥PA=20201204182323419.gifG。

注:公开的信息(E,G,n,PA)


IEpI表示椭圆群Ep(a,b)的元素个数,n是IEpI的素因子。满足:

20201204182323419.gif

加密算法

  • 将m编码成一个数m<p,在椭圆群Ep(a,b)中随机选择一点20201204182323419.gif
  • 在区间[1,n-1]内选取一个随机数k,计算点
  • 依据接受方的公钥PB计算点(2,y)=kPB;
  • 计算密文C=20201204182323419.gif
  • 传送加密数据{kG,20201204182323419.gif,C}给接受方。

解密算法

  • 接受方接受加密数据{kG,20201204182323419.gif,C}。
  • 接受方使用自己的私钥20201204182323419.gif作如下计算:20201204182323419.gif
  • 计算m=20201204182323419.gif,得明文m

小结

  • 计算量小,处理速度快
  • 存储空间占用小
  • 带宽要求低
  • 应用前景非常好,特别在移动通信、无线设备上的应用
  • 安全性能更高(160位等同RSA的1024位)

在保持同等安全的条件下所需的密钥长度(单位为比特)

RSA 1024 2048 3072 7680 15360
ECC 160 224 256 384 512

Ecc的Go实现

crypto/ecdsa

公钥/私钥。因为

type PrivateKey struct {
     PublicKey     
     D   *big.Int 
}

公钥在私钥的结构体里面

crypto/elliptic 包

func P256() Curve

返回一个实现了P-256的曲线。

crypto/rand

func Read(b []byte) (n int, err error)

本函数是一个使用io.ReadFull调用Reader.Read的辅助性函数。当且仅当err == nil时,返回值n == len(b)。

crypto/x509包

func MarshalECPrivateKey(key *ecdsa.PrivateKey) ([]byte, error)

MarshalECPrivateKey将ecdsa私钥序列化为ASN.1 DER编码。

x509等其他包在https://blog.csdn.net/lady_killer9/article/details/118026802 中有提到。

代码

生成密钥对

使用ecdsa.GenerateKey生成私钥

使用x509.MarshalECPrivateKey对生成的私钥序列化

使用pem.Block转为块,使用pem.Encode编码

保存私钥到文件

公钥从私钥结构体中取出,其他类似,x509序列化使用MarshalECPrivateKey函数即可

// 生成ECC私钥对

// keySize 密钥大小, 224 256 384 521

// dirPath 密钥文件生成后保存的目录

// 返回 错误

func GenerateECCKey(keySize int,dirPath string) error {
  // generate private key
  var priKey *ecdsa.PrivateKey
  var err error
  switch keySize{
  case 224:priKey,err = ecdsa.GenerateKey(elliptic.P224(),rand.Reader)
  case 256:priKey,err = ecdsa.GenerateKey(elliptic.P256(),rand.Reader)
  case 384:priKey,err = ecdsa.GenerateKey(elliptic.P256(),rand.Reader)
  case 521:priKey,err = ecdsa.GenerateKey(elliptic.P521(),rand.Reader)
  default:priKey,err = nil,nil
  }
  if priKey == nil{
    _, file, line, _ := runtime.Caller(0)
    return util.Error(file,line+1,errors.EcckeyError)
  }
  if err != nil{
    _, file, line, _ := runtime.Caller(0)
    return util.Error(file,line+1,err.Error())
  }
  // x509
  derText,err := x509.MarshalECPrivateKey(priKey)
  if err != nil{
    _, file, line, _ := runtime.Caller(0)
    return util.Error(file,line+1,err.Error())
  }
  // pem block
  block := &pem.Block{
    Type:"ecdsa private key",
    Bytes:derText,
  }
  file,err := os.Create(dirPath+"eccPrivate.pem")
  if err != nil{
    _, file, line, _ := runtime.Caller(0)
    return util.Error(file,line+1,err.Error())
  }
  err = pem.Encode(file,block)
  if err != nil{
    _, file, line, _ := runtime.Caller(0)
    return util.Error(file,line+1,err.Error())
  }
  file.Close()
  // public key
  pubKey := priKey.PublicKey
  derText, err = x509.MarshalPKIXPublicKey(&pubKey)
  block = &pem.Block{
    Type:"ecdsa public key",
    Bytes:derText,
  }
  file, err = os.Create(dirPath+"eccPublic.pem")
  if err != nil{
    _, file, line, _ := runtime.Caller(0)
    return util.Error(file,line+1,err.Error())
  }
  err = pem.Encode(file,block)
  if err != nil{
    _, file, line, _ := runtime.Caller(0)
    return util.Error(file,line+1,err.Error())
  }
  file.Close()
  return nil
}

加密

go包没有ecc的加密,这里采用的github上的一个项目的ecies包

  • 获取block块
  • 使用x509.ParsePKIXPublicKey解析为公钥
  • 断言后转为ecies包的Public类型(转换函数附在后面)
  • 使用ecies.Encrypt加密

// Ecc 加密

// plainText 明文

// filePath 公钥文件路径

// 返回 密文 错误

func EccEncrypt(plainText []byte,filePath string)  ([]byte, error) {
  // get pem.Block
  block,err := util.GetKey(filePath)
  if err != nil{
    _, file, line, _ := runtime.Caller(0)
    return nil,util.Error(file,line+1,err.Error())
  }
  // X509
  publicInterface,err := x509.ParsePKIXPublicKey(block.Bytes)
  if err != nil{
    _, file, line, _ := runtime.Caller(0)
    return nil,util.Error(file,line+1,err.Error())
  }
  publicKey,flag := publicInterface.(*ecdsa.PublicKey)
  if flag == false{
    _, file, line, _ := runtime.Caller(0)
    return nil,util.Error(file,line+1,errors.RsatransError)
  }
  cipherText,err := ecies.Encrypt(rand.Reader,util.PubEcdsaToEcies(publicKey),plainText,nil,nil)
  if err != nil{
    _, file, line, _ := runtime.Caller(0)
    return nil,util.Error(file,line+1,err.Error())
  }
  return cipherText,err
}

解密

  • 获取block块
  • 使用x509.ParseECPrivateKey解析为私钥
  • 转为ecies的私钥格式(转换函数附在后面)
  • 使用ecies.Decrypt解密// ECC 解密

// cipherText 密文

// filePath 私钥文件路径

// 返回 明文 错误

func EccDecrypt(cipherText []byte,filePath string) (plainText []byte,err error)  {
  // get pem.Block
  block,err := util.GetKey(filePath)
  if err != nil{
    _, file, line, _ := runtime.Caller(0)
    return nil,util.Error(file,line+1,err.Error())
  }
  // get privateKey
  privateKey, _ := x509.ParseECPrivateKey(block.Bytes)
  priKey := util.PriEcdsaToEcies(privateKey)
  plainText,err = priKey.Decrypt(cipherText,nil,nil)
  if err != nil{
    _, file, line, _ := runtime.Caller(0)
    return nil,util.Error(file,line+1,err.Error())
  }
  return plainText,nil
}

附:ecdsa包的公钥私钥转为ecies对应的密钥的转换代码,全部代码看后面gitee链接

// ecdsa public key to ecies public key
func PubEcdsaToEcies(pub *ecdsa.PublicKey) *ecies.PublicKey {
  return &ecies.PublicKey{
    X:      pub.X,
    Y:      pub.Y,
    Curve:  pub.Curve,
    Params: ecies.ParamsFromCurve(pub.Curve),
  }
}
// ecdsa private key to ecies private key
func PriEcdsaToEcies(prv *ecdsa.PrivateKey) *ecies.PrivateKey {
  pub := PubEcdsaToEcies(&prv.PublicKey)
  return &ecies.PrivateKey{*pub, prv.D}
}

测试代码

  plainText := []byte("hi, I'm lady_killer9")
  cipherText,err := EccEncrypt(plainText,"./eccPublic.pem")
  if err!=nil{
    fmt.Println(err)
  }
  fmt.Printf("加密后:%s\n",cipherText)
  plainText,err = EccDecrypt(cipherText,"./eccPrivate.pem")
  if err!=nil{
    fmt.Println(err)
  }
  fmt.Printf("解密后:%s\n",plainText)

截图

2020062310470442.png

全部源码代码放在:https://gitee.com/frankyu365/gocrypto

补:ECC和RSA对比

数论基础


RSA:欧拉定理


ECC:离散对数


安全性基础


RSA:整数分解问题的困难性


ECC:椭圆曲线,离散对数问题的难解性


当前安全密钥长度


RSA:1024位


ECC:160位


消耗


RSA:CPU、内存消耗大


ECC:CPU、内存消耗小


安全等级与密钥长度


RSA:增长较快


ECC:成线性


参考

《现代密码学教程 谷利泽,杨义先等》


Go标准库-crypto/ecdsa


Go标准库-crypto/elliptic


Go标准库-crypto/rand


Go标准库-crypto/hex


Go标准库-crypto/sha256


Github-以太坊


更多Go相关内容:Go-Golang学习总结笔记


有问题请下方评论,转载请注明出处,并附有原文链接,谢谢!如有侵权,请及时联系。





相关文章
|
5月前
|
Cloud Native Go 开发工具
不改一行代码轻松玩转 Go 应用微服务治理
为了更好的进行 Go 应用微服务治理,提高研发效率和系统稳定性,本文将介绍 MSE 微服务治理方案,无需修改业务代码,实现治理能力。
19885 17
|
11天前
|
算法 安全 Go
Go语言中的加密和解密是如何实现的?
Go语言通过标准库中的`crypto`包提供丰富的加密和解密功能,包括对称加密(如AES)、非对称加密(如RSA、ECDSA)及散列函数(如SHA256)。`encoding/base64`包则用于Base64编码与解码。开发者可根据需求选择合适的算法和密钥,使用这些包进行加密操作。示例代码展示了如何使用`crypto/aes`包实现对称加密。加密和解密操作涉及敏感数据处理,需格外注意安全性。
33 14
|
2月前
|
安全 Go 开发者
代码之美:Go语言并发编程的优雅实现与案例分析
【10月更文挑战第28天】Go语言自2009年发布以来,凭借简洁的语法、高效的性能和原生的并发支持,赢得了众多开发者的青睐。本文通过两个案例,分别展示了如何使用goroutine和channel实现并发下载网页和构建并发Web服务器,深入探讨了Go语言并发编程的优雅实现。
43 2
|
2月前
|
SQL 监控 算法
为Go应用无侵入地添加任意代码
这篇文章旨在提供技术深度和实践指南,帮助开发者理解并应用这项创新技术来提高Golang应用的监控与服务治理能力。在接下来的部分,我们将通过一些实际案例,进一步展示如何在不同场景中应用这项技术,提供更多实践启示。
|
3月前
|
算法 安全 Go
RSA加密算法详解与Python和Go实现
RSA加密算法详解与Python和Go实现
287 1
|
3月前
|
安全 算法 Java
数据库信息/密码加盐加密 —— Java代码手写+集成两种方式,手把手教学!保证能用!
本文提供了在数据库中对密码等敏感信息进行加盐加密的详细教程,包括手写MD5加密算法和使用Spring Security的BCryptPasswordEncoder进行加密,并强调了使用BCryptPasswordEncoder时需要注意的Spring Security配置问题。
255 0
数据库信息/密码加盐加密 —— Java代码手写+集成两种方式,手把手教学!保证能用!
|
3月前
|
JSON 搜索推荐 Go
ZincSearch搜索引擎中文文档及在Go语言中代码实现
ZincSearch官网及开发文档均为英文,对非英语用户不够友好。GoFly全栈开发社区将官方文档翻译成中文,并增加实战经验和代码,便于新手使用。本文档涵盖ZincSearch在Go语言中的实现,包括封装工具库、操作接口、统一组件调用及业务代码示例。官方文档https://zincsearch-docs.zinc.dev;中文文档https://doc.goflys.cn/docview?id=41。
146 0
|
4月前
|
存储 安全 数据安全/隐私保护
安全升级!Python AES加密实战,为你的代码加上一层神秘保护罩
【9月更文挑战第12天】在软件开发中,数据安全至关重要。本文将深入探讨如何使用Python中的AES加密技术保护代码免受非法访问和篡改。AES(高级加密标准)因其高效性和灵活性,已成为全球最广泛使用的对称加密算法之一。通过实战演练,我们将展示如何利用pycryptodome库实现AES加密,包括生成密钥、初始化向量(IV)、加密和解密文本数据等步骤。此外,还将介绍密钥管理和IV随机性等安全注意事项。通过本文的学习,你将掌握使用AES加密保护敏感数据的方法,为代码增添坚实的安全屏障。
176 8
|
3月前
|
安全 测试技术 Go
Python 和 Go 实现 AES 加密算法的技术详解
Python 和 Go 实现 AES 加密算法的技术详解
176 0
|
5月前
|
缓存 NoSQL 数据库
go-zero微服务实战系列(五、缓存代码怎么写)
go-zero微服务实战系列(五、缓存代码怎么写)