go语言对称加密使用(DES、3DES、AES)

一、数据填充

进行DES、3DES、AES三种对称加密算法时,首先要对原始数据进行字节填充,使原始数据位数与所对应加密算法块数据量成倍数。

(一)常采用PKCS5Padding填充、Zeros填充(0填充)

  • block cipher(分组密码、块密码)

  • block size(块大小)

    • DEA、3DES的block size为8位

    • AES的block size为16位

(二)PKCS5Padding

  • 每个填充的字节都记录了填充的总字节数

  • "a" 填充后:[97 7 7 7 7 7 7 7]

  • "ab" 填充后:[97 98 6 6 6 6 6 6]

  • “一a” 填充后:[228 184 128 97 4 4 4 4]

  • "12345678" 填充后:[49 50 51 52 53 54 55 56 8 8 8 8 8 8 8 8]

PKCS5Padding填充:

// 末尾填充字节
func PKCS5Padding(data []byte, blockSize int) []byte {
	padding := blockSize - len(data)%blockSize // 要填充的值和个数
	slice1 := []byte{byte(padding)}            // 要填充的单个二进制值
	slice2 := bytes.Repeat(slice1, padding)    // 要填充的二进制数组
	return append(data, slice2...)             // 填充到数据末端
}

去除PKCS5Padding填充:

// 去除填充的字节
func PKCS5UnPadding(data []byte) []byte {
	unpadding := data[len(data)-1]                // 获取二进制数组最后一个数值
	result := data[:(len(data) - int(unpadding))] // 截取开始至总长度减去填充值之间的有效数据
	return result
}

(三)ZerosPadding

  • 全部填充为0的字节

  • "a" 填充后:[97 0 0 0 0 0 0 0]

  • "ab" 填充后:[97 98 0 0 0 0 0 0]

  • “一a” 填充后:[228 184 128 97 0 0 0 0]

  • "12345678" 填充后:[49 50 51 52 53 54 55 56 0 0 0 0 0 0 0 0]

ZerosPadding填充:

// 末尾填充0
func ZerosPadding(data []byte, blockSize int) []byte {
	padding := blockSize - len(data)%blockSize // 要填充的个数
	slice1 := []byte{0}                        // 要填充的单个0数据
	slice2 := bytes.Repeat(slice1, padding)    // 要填充的0二进制数组
	return append(data, slice2...)             // 填充到数据末端
}

去除ZerosPadding填充:

// 去除填充的0
func ZerosUnPadding(data []byte) []byte {
	return bytes.TrimRightFunc(data, func(r rune) bool { // 去除满足条件的子切片
		return r == 0
	})
}

二、加密过程

// 对称加密(Symmetric Cryptography)
func SCEncrypt(originalBytes, key []byte, scType string) ([]byte, error) {
	// 1、实例化密码器block(参数为密钥)
	var err error
	var block cipher.Block
	switch scType {
	case "des":
		block, err = des.NewCipher(key)
	case "3des":
		block, err = des.NewTripleDESCipher(key)
	case "aes":
		block, err = aes.NewCipher(key)
	}
	if err != nil {
		return nil, err
	}
	blockSize := block.BlockSize()

	// 2、对明文进行填充(参数为原始字节切片和密码对象的区块个数)
	paddingBytes := PKCS5Padding(originalBytes, blockSize)

	// 3、实例化加密模式(参数为密码对象和密钥)
	blockMode := cipher.NewCBCEncrypter(block, key[:blockSize])

	// 4、对填充字节后的明文进行加密(参数为加密字节切片和填充字节切片)
	cipherBytes := make([]byte, len(paddingBytes))
	blockMode.CryptBlocks(cipherBytes, paddingBytes)
	return cipherBytes, nil
}

三、解密过程

// 对称解密
func SCDecrypt(cipherBytes, key []byte, scType string) ([]byte, error) {
	// 1、实例化密码器block(参数为密钥)
	var err error
	var block cipher.Block
	switch scType {
	case "des":
		block, err = des.NewCipher(key)
	case "3des":
		block, err = des.NewTripleDESCipher(key)
	case "aes":
		block, err = aes.NewCipher(key)
	}
	if err != nil {
		return nil, err
	}
	blockSize := block.BlockSize()

	// 2、实例化解密模式(参数为密码对象和密钥)
	blockMode := cipher.NewCBCDecrypter(block, key[:blockSize])

	// 3、对密文进行解密(参数为填充字节切片和加密字节切片)
	paddingBytes := make([]byte, len(cipherBytes))
	blockMode.CryptBlocks(paddingBytes, cipherBytes)

	// 4、去除填充的字节(参数为填充切片)
	originalBytes := PKCS5UnPadding(paddingBytes)
	return originalBytes, nil
}

四、封装字符串加密解密

// 封装字符串对称加密
func SCEncryptString(originalText, key, scType string) (string, error) {
	cipherBytes, err := SCEncrypt([]byte(originalText), []byte(key), scType)
	if err != nil {
		return "", err
	}
	// base64 编码(encoded)
	base64str := base64.StdEncoding.EncodeToString(cipherBytes)
	return base64str, nil
}

// 封装字符串对称解密
func SCDecryptString(cipherText, key, scType string) (string, error) {
	// base64 解码(decode)
	cipherBytes, _ := base64.StdEncoding.DecodeString(cipherText)
	cipherBytes, err := SCDecrypt(cipherBytes, []byte(key), scType)
	if err != nil {
		return "", err
	}
	return string(cipherBytes), nil
}

五、完整代码

  • DES密钥占8字节

  • 3DES密钥占24字节

  • AES密钥。key长度:16,24,32 bytes 对应 AES-128,AES-192,AES-256

package main

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

func main() {
	// DES密钥
	key := "12345678" // 占8字节
	// 3DES密钥
	// key = "abcdefgh012345678" // 占24字节
	// AES密钥。key长度:16,24,32 bytes 对应 AES-128,AES-192,AES-256
	// key = "01234567abcdefgh" // 占16字节

	keyBytes := []byte(key)
	str := "a"
	cipherArr, err := SCEncrypt([]byte(str), keyBytes, "des")
	if err != nil {
		panic(err)
	}
	fmt.Printf("加密后的字节数组:%v\n", cipherArr)
	fmt.Printf("加密后的字节数组:%x\n", cipherArr)
	originalArr, _ := SCDecrypt(cipherArr, keyBytes, "des")
	fmt.Println(string(originalArr))

	fmt.Println("------------------------------------------------------")

	str = "字符串加密aa12"
	cipherText, _ := SCEncryptString(str, key, "des")
	fmt.Println(cipherText)

	originalText, _ := SCDecryptString(cipherText, key, "des")
	fmt.Println(originalText)
}

// 对称加密(Symmetric Cryptography)
func SCEncrypt(originalBytes, key []byte, scType string) ([]byte, error) {
	// 1、实例化密码器block(参数为密钥)
	var err error
	var block cipher.Block
	switch scType {
	case "des":
		block, err = des.NewCipher(key)
	case "3des":
		block, err = des.NewTripleDESCipher(key)
	case "aes":
		block, err = aes.NewCipher(key)
	}
	if err != nil {
		return nil, err
	}
	blockSize := block.BlockSize()

	// 2、对明文进行填充(参数为原始字节切片和密码对象的区块个数)
	paddingBytes := PKCS5Padding(originalBytes, blockSize)

	// 3、实例化加密模式(参数为密码对象和密钥)
	blockMode := cipher.NewCBCEncrypter(block, key[:blockSize])

	// 4、对填充字节后的明文进行加密(参数为加密字节切片和填充字节切片)
	cipherBytes := make([]byte, len(paddingBytes))
	blockMode.CryptBlocks(cipherBytes, paddingBytes)
	return cipherBytes, nil
}

// 对称解密
func SCDecrypt(cipherBytes, key []byte, scType string) ([]byte, error) {
	// 1、实例化密码器block(参数为密钥)
	var err error
	var block cipher.Block
	switch scType {
	case "des":
		block, err = des.NewCipher(key)
	case "3des":
		block, err = des.NewTripleDESCipher(key)
	case "aes":
		block, err = aes.NewCipher(key)
	}
	if err != nil {
		return nil, err
	}
	blockSize := block.BlockSize()

	// 2、实例化解密模式(参数为密码对象和密钥)
	blockMode := cipher.NewCBCDecrypter(block, key[:blockSize])

	// 3、对密文进行解密(参数为填充字节切片和加密字节切片)
	paddingBytes := make([]byte, len(cipherBytes))
	blockMode.CryptBlocks(paddingBytes, cipherBytes)

	// 4、去除填充的字节(参数为填充切片)
	originalBytes := PKCS5UnPadding(paddingBytes)
	return originalBytes, nil
}

// 封装字符串对称加密
func SCEncryptString(originalText, key, scType string) (string, error) {
	cipherBytes, err := SCEncrypt([]byte(originalText), []byte(key), scType)
	if err != nil {
		return "", err
	}
	// base64 编码(encoded)
	base64str := base64.StdEncoding.EncodeToString(cipherBytes)
	return base64str, nil
}

// 封装字符串对称解密
func SCDecryptString(cipherText, key, scType string) (string, error) {
	// base64 解码(decode)
	cipherBytes, _ := base64.StdEncoding.DecodeString(cipherText)
	cipherBytes, err := SCDecrypt(cipherBytes, []byte(key), scType)
	if err != nil {
		return "", err
	}
	return string(cipherBytes), nil
}

// 末尾填充字节
func PKCS5Padding(data []byte, blockSize int) []byte {
	padding := blockSize - len(data)%blockSize // 要填充的值和个数
	slice1 := []byte{byte(padding)}            // 要填充的单个二进制值
	slice2 := bytes.Repeat(slice1, padding)    // 要填充的二进制数组
	return append(data, slice2...)             // 填充到数据末端
}

// 末尾填充0
func ZerosPadding(data []byte, blockSize int) []byte {
	padding := blockSize - len(data)%blockSize // 要填充的个数
	slice1 := []byte{0}                        // 要填充的单个0数据
	slice2 := bytes.Repeat(slice1, padding)    // 要填充的0二进制数组
	return append(data, slice2...)             // 填充到数据末端
}

// 去除填充的字节
func PKCS5UnPadding(data []byte) []byte {
	unpadding := data[len(data)-1]                // 获取二进制数组最后一个数值
	result := data[:(len(data) - int(unpadding))] // 截取开始至总长度减去填充值之间的有效数据
	return result
}

// 去除填充的0
func ZerosUnPadding(data []byte) []byte {
	return bytes.TrimRightFunc(data, func(r rune) bool { // 去除满足条件的子切片
		return r == 0
	})
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值