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))
}