1. 程式人生 > >go加密演算法:非對稱加密(三)--Elliptic

go加密演算法:非對稱加密(三)--Elliptic

看了2星期的區塊鏈原理與執行機制,加密這裡開始變得有些生疏,花了一天時間複習了一些;看到了之前忽略的,也學會了橢圓曲線加密。
package main

//https://studygolang.com/articles/13228
//https://blog.csdn.net/teaspring/article/details/77834360
import (
    "bytes"
    "compress/gzip"//實現了gzip格式壓縮檔案的讀寫
    "crypto/ecdsa"
    "crypto/elliptic"
    "crypto/md5"
    "crypto/rand"
    "encoding/hex"//實現了16進位制字元表示的編解碼
    "errors"
    "fmt"
    "math/big"//實現了大數字的多精度計算
    "strings"
)
/*
io包提供了對I/O原語的基本介面。本包的基本任務是包裝這些原語已有的實現(如os包裡的原語),
使之成為共享的公共介面,這些公共介面抽象出了泛用的函式並附加了一些相關的原語的操作
*/
/**
  通過一個隨機key建立公鑰和私鑰
  隨機key至少為36位
*/

func getEcdsaKey() (*ecdsa.PrivateKey, ecdsa.PublicKey, error) {

    var err error

    var prk *ecdsa.PrivateKey
    var puk ecdsa.PublicKey
    var curve elliptic.Curve
    curve = elliptic.P256()

    //func NewReader(s string) *Reader
    prk, err = ecdsa.GenerateKey(curve,rand.Reader)
    if err != nil {
        return prk, puk, err
    }
    //prk:私鑰 puk:公鑰
    puk = prk.PublicKey

    return prk, puk, err

}

/**
  對text加密,text必須是一個hash值,例如md5、sha1等
  使用私鑰prk
  返回加密結果,結果為數字證書r、s的序列化後拼接,然後用hex轉換為string
*/
func sign(text []byte, prk *ecdsa.PrivateKey) (string, error) {

    //r, s, err := ecdsa.Sign(strings.NewReader(randSign), prk, text)
    r, s, err := ecdsa.Sign(rand.Reader, 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
    //建立並返回一個Writer。寫入返回值的資料都會在壓縮後寫入w
    w := gzip.NewWriter(
&b) //內建函式close關閉通道,該通道必須為雙向的或只發送的 //defer通常用來釋放函式內部變數。 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 } /* gzip.NewReader(r io.Reader) (*Reader, error) 返回一個從r讀取並解壓資料的*Reader。其實現會緩衝輸入流的資料,並可能從r中讀取比需要的更多的資料。 呼叫者有責任在讀取完畢後呼叫返回值的Close方法。 buffer.NewBuffer(buf []byte) *Buffer { return
&Buffer{buf: buf} } 使用buf作為初始內容建立並初始化一個Buffer。本函式用於建立一個用於讀取已存在資料的buffer; 也用於指定用於寫入的內部緩衝的大小, 此時,buf應為一個具有指定容量但長度為0的切片。buf會被作為返回值的底層緩衝切片。 大多數情況下,new(Buffer)(或只是宣告一個Buffer型別變數)就足以初始化一個Buffer了。 */ //Buffer是一個實現了讀寫方法的可變大小的位元組緩衝 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) //Reader型別滿足io.Reader介面,可以從gzip格式壓縮檔案讀取並解壓資料。 //一般,一個gzip檔案可以是多個gzip檔案的串聯,每一個都有自己的頭域。從Reader讀取資料會返回串聯的每個檔案的解壓資料, // 但只有第一個檔案的頭域被記錄在Reader的Header欄位裡。 //gzip檔案會儲存未壓縮資料的長度與校驗和。當讀取到未壓縮資料的結尾時,如果資料的長度或者校驗和不正確, //Reader會返回ErrCheckSum。因此,呼叫者應該將Read方法返回的資料視為暫定的,直到他們在資料結尾獲得了一個io.EOF。 count, err := r.Read(buf) //func (z *Reader) Read(p []byte) (n int, err error) if err != nil { fmt.Println("decode = ", err) err = errors.New("decode read error," + err.Error()) return } //Split(s, sep string) []string //sep:步長 rs := strings.Split(string(buf[:count]), "+") if len(rs) != 2 { err = errors.New("decode fail") return } //實現了Marshaler介面的型別可以將自身序列化為合法的json描述。 //UnmarshalText必須可以解碼MarshalText生成的textual格式資料。 //本函式可能會對data內容作出修改,所以如果要保持data的資料請事先進行拷貝 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加密 msg+ */ //func hashtext(text, salt string) []byte { func hashtext(text string) []byte { Md5Inst := md5.New() Md5Inst.Write([]byte(text)) //result := Md5Inst.Sum([]byte(salt)) return Md5Inst.Sum(nil) } func main() { //建立公鑰和私鑰 prk, puk, err := getEcdsaKey() if err != nil { fmt.Println(err) } //待加密的明文 text := string("少壯不努力,活該你單身2333") //hash取值 htext := hashtext(text) //hash值編碼輸出 hex.EncodeToString(htext) //hash值+私鑰進行簽名 result, err := sign(htext, prk) if err != nil { fmt.Println(err) } //簽名與hash值進行校驗 //hash值+密文+公鑰 tmp, err := verify(htext, result, puk) fmt.Println(tmp) }