- 接受方接受加密数据{kG,
,C}。
- 接受方使用自己的私钥
作如下计算:
- 计算m=
,得明文m。
小结
- 计算量小,处理速度快
- 存储空间占用小
- 带宽要求低
- 应用前景非常好,特别在移动通信、无线设备上的应用
- 安全性能更高(160位等同RSA的1024位)
在保持同等安全的条件下所需的密钥长度(单位为比特)
RSA | 1024 | 2048 | 3072 | 7680 | 15360 |
ECC | 160 | 224 | 256 | 384 | 512 |
Ecc的Go实现
crypto/ecdsa
包
func GenerateKey(c elliptic.Curve, rand io.Reader) (priv *PrivateKey, err error)
公钥/私钥。因为
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.youkuaiyun.com/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)
截图
全部源码代码放在:https://gitee.com/frankyu365/gocrypto
补:ECC和RSA对比
数论基础
RSA:欧拉定理
ECC:离散对数
安全性基础
RSA:整数分解问题的困难性
ECC:椭圆曲线,离散对数问题的难解性
当前安全密钥长度
RSA:1024位
ECC:160位
消耗
RSA:CPU、内存消耗大
ECC:CPU、内存消耗小
最后
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数网络安全工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年网络安全全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上网络安全知识点!真正的体系化!
如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
BK3t3DLU-1715488547474)]
[外链图片转存中…(img-NDJHi25G-1715488547474)]
[外链图片转存中…(img-B1rk9f2n-1715488547474)]
[外链图片转存中…(img-0SG1l3ML-1715488547475)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上网络安全知识点!真正的体系化!
如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!