Go 对称加密解密工具

91 阅读2分钟

加解密部分

package main

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

// 使用PKCS7进行填充,IOS也是7
func PKCS7Padding(ciphertext []byte, blockSize int) []byte {
	padding := blockSize - len(ciphertext)%blockSize
	padtext := bytes.Repeat([]byte{byte(padding)}, padding)
	return append(ciphertext, padtext...)
}

func PKCS7UnPadding(origData []byte) []byte {
	length := len(origData)
	unpadding := int(origData[length-1])
	return origData[:(length - unpadding)]
}

// aes加密,填充秘钥key的16位,24,32分别对应AES-128, AES-192, or AES-256.
func AesCBCEncrypt(rawData, key []byte) ([]byte, error) {
	block, err := aes.NewCipher(key)
	if err != nil {
		panic(err)
	}

	blockSize := block.BlockSize()
	rawData = PKCS7Padding(rawData, blockSize)
	//初始向量IV必须是唯一,但不需要保密
	cipherText := make([]byte, blockSize+len(rawData))

	iv := cipherText[:blockSize]
	if _, err := io.ReadFull(rand.Reader, iv); err != nil {
		panic(err)
	}

	mode := cipher.NewCBCEncrypter(block, iv)
	mode.CryptBlocks(cipherText[blockSize:], rawData)

	return cipherText, nil
}

func AesCBCDncrypt(encryptData, key []byte) ([]byte, error) {
	block, err := aes.NewCipher(key)
	if err != nil {
		panic(err)
	}

	blockSize := block.BlockSize()

	if len(encryptData) < blockSize {
		panic("ciphertext too short")
	}
	iv := encryptData[:blockSize]
	encryptData = encryptData[blockSize:]

	// CBC mode always works in whole blocks.
	if len(encryptData)%blockSize != 0 {
		panic("ciphertext is not a multiple of the block size")
	}

	mode := cipher.NewCBCDecrypter(block, iv)

	// CryptBlocks can work in-place if the two arguments are the same.
	mode.CryptBlocks(encryptData, encryptData)
	//解填充
	encryptData = PKCS7UnPadding(encryptData)
	return encryptData, nil
}

func Encrypt(rawData, key []byte) (string, error) {
	data, err := AesCBCEncrypt(rawData, key)
	if err != nil {
		return "", err
	}
	return base64.StdEncoding.EncodeToString(data), nil
}

func Dncrypt(rawData string, key []byte) (string, error) {
	data, err := base64.StdEncoding.DecodeString(rawData)
	if err != nil {
		return "", err
	}
	dnData, err := AesCBCDncrypt(data, key)
	if err != nil {
		return "", err
	}
	return string(dnData), nil
}


命令行处理部分

package main

import (
	"fmt"

	"github.com/spf13/cobra"
)

var pass string
var key string

var ciperCmd = &cobra.Command{
	Use:   "cipher",
	Short: "用于对字符串进行加密解密",
	Run: func(cmd *cobra.Command, args []string) {

		key := PKCS7Padding([]byte(key), 16)

		dFlag, _ := cmd.Flags().GetBool("decry")
		eFlag, _ := cmd.Flags().GetBool("encry")
		if dFlag && eFlag {
			panic("不能同时指定 decry(d) 和 encry(e)")
		} else if !dFlag && !eFlag {
			panic("必须要指定 decry(d) 和 encry(e) 中的一个")
		} else if dFlag {
			res, err := Dncrypt(pass, key)
			if err != nil {
				panic(err)
			} else {
				fmt.Println(res)
			}
		} else {
			res, err := Encrypt([]byte(pass), key)
			if err != nil {
				panic(err)
			} else {
				fmt.Println(res)
			}
		}
	},
}

func init() {
	ciperCmd.Flags().BoolP("encry", "e", false, "如果需要加密指定此参数")
	ciperCmd.Flags().BoolP("decry", "d", false, "如果需要解密指定此参数")
	ciperCmd.Flags().StringVarP(&pass, "string", "s", "", "指定需要加密或者解密的字符串")

	ciperCmd.MarkFlagRequired("pass")
}

func main() {
	key = "yAoLOEe46mikbDT5"
	ciperCmd.Execute()
}