0


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
    })
}
标签: golang 安全

本文转载自: https://blog.csdn.net/qq_30712797/article/details/128451538
版权归原作者 咸甜适中 所有, 如有侵权,请联系我们删除。

“go语言对称加密使用(DES、3DES、AES)”的评论:

还没有评论