Go-ecc加密解密详解与代码_ecdsa(1)

crypto/ecdsa 包

crypto/elliptic 包

crypto/rand 包

crypto/x509包

代码

生成密钥对

加密

解密

测试代码

截图

补:ECC和RSA对比

参考


Ecc概述

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

比特币也是用的这个。

历史

  • 椭圆曲线在代数学和几何学上已广泛研究了150多年之久,有丰富而深厚的理论积累。
  • 1985年,Koblitz和Miller提出椭圆曲线密码体制(EllipticCurve Cryptosystem,简称ECC)椭圆曲线并不是椭圆,之所以称为椭圆曲线是因为它们是用三次方程来表示的,它的一般形式:
  • y2+axy+by=x3+cx^2+dx+e,其中a,b,c,d和e是满足某些条件的实数。
  • 大多数的椭圆曲线密码系统是在模p或F2下运算。
  • 椭圆曲线密码已经逐渐被采用,已成为公钥密码的一个重要发展方向。

密钥对生成

  • 选择一个椭圆曲线E:y2=x3+ax+b(modp)),构造一个椭圆群Ep(a,b)。
  • 在Ep(a,b)中挑选生成元点G=(x1,y1),G应使得满足nG=O最小的n是一个非常大的素数。
  • 选择一个小于n的整数n_A作为其私钥,然后产生其公钥PA=n_AG。

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

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

p+1-2\sqrt{p}\leq |E_p|\leq p+1+2\sqrt{p}

加密算法

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

解密算法

  • 接受方接受加密数据{kG,P_t+kP_B,C}。
  • 接受方使用自己的私钥n_B作如下计算:P_t+kP_B-nB(kG)=P_t+k(n_BG)-n_B(kG)=P_t
  • 计算m=(C-y_t)/x_t,得明文m

小结

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

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

RSA102420483072768015360
ECC160224256384512

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.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链接

最后

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数网络安全工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年网络安全全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。

img

img

img

img

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上网络安全知识点!真正的体系化!

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

2Fhds3fG-1715847520962)]

[外链图片转存中…(img-7eqmT9ok-1715847520963)]

[外链图片转存中…(img-izfMgL55-1715847520963)]

[外链图片转存中…(img-7oGpTzH7-1715847520963)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上网络安全知识点!真正的体系化!

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
转python写法:#!/bin/sh time_stamp=`date +%s` function CheckStop() { if [ $? -ne 0 ]; then echo "execute fail, error on line_no:"$1" exit!!!" exit fi } function GenEcdsaKey() { ec_param_file_path="/tmp/ec_param.pem."$time_stamp openssl ecparam -out $ec_param_file_path -name prime256v1 -genkey CheckStop $LINENO openssl genpkey -paramfile $ec_param_file_path -out $1 CheckStop $LINENO openssl pkey -in $1 -inform PEM -out $2 -outform PEM -pubout CheckStop $LINENO rm $ec_param_file_path echo "gen_ecdsa_key succ prikey_path:"$1" pubkey_path:"$2 } function GenEcdsaSign() { ec_sign_info_file="/tmp/ec_sign_info_file."$time_stamp ec_sign_info_sha256="/tmp/ec_sign_info_sha256."$time_stamp ec_binary_sign_file="/tmp/ec_binary_sign_file."$time_stamp echo -n "$1"_"$2" > $ec_sign_info_file openssl dgst -sha256 -binary -out $ec_sign_info_sha256 $ec_sign_info_file CheckStop $LINENO openssl pkeyutl -sign -in $ec_sign_info_sha256 -out $ec_binary_sign_file -inkey $3 -keyform PEM CheckStop $LINENO openssl base64 -e -in $ec_binary_sign_file -out $4 CheckStop $LINENO rm $ec_sign_info_file $ec_sign_info_sha256 $ec_binary_sign_file echo "gen_ecdsa_sign succ sign_file_path:"$4 } function VerifyEcdsaSign() { ec_sign_info_file="/tmp/ec_sign_info_file."$time_stamp ec_sign_info_sha256="/tmp/ec_sign_info_sha256."$time_stamp ec_binary_sign_file="/tmp/ec_binary_sign_file."$time_stamp echo -n "$1"_"$2" > $ec_sign_info_file openssl dgst -sha256 -binary -out $ec_sign_info_sha256 $ec_sign_info_file CheckStop $LINENO openssl base64 -d -in $4 -out $ec_binary_sign_file CheckStop $LINENO openssl pkeyutl -verify -in $ec_sign_info_sha256 -sigfile $ec_binary_sign_file -pubin -inkey $3 -keyform PEM rm $ec_sign_info_file $ec_sign_info_sha256 $ec_binary_sign_file } function Usage() { echo "Usage:" echo "mmiot_ecdsa_sign.sh gen_ecdsa_key <private_key_file_path> <public_key_file_path>" echo "mmiot_ecdsa_sign.sh gen_ecdsa_sign <product_id> <sn> <private_
05-31
以下是转换后的 Python 代码: ```python #!/usr/bin/env python import os import subprocess import base64 time_stamp = str(int(time.time())) def check_stop(line_no, ret): if ret != 0: print("execute fail, error on line_no: ", line_no, " exit!!!") exit() def gen_ecdsa_key(private_key_file_path, public_key_file_path): ec_param_file_path = "/tmp/ec_param.pem." + time_stamp ret = subprocess.call(["openssl", "ecparam", "-out", ec_param_file_path, "-name", "prime256v1", "-genkey"]) check_stop(sys._getframe().f_lineno, ret) ret = subprocess.call(["openssl", "genpkey", "-paramfile", ec_param_file_path, "-out", private_key_file_path]) check_stop(sys._getframe().f_lineno, ret) ret = subprocess.call(["openssl", "pkey", "-in", private_key_file_path, "-inform", "PEM", "-out", public_key_file_path, "-outform", "PEM", "-pubout"]) check_stop(sys._getframe().f_lineno, ret) os.remove(ec_param_file_path) print("gen_ecdsa_key succ prikey_path:", private_key_file_path, " pubkey_path:", public_key_file_path) def gen_ecdsa_sign(product_id, sn, private_key_file_path, sign_file_path): ec_sign_info_file = "/tmp/ec_sign_info_file." + time_stamp ec_sign_info_sha256 = "/tmp/ec_sign_info_sha256." + time_stamp ec_binary_sign_file = "/tmp/ec_binary_sign_file." + time_stamp with open(ec_sign_info_file, 'w') as f: f.write(product_id + "_" + sn) ret = subprocess.call(["openssl", "dgst", "-sha256", "-binary", "-out", ec_sign_info_sha256, ec_sign_info_file]) check_stop(sys._getframe().f_lineno, ret) ret = subprocess.call(["openssl", "pkeyutl", "-sign", "-in", ec_sign_info_sha256, "-out", ec_binary_sign_file, "-inkey", private_key_file_path, "-keyform", "PEM"]) check_stop(sys._getframe().f_lineno, ret) with open(ec_binary_sign_file, 'rb') as f: sign_binary = f.read() sign_base64 = base64.b64encode(sign_binary).decode() with open(sign_file_path, 'w') as f: f.write(sign_base64) os.remove(ec_sign_info_file) os.remove(ec_sign_info_sha256) os.remove(ec_binary_sign_file) print("gen_ecdsa_sign succ sign_file_path:", sign_file_path) def verify_ecdsa_sign(product_id, sn, public_key_file_path, sign_file_path): ec_sign_info_file = "/tmp/ec_sign_info_file." + time_stamp ec_sign_info_sha256 = "/tmp/ec_sign_info_sha256." + time_stamp ec_binary_sign_file = "/tmp/ec_binary_sign_file." + time_stamp with open(ec_sign_info_file, 'w') as f: f.write(product_id + "_" + sn) ret = subprocess.call(["openssl", "dgst", "-sha256", "-binary", "-out", ec_sign_info_sha256, ec_sign_info_file]) check_stop(sys._getframe().f_lineno, ret) with open(sign_file_path, 'r') as f: sign_base64 = f.read() sign_binary = base64.b64decode(sign_base64) with open(ec_binary_sign_file, 'wb') as f: f.write(sign_binary) ret = subprocess.call(["openssl", "pkeyutl", "-verify", "-in", ec_sign_info_sha256, "-sigfile", ec_binary_sign_file, "-pubin", "-inkey", public_key_file_path, "-keyform", "PEM"]) os.remove(ec_sign_info_file) os.remove(ec_sign_info_sha256) os.remove(ec_binary_sign_file) print("verify_ecdsa_sign result:", "succ" if ret == 0 else "fail") if len(sys.argv) < 2: print("Usage:") print("python mmiot_ecdsa_sign.py gen_ecdsa_key <private_key_file_path> <public_key_file_path>") print("python mmiot_ecdsa_sign.py gen_ecdsa_sign <product_id> <sn> <private_key_file_path> <sign_file_path>") print("python mmiot_ecdsa_sign.py verify_ecdsa_sign <product_id> <sn> <public_key_file_path> <sign_file_path>") exit() if sys.argv[1] == "gen_ecdsa_key": gen_ecdsa_key(sys.argv[2], sys.argv[3]) elif sys.argv[1] == "gen_ecdsa_sign": gen_ecdsa_sign(sys.argv[2], sys.argv[3], sys.argv[4], sys.argv[5]) elif sys.argv[1] == "verify_ecdsa_sign": verify_ecdsa_sign(sys.argv[2], sys.argv[3], sys.argv[4], sys.argv[5]) else: print("Usage:") print("python mmiot_ecdsa_sign.py gen_ecdsa_key <private_key_file_path> <public_key_file_path>") print("python mmiot_ecdsa_sign.py gen_ecdsa_sign <product_id> <sn> <private_key_file_path> <sign_file_path>") print("python mmiot_ecdsa_sign.py verify_ecdsa_sign <product_id> <sn> <public_key_file_path> <sign_file_path>") ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值