非對稱式加密演算法有RSA、ECDSA,對極大整數做因數分解的難度決定了RSA演算法的可靠性,ECDSA為橢圓曲線密碼編譯演算法,是基於橢圓方程公式,所以安全性要高於RSA。
這裡說下使用ecdsa做簽名和校正,並不講原理;
golang封裝的ecdsa目前只有用私密金鑰加密,公開金鑰做校正,沒有解密環節;所以目前可以應用於數位簽章;
以下為封裝:
/** 通過一個隨機key建立公開金鑰和私密金鑰 隨機key至少為36位 */func getEcdsaKey(randKey string) (*ecdsa.PrivateKey, ecdsa.PublicKey, error){ var err error var prk *ecdsa.PrivateKey var puk ecdsa.PublicKey var curve elliptic.Curve lenth := len(randKey) if lenth < 224/8 { err =errors.New("私密金鑰長度太短,至少為36位!") return prk,puk,err } if lenth > 521/8 + 8 { curve = elliptic.P521() }else if lenth > 384/8 + 8 { curve = elliptic.P384() }else if lenth > 256/8 + 8 { curve = elliptic.P256() }else if lenth > 224/8 + 8 { curve = elliptic.P224() } prk, err = ecdsa.GenerateKey(curve,strings.NewReader(randKey)) if err != nil { return prk, puk, err } puk = prk.PublicKey return prk, puk, err}/** 對text加密,text必須是一個hash值,例如md5、sha1等 使用私密金鑰prk 使用隨機熵增強加密安全,安全依賴於此熵,randsign 返回加密結果,結果為數位憑證r、s的序列化後拼接,然後用hex轉換為string */func sign(text []byte,randSign string,prk *ecdsa.PrivateKey) (string, error) { r, s, err := ecdsa.Sign(strings.NewReader(randSign), prk, text) if err != nil { return "", err } rt, err := r.MarshalText() if err != nil { return "", err } st, err := s.MarshalText() if err != nil { return "", err } var b bytes.Buffer w := gzip.NewWriter(&b) defer w.Close() _, err = w.Write([]byte(string(rt) + "+" + string(st))) if err != nil { return "", err } w.Flush() return hex.EncodeToString(b.Bytes()), nil}/** 認證分解 通過hex解碼,分割成數位憑證r,s */func getSign( signature string) (rint, sint big.Int, err error) { byterun, err := hex.DecodeString(signature) if err != nil { err = errors.New("decrypt error, "+ err.Error()) return } r, err := gzip.NewReader(bytes.NewBuffer(byterun)) if err != nil { err = errors.New("decode error,"+err.Error()) return } defer r.Close() buf := make([]byte, 1024) count, err := r.Read(buf) if err != nil { fmt.Println("decode = ",err) err = errors.New("decode read error," + err.Error()) return } rs := strings.Split(string(buf[:count]),"+") if len(rs) != 2 { err = errors.New("decode fail") return } err = rint.UnmarshalText([]byte(rs[0])) if err != nil { err = errors.New("decrypt rint fail, "+ err.Error()) return } err = sint.UnmarshalText([]byte(rs[1])) if err != nil { err = errors.New("decrypt sint fail, "+ err.Error()) return } return}/** 校正常值內容是否與簽名一致 使用公開金鑰校正簽名和常值內容 */func verify(text []byte, signature string, key ecdsa.PublicKey) (bool, error) { rint, sint, err :=getSign(signature) if err != nil { return false, err } result := ecdsa.Verify(&key,text,&rint,&sint) return result, nil}/** hash加密 使用md5加密 */func hashtext(text, salt string) ([]byte) { Md5Inst := md5.New() Md5Inst.Write([]byte(text)) result := Md5Inst.Sum([]byte(salt)) return result}func main() { //隨機熵,用於加密安全 randSign := "20180619zafes" //隨機key,用於建立公開金鑰和私密金鑰 randKey := "fb0f7279c18d4394594fc9714797c9680335a320" //建立公開金鑰和私密金鑰 prk, puk, err := getEcdsaKey(randKey) if err != nil { fmt.Println(err) } //hash加密使用md5用到的salt salt := "131ilzaw" //待加密的明文 text := "hlloaefaefaefaefaefaefaefhelloaefaefaefaefaefaefaefhelloaefaefaefaefaefaefaef" //text1 := "hlloaefaefaefaefaefaefaefhelloaefaefaefaefaefaefaefhelloaefaefaefaefaefaefaef1" //hash取值 htext := hashtext(text,salt) //htext1 := hashtext(text1,salt) //hash值編碼輸出 fmt.Println(hex.EncodeToString(htext)) //hash值進行簽名 result, err := sign(htext,randSign,prk) if err != nil { fmt.Println(err) } //簽名輸出 fmt.Println(result) //簽名與hash值進行校正 tmp, err := verify(htext,result,puk) fmt.Println(tmp)}
借鑒使用……