zoukankan      html  css  js  c++  java
  • go加密算法:非对称加密(三)--Elliptic

    看了2星期的区块链原理与运行机制,加密这里开始变得有些生疏,花了一天时间复习了一些;看到了之前忽略的,也学会了椭圆曲线加密。
    //基础板:浅显易懂
    package main

    import (
    "crypto/ecdsa"
    "crypto/md5"
    "encoding/hex"
    "fmt"
    "math/big"
    "strings"

    "crypto/elliptic"
    "crypto/rand"
    )

    func main() {
    src := []byte(string("少壮不努力,活该你单身23333"))
    //src1 := []byte(string("少壮不努力,老大徒伤悲3344"))
    mysrc := myHash(src)
    //mysrc1 := myHash(src1)

    prk, puk, _ := genePriPubKey()
    mystring := sign(prk, mysrc)

    r, s := getSign(mystring)

    result := verifySign(&r, &s, mysrc, puk)
    fmt.Print(result)

    }

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

    var err error
    var pubkey ecdsa.PublicKey
    var prikey *ecdsa.PrivateKey
    var curve elliptic.Curve

    curve = elliptic.P384()
    prikey, err = ecdsa.GenerateKey(curve, rand.Reader)
    if err != nil {
    return prikey, pubkey, err
    }
    pubkey = prikey.PublicKey

    return prikey, pubkey, err
    }
    func myHash(src []byte) []byte {
    myhash := md5.New()
    myhash.Write(src)
    return myhash.Sum(nil)
    }

    func sign(key *ecdsa.PrivateKey, myhash []byte) string {
    r, s, _ := ecdsa.Sign(rand.Reader, key, myhash)
    rm, _ := r.MarshalText()
    sm, _ := s.MarshalText()

    return hex.EncodeToString([]byte(string(rm) + "+" + string(sm)))
    }

    func getSign(hexrs string) (rint, sint big.Int) {
    st, _ := hex.DecodeString(hexrs)
    str := strings.Split(string(st), "+")
    _ = rint.UnmarshalText([]byte(str[0]))
    //rint是指针:error: invalid memory address or nil pointer dereference
    _ = sint.UnmarshalText([]byte(str[1]))

    return
    }

    func verifySign(rint, sint *big.Int, myhash []byte, pubkey ecdsa.PublicKey) bool {
    result := ecdsa.Verify(&pubkey, myhash, rint, sint)
    return result
    }
    //进阶版:结合gzip/bytes的使用,加入缓冲
    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)
    }
  • 相关阅读:
    删除链表的倒数第N个节点
    SVN快速入门(TSVN)
    C# HttpWebRequest提交数据方式浅析
    简单的3个SQL视图搞定所有SqlServer数据库字典
    简单统计SQLSERVER用户数据表大小(包括记录总数和空间占用情况)
    详细讲解Android对自己的应用代码进行混淆加密防止反编译
    PHP之网络编程
    PHP之ThinkPHP模板标签操作
    PHP之ThinkPHP数据操作CURD
    关于数组的取极值和排序
  • 原文地址:https://www.cnblogs.com/eilinge/p/10225079.html
Copyright © 2011-2022 走看看