TrumanWong

Go AES加密(CBC模式)

TrumanWong
2/24/2023

前言

高级加密标准A dvanced Encryption Standard,缩写AES,又称Rijndael加密法,是美国联邦政府采用的一种区块加密标准。这个标准用来替代原先的DES,已经被多方分析且广为全世界所使用。经过五年的甄选流程,高级加密标准由美国国家标准与技术研究院(NIST)于2001年11月26日发布于FIPS PUB 197,并在2002年5月26日成为有效的标准。现在,高级加密标准已然成为对称密钥加密中最流行的算法之一。

该算法为比利时密码学家Joan DaemenVincent Rijmen所设计,结合两位作者的名字,以Rijndael为名投稿高级加密标准的甄选流程。

对称加密

AES是对称加密算法,优缺点如下:

  • 优点

    加密速度快。

  • 缺点

    如果密钥丢失,就容易解密密文,安全性相对较差

AES加密需要:明文+密钥+偏移量IV+密码模式(算法/模式/填充)

AES解密需要:密文+密钥+偏移量IV+密码模式(算法/模式/填充)

AES算法模式一般为AESCBCPKCS7Padding等。

加密模式

AES的加密模式有以下几种

  • 电码本模式ECB
  • 密码分组链接模式CBC
  • 计算器模式CTR
  • 密码反馈模式CFB
  • 输出反馈模式OFB

填充模式

  • ZeroPadding

    数据长度不对齐时使用0填充,否则不填充。

  • PKCS7Padding

    假设数据长度需要填充n(n>0)个字节才对齐,那么填充n个字节,每个字节都是n;如果数据本身就已经对齐了,则填充一块长度为块大小的数据,每个字节都是块大小。

  • PKCS5Padding

    PKCS7Padding的子集,块大小固定为8字节,两者的区别在于PKCS5Padding是限制块大小的PKCS7Padding

编码

package encrypt

import (
    "bytes"
    "crypto/aes"
    "crypto/cipher"
)

// AesCBCEncrypt key密钥长度必须为16/24/32位, iv偏移量
func AesCBCEncrypt(input, key, iv []byte) ([]byte, error) {
    block, err := aes.NewCipher(key)
    if err != nil {
        return nil, err
    }
    input = PKCS7Padding(input, block.BlockSize())
    // 偏移量,不传取密钥的前16个字符
    if len(iv) == 0 {
        iv = key[:block.BlockSize()]
    }
    // 加密模式
    blockMode := cipher.NewCBCEncrypter(block, iv)
    encrypt := make([]byte, len(input))
    blockMode.CryptBlocks(encrypt, input)
    return encrypt, nil
}

// AesCBCDecrypt key密钥长度必须为16/24/32位
func AesCBCDecrypt(input, key, iv []byte) ([]byte, error) {
    block, err := aes.NewCipher(key)
    if err != nil {
        return nil, err
    }
    // 偏移量,不传取密钥的前16个字符
    if len(iv) == 0 {
        iv = key[:block.BlockSize()]
    }
    // 加密模式
    blockMode := cipher.NewCBCDecrypter(block, iv)
    decrypt := make([]byte, len(input))
    blockMode.CryptBlocks(decrypt, input)
    decrypt = PKCS7UnPadding(decrypt)
    return decrypt, nil
}

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