go加密

1、对称加密Nacl包的使用

/*
go对称加密NACl:networking and cryptography library
*/
package main

import (
    "crypto/rand"
    "errors"
    "fmt"
    "golang.org/x/crypto/nacl/secretbox"
    "io"
)

const (
    KeySize   = 32
    NonceSize = 24
)

//根据/dev/urandom这个块设备文件读取到随机数-在linux系统中执行 【od  /dev/urandom】可以查看随机数在不停的产生
func GenerateKey() (*[KeySize]byte, error) {
    key := new([KeySize]byte)

    n, err := io.ReadFull(rand.Reader, key[:])
    fmt.Println(n)
    if err != nil {
        return nil, err
    }
    return key, nil
}

func GenerateNonce() (*[NonceSize]byte, error) {
    nonce := new([NonceSize]byte)

    n, err := io.ReadFull(rand.Reader, nonce[:])
    fmt.Println(n)
    if err != nil {
        return nil, err
    }
    return nonce, nil
}

var (
    ErrEncrypt = errors.New("secret: encryption failed")
    ErrDncrypt = errors.New("secret: decryption failed")
)

//Encrypt方法,生产一个随机nonce然后使用Nacl的secretbox包来加密。
func Encrypt(key *[KeySize]byte, message []byte) ([]byte, error) {
    nonce, err := GenerateNonce()
    if err != nil {
        return nil, ErrEncrypt
    }
    out := make([]byte, len(nonce))
    copy(out, nonce[:])
    out = secretbox.Seal(out, message, nonce, key) //加密函数
    return out, nil
}

//解密需要检查密文的长度保证密文的完成性,在解密的过程,Key值的交换是需要保密的
func Decrypt(key *[KeySize]byte, message []byte) ([]byte, error) {
    if len(message) < (NonceSize + secretbox.Overhead) {
        return nil, ErrDncrypt
    }
    var nonce [NonceSize]byte
    copy(nonce[:], message[:NonceSize])
    out, ok := secretbox.Open(nil, message[NonceSize:], &nonce, key) //解密函数
    if !ok {
        return nil, ErrDncrypt
    }
    return out, nil
}

func main() {
    key, _ := GenerateKey()
    message, _ := Encrypt(key, []byte("google"))
    fmt.Println(message)
    plainText, _ := Decrypt(key, message)
    fmt.Println(string(plainText))
}

2、AES-GCM加密

/*
go对称加密AES-GCM加密
*/
package main

import (
    "crypto/aes"
    "crypto/cipher"
    "crypto/rand"
    "encoding/binary"
    "errors"
    "fmt"
    "io"
)

const (
    KeySize   = 32
    NonceSize = 12
)

//根据/dev/urandom这个块设备文件读取到随机数-在linux系统中执行 【od  /dev/urandom】可以查看随机数在不停的产生
func GenerateKey() (*[KeySize]byte, error) {
    key := new([KeySize]byte)

    _, err := io.ReadFull(rand.Reader, key[:])
    if err != nil {
        return nil, err
    }
    return key, nil
}

func GenerateNonce() (*[NonceSize]byte, error) {
    nonce := new([NonceSize]byte)

    _, err := io.ReadFull(rand.Reader, nonce[:])
    if err != nil {
        return nil, err
    }
    return nonce, nil
}

var (
    ErrEncrypt = errors.New("secret: encryption failed")
    ErrDncrypt = errors.New("secret: decryption failed")
)

//Encrypt方法,加密需要额外的其他数据用于验证密文的完成性,key的长度可以是16字节对应AES-128
//24字节对应AES-192,32字节对应AES-256
func Encrypt(key []byte, message []byte) ([]byte, error) {
    block, err := aes.NewCipher(key)
    if err != nil {
        return nil, ErrEncrypt
    }
    gcm, err := cipher.NewGCM(block)
    if err != nil {
        return nil, ErrEncrypt
    }
    nonce, err := GenerateNonce()
    if err != nil {
        return nil, ErrEncrypt
    }
    //seal函数将密文添加到第一个newNonce后面,最后一个参数用于验证密文完整性使用,这里没有添加内容
    newNonce := nonce[:]
    cipherText := gcm.Seal(newNonce, newNonce, message, nil)
    return cipherText, nil

}

func EncryptWithID(key, message []byte, sender uint32) ([]byte, error) {
    buf := make([]byte, 4)
    binary.BigEndian.PutUint32(buf, sender) //该函数将uint32整数转换成字节流
    block, err := aes.NewCipher(key)
    if err != nil {
        return nil, ErrEncrypt
    }
    gcm, err := cipher.NewGCM(block)
    if err != nil {
        return nil, ErrEncrypt
    }
    nonce, err := GenerateNonce()
    if err != nil {
        return nil, ErrEncrypt
    }
    //seal函数将密文添加到第一个newNonce后面,最后一个参数用于验证密文完整性使用,这里没有添加内容
    newNonce := nonce[:]
    buf = append(buf, newNonce...)
    cipherText := gcm.Seal(buf, newNonce, message, buf[:4]) //加密添加额外的信息,send ID转成bytes内容
    return cipherText, nil

}

//加密如果添加了额外信息,解密需要拿到额外的信息,如上面的sender ID
func DecryptWithID(key, message []byte) ([]byte, error) {
    if len(message) <= NonceSize+4 {
        return nil, ErrDncrypt
    }

    block, err := aes.NewCipher(key)
    if err != nil {
        return nil, ErrDncrypt
    }
    gcm, err := cipher.NewGCM(block)
    if err != nil {
        return nil, ErrDncrypt
    }
    nonec := make([]byte, NonceSize)
    copy(nonec, message[4:])
    plainText, err := gcm.Open(nil, nonec, message[4+NonceSize:], message[:4]) //解密,需要添加额外信息send的密文,即message[:4]部分
    if err != nil {
        return nil, ErrDncrypt
    }
    return plainText, nil
}

func main() {
    key, _ := GenerateKey()
    message, _ := EncryptWithID(key[:], []byte("google"), 100)
    plainText, _ := DecryptWithID(key[:], message)
    fmt.Println("plainText:", string(plainText))
}

3、AES-CTR with HMAC加密

/*
go对称加密AES-CTR with HMAC加密
*/
package main

import (
    "crypto/aes"
    "crypto/cipher"
    "crypto/hmac"
    "crypto/rand"
    "crypto/sha256"
    "errors"
    "fmt"
    "io"
)

const (
    NonceSize = aes.BlockSize
    MACSize   = 32 // Output size of HMAC-SHA-256
    CKeySize  = 32 // Cipher key size - AES-256
    MKeySize  = 32 // HMAC key size - HMAC-SHA-256
)

var KeySize = CKeySize + MKeySize

var (
    ErrEncrypt = errors.New("secret: encryption failed")
    ErrDecrypt = errors.New("secret: decryption failed")
)

func RandBytes(n int) ([]byte, error) {
    r := make([]byte, n)
    _, err := io.ReadFull(rand.Reader, r)
    if err != nil {
        return nil, err
    }
    return r, nil
}

func Encrypt(key, message []byte) ([]byte, error) {
    if len(key) != KeySize {
        return nil, ErrEncrypt
    }
    nonce, err := RandBytes(NonceSize)
    if err != nil {
        return nil, ErrEncrypt
    }
    ct := make([]byte, len(message))
    block, _ := aes.NewCipher(key[:CKeySize])
    ctr := cipher.NewCTR(block, nonce)
    ctr.XORKeyStream(ct, message)

    hash := hmac.New(sha256.New, key[CKeySize:])
    ct = append(nonce, ct...)
    hash.Write(ct)
    ct = hash.Sum(ct)
    return ct, nil

}

func Decrypt(key, message []byte) ([]byte, error) {
    if len(key) != KeySize {
        return nil, ErrDecrypt
    }

    if len(message) <= (NonceSize + MACSize) {
        return nil, ErrDecrypt
    }

    macStart := len(message) - MACSize
    tag := message[macStart:]
    out := make([]byte, macStart-NonceSize)
    message = message[:macStart]

    h := hmac.New(sha256.New, key[CKeySize:])
    h.Write(message)
    mac := h.Sum(nil)
    if !hmac.Equal(mac, tag) {
        return nil, ErrDecrypt
    }

    c, _ := aes.NewCipher(key[:CKeySize])
    ctr := cipher.NewCTR(c, message[:NonceSize])
    ctr.XORKeyStream(out, message[NonceSize:])
    return out, nil
}

func main() {
    key, _ := RandBytes(64)
    message, _ := Encrypt(key[:], []byte("google"))
    plainText, _ := Decrypt(key[:], message)
    fmt.Println("plainText:", string(plainText))
}

推荐阅读更多精彩内容