go系列-加密与解密

1 Base64加密与解密

1.1 标准编码与解码

package main

import (
	"encoding/base64"
	"fmt"
)

func main() {

	var str string = "杨国强"
   //标准加密
	encoded := base64.StdEncoding.EncodeToString([]byte(str))
	fmt.Printf("str:%v\n", encoded)

   //标准解密
	decoded, err := base64.StdEncoding.DecodeString(encoded)
	if err != nil {
		fmt.Printf("decode base 64 failed:%v\n", err)
		return
	}
    fmt.Printf("str:%v\n", string(decoded)) 
  
}

运行结果

# go run base64.go

str:5p2o5Zu95by6

str:杨国强

1.2 URL编码和解码

URL和文件名安全方式是标准方式的变体,其输出用于URL和文件名。因为+和/字符是标准Base64字符对URL和文件名编码不安全,变体即使用-代替+,_(下划线)代替/。

func decode() {
	data := "hello world12345!?$*&()'-@~"

	uEnc := base64.URLEncoding.EncodeToString([]byte(data))

    // Base64 Url Decoding
	uDec, err := base64.URLEncoding.DecodeString(uEnc)
	if err != nil {
		fmt.Printf("Error decoding string: %s ", err.Error())
		return
	}
	
	fmt.Println(string(uDec)) // "hello world12345!?$*&()'-@~"
}

1.3 无填充编码

标准Base64编码对输出结果使用=进行填充。一般也建议使用填充方式,但一些场景无需填充。我们可以使用Raw方式编码即没有填充。

func main() {
	data := "abc!?$*&()'-@~"

	// Base64 Encoding without Padding
	swEnc := base64.RawStdEncoding.EncodeToString([]byte(data))
	fmt.Println(swEnc) // YWJjIT8kKiYoKSctQH4

	// Base64 Url Encoding without Padding
	uwEnc := base64.RawURLEncoding.EncodeToString([]byte(data))
	fmt.Println(uwEnc) //YWJjIT8kKiYoKSctQH4
}

2 aes256加密与解密

package main

import (
	"bytes"
	"crypto/aes"
	"crypto/cipher"
	"crypto/rand"
	"encoding/base64"
	"encoding/binary"
	"fmt"
)

func Encrypt(data []byte, key string) (string, error) {
	keyData, err := aes.NewCipher([]byte(key))
	if err != nil {
		return "", err
	}
	data, err = pad(data, aes.BlockSize)
	if err != nil {
		return "", err
	}
	iv := random(aes.BlockSize)
	mode := cipher.NewCBCEncrypter(keyData, []byte(iv))
	mode.CryptBlocks(data, data)
	return iv + base64.StdEncoding.EncodeToString(data), nil
}

func Decrypt(encrypted string, password string) ([]byte, error) {
	keyData, err := aes.NewCipher([]byte(password))
	if err != nil {
		return nil, err
	}
	if len(encrypted) <= aes.BlockSize {
		return nil, fmt.Errorf("encrypted data too short")
	}
	iv := encrypted[:aes.BlockSize]
	encryptedString := encrypted[aes.BlockSize:]
	data, err := base64.StdEncoding.DecodeString(encryptedString)
	if err != nil {
		return nil, err
	}
	mode := cipher.NewCBCDecrypter(keyData, []byte(iv))
	mode.CryptBlocks(data, data)
	data, err = unpad(data, aes.BlockSize)
	if err != nil {
		return nil, err
	}
	return data, nil
}

// PKCS#7 padding

func pad(b []byte, blocksize int) ([]byte, error) {
	if blocksize <= 0 {
		return nil, fmt.Errorf("invalid blocksize %d", blocksize)
	}
	if len(b) == 0 {
		return nil, fmt.Errorf("invalid data")
	}
	n := blocksize - (len(b) % blocksize)
	pb := make([]byte, len(b)+n)
	copy(pb, b)
	copy(pb[len(b):], bytes.Repeat([]byte{byte(n)}, n))
	return pb, nil
}

func unpad(b []byte, blocksize int) ([]byte, error) {
	if blocksize <= 0 {
		return nil, fmt.Errorf("invalid blocksize %d", blocksize)
	}
	if len(b) == 0 {
		return nil, fmt.Errorf("invalid data")
	}
	if len(b)%blocksize != 0 {
		return nil, fmt.Errorf("invalid data length")
	}
	c := b[len(b)-1]
	n := int(c)
	if n == 0 || n > len(b) {
		return nil, fmt.Errorf("invalid padding")
	}
	for i := 0; i < n; i++ {
		if b[len(b)-n+i] != c {
			return nil, fmt.Errorf("invalid padding")
		}
	}
	return b[:len(b)-n], nil
}

// String generates a random string using only letters provided in the letters parameter
// if user ommit letters parameters, this function will use defLetters instead
func random(n int, letters ...string) string {
	defLetters := []rune("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
	var letterRunes []rune
	if len(letters) == 0 {
		letterRunes = defLetters
	} else {
		letterRunes = []rune(letters[0])
	}
	var bb bytes.Buffer
	bb.Grow(n)
	l := uint32(len(letterRunes))
	// on each loop, generate one random rune and append to output
	for i := 0; i < n; i++ {
		bb.WriteRune(letterRunes[binary.BigEndian.Uint32(genBytes(4))%l])
	}
	return bb.String()
}

// Bytes generates n random bytes
func genBytes(n int) []byte {
	b := make([]byte, n)
	_, err := rand.Read(b)
	if err != nil {
		panic(err)
	}
	return b
}
func main() {
	//key := random(32)
	key := "HXl8G2+60gnxdvi.oP5?L94*F=VrDM3_"
	//key := "XPhtIGprLh8AJ01CvkFstT8Ze34TQNMi"
	println("key:", key)
	pwd := "test123"
	encrypted, err := Encrypt([]byte(pwd), key)
	if err != nil {
		fmt.Printf("encrypt error: %v\n", err)
		return
	}
	fmt.Printf("encrypt:%v\n",encrypted)
	decrypted, err := Decrypt(encrypted, key)
	if err != nil {
		fmt.Printf("decrypt error: %v\n", err)
		return
	}
	if string(decrypted) != pwd {
		 fmt.Printf("Decrypted text does not match original text")
	}
	fmt.Printf("decrypted:%v\n",string(decrypted))
}

运行结果:

key: HXl8G2+60gnxdvi.oP5?L94*F=VrDM3_
encrypt:tHEfGSTj2ZAgfM6hxem3wCzmUsrT+Zfq4Mk3hA==
decrypted:test123

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

alden_ygq

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值