Go语言aes加密解密处理
文章目录
1. 概述
1.1 AES概述
高级加密标准(英语:Advanced Encryption Standard,缩写:AES),又称Rijndael加密法(荷兰语发音:[ˈrɛindaːl],音似英文的“Rhine doll”),是美国联邦政府采用的一种区块加密标准。这个标准用来替代原先的DES,已经被多方分析且广为全世界所使用。经过五年的甄选流程,高级加密标准由美国国家标准与技术研究院(NIST)于2001年11月26日发布于FIPS PUB 197,并在2002年5月26日成为有效的标准。现在,高级加密标准已然成为对称密钥加密中最流行的算法之一。
该算法为比利时密码学家Joan Daemen和Vincent Rijmen所设计,结合两位作者的名字,以Rijndael为名投稿高级加密标准的甄选流程。
更多说明请查看:
https://zh.wikipedia.org/wiki/高级加密标准
1.2 分组密码工作模式
密码学中,分组密码的工作模式(mode of operation)允许使用同一个分组密码密钥对多于一块的数据进行加密,并保证其安全性。将数据扩展到符合密码块大小的长度。一种工作模式描述了加密每一数据块的过程,并常常使用基于一个通常称为初始化向量的附加输入值以进行随机化,以保证安全。
工作模式主要用来进行加密和认证。对加密模式的研究曾经包含数据的完整性保护,即在某些数据被修改后的情况下密码的误差传播特性。后来的研究则将完整性保护作为另一个完全不同的,与加密无关的密码学目标。部分现代的工作模式用有效的方法将加密和认证结合起来,称为认证加密模式。
虽然工作模式通常应用于对称加密,它亦可以应用于公钥加密,例如在原理上对RSA进行处理,但在实用中,公钥密码学通常不用于加密较长的信息,而是使用结合对称加密和公钥加密的混合加密方案。
最早出现的工作模式,ECB,CBC,OFB和CFB可以追溯到1981年。2001年,NIST修订了其早先发布的工作模式任务栏表,加入了AES,并加入了CTR模式。最后,在2010年1月,NIST加入了XTS-AES,而其余的可信模式并没有为NIST所认证。例如CTS是一种密文窃取的模式,许多常见的密码学运行库提供了这种模式。
ECB,CBC,OFB,CFB,CTR和XTS模式仅仅提供了机密性;为了保证加密信息没有被意外修改或恶意篡改,需要采用分离的消息验证码,例如CBC-MAC。密码学社区认识到了对专用的保证完整性的方法的需求,NIST因此提出了HMAC,CMAC和GMAC。HMAC在2002年通过了认证,CMAC在2005年通过,GMAC则在2007年被标准化。
在发现将认证模式与加密模式联合起来的难度之后,密码学社区开始研究结合了加密和认证的单一模式,这种模式被称为认证加密模式(AE,Authenticated Encryption),或称为authenc。AE模式的例子包括CCM,GCM[11],CWC,EAX,IAPM和OCB。
现在,工作模式为许多国家和国内的标准认证实体所定义,其中最有影响力的来源是美国的NIST,而其它有影响力的组织包括ISO,IEC,IEEE,美国的ANSI,以及IETF。
常见模式:电子密码本(ECB)、密码块链接(CBC)、填充密码块链接(PCBC)、密文反馈(CFB)、输出反馈(OFB)、计数器模式(CTR)。
更多请查看:https://zh.wikipedia.org/wiki/%E5%88%86%E7%BB%84%E5%AF%86%E7%A0%81%E5%B7%A5%E4%BD%9C%E6%A8%A1%E5%BC%8F#%E8%AE%A1%E6%95%B0%E5%99%A8%E6%A8%A1%E5%BC%8F%EF%BC%88CTR%EF%BC%89
2. go实现
2.1 CBC模式
func PKCS5Padding(plaintext []byte, blockSize int) []byte {
padding := blockSize - len(plaintext)%blockSize
paddingText := bytes.Repeat([]byte{byte(padding)}, padding)
return append(plaintext, paddingText...)
}
func PKCS5UnPadding(origData []byte) []byte {
length := len(origData)
unPadding := int(origData[length-1])
return origData[:(length - unPadding)]
}
func AESEncryptCBC(origData, key []byte) ([]byte, error) {
block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
//AES分组长度为128位,所以blockSize=16,单位字节
blockSize := block.BlockSize()
origData = PKCS5Padding(origData, blockSize)
blockMode := cipher.NewCBCEncrypter(block, key[:blockSize]) //初始向量的长度必须等于块block的长度16字节
encrypted := make([]byte, len(origData))
blockMode.CryptBlocks(encrypted, origData)
return encrypted, nil
}
func AESDecryptCBC(encrypted, key []byte) ([]byte, error) {
block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
//AES分组长度为128位,所以blockSize=16,单位字节
blockSize := block.BlockSize()
blockMode := cipher.NewCBCDecrypter(block, key[:blockSize]) //初始向量的长度必须等于块block的长度16字节
origData := make([]byte, len(encrypted))
blockMode.CryptBlocks(origData, encrypted)
origData = PKCS5UnPadding(origData)
return origData, nil
}
填充和去除填充的模式可以更改。
2.2 ECB模式
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)]
}
func AESDecryptECB(data, key []byte) []byte {
block, _ := aes.NewCipher(key)
decrypted := make([]byte, len(data))
size := block.BlockSize()
for bs, be := 0, size; bs < len(data); bs, be = bs+size, be+size {
block.Decrypt(decrypted[bs:be], data[bs:be])
}
return PKCS7UnPadding(decrypted)
}
func AESEncryptECB(data, key []byte) []byte {
block, _ := aes.NewCipher(key)
data = PKCS7Padding(data, block.BlockSize())
decrypted := make([]byte, len(data))
size := block.BlockSize()
for bs, be := 0, size; bs < len(data); bs, be = bs+size, be+size {
block.Encrypt(decrypted[bs:be], data[bs:be])
}
return decrypted
}
2.3 使用实例
package main
import (
"encoding/base64"
"fmt"
"gitlab.com/xxx/util"
)
func main() {
password := "admin"
data := util.AESEncryptECB([]byte(password), []byte("0123456789abcdef"))
cre := util.AESDecryptECB(data, []byte("0123456789abcdef"))
fmt.Println(string(cre))
fmt.Println(base64.StdEncoding.EncodeToString(data))
data, _ = util.AESEncryptCBC([]byte(password), []byte("0123456789abcdef"))
cre, _ = util.AESDecryptCBC(data, []byte("0123456789abcdef"))
fmt.Println(string(cre))
fmt.Println(base64.StdEncoding.EncodeToString(data))
}
结果:
admin
goLfAELVjjdnoF2e9yy11w==
admin
0bfPC68vdB69vK516zf/Ig==