目錄git
Ecc概述github
歷史golang
密鑰對生成算法
加密算法安全
解密算法ide
小結函數
Ecc的Go實現性能
Ecc概述ECC的主要優點是在某些狀況下它比其餘的算法(好比RSA加密算法)使用更小的密鑰並提供至關的或更高等級的安全。ECC的另外一個優點是能夠定義羣之間的雙線性映射,基於Weil對或是Tate對;雙線性映射已經在密碼學中發現了大量的應用,例如基於身份的加密。
不過一個缺點是加密和解密操做的實現比其餘機制花費的時間長。
比特幣也是用的這個。
注:公開的信息(E,G,n,PA)
IEpI表示橢圓羣Ep(a,b)的元素個數,n是IEpI的素因子。知足:
在保持同等安全的條件下所需的密鑰長度(單位爲比特)
RSA | 1024 | 2048 | 3072 | 7680 | 15360 |
---|---|---|---|---|---|
ECC | 160 | 224 | 256 | 384 | 512 |
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)。
func MarshalECPrivateKey(key *ecdsa.PrivateKey) ([]byte, error)
MarshalECPrivateKey將ecdsa私鑰序列化爲ASN.1 DER編碼。
// 生成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包
// 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 }
// 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
參考《現代密碼學教程 谷利澤,楊義先等》
Github-以太坊