Go语言在标准库的crypto包中提供了一系列的子包用于各种主流类型的加密解密算法,例如其中的des子包用于实现流行的对称加密算法DES和3DES,aes子包用于实现比des加密算法强度更大的AES加密算法,rsa包用于实现经典的不对称加密算法RSA,md5包用于实现不可逆加密算法md5,而sha1用于实现比md5抗穷举法破解能力更强的SHA1算法。
下面的代码演示了如何使用crypto/aes包实现AES加密算法。
package main
import (
"bytes"
"crypto/aes"
"crypto/cipher"
"fmt"
"io"
"log"
)
// encryptByAES 是用AES算法加密字符串textA的函数,keyA表示密钥
func encryptByAES(textA, keyA string) []byte {
//将密钥转换成字节,密钥的最终形式应该是字节序列
keyT := []byte(keyA)
//将原文也转换为字节切片
inBytesT := []byte(textA)
//生成准备用于流式编码的缓冲区
inBufT := bytes.NewBuffer(inBytesT)
//生成AES加密块
blockT, errT := aes.NewCipher(keyT)
if errT != nil {
log.Fatal(errT)
}
var iv [aes.BlockSize]byte
//使用AES的OFB模式
streamT := cipher.NewOFB(blockT, iv[:])
outBufT := new(bytes.Buffer)
//生成流式写入器
writer := &cipher.StreamWriter{S: streamT,W: outBufT}
//真正进行加密的步骤
if _, errT := io.Copy(writer, inBufT); errT !=nil {
log.Fatal(errT)
}
return outBufT.Bytes()
}
// decryptByAES 是用AES算法解密字符串的函数,keyA表示密钥,bytesA是密文数据
func decryptByAES(bytesA []byte, keyA string) string {
//将密文转换成可以流式操作的类型
inBufT := bytes.NewBuffer(bytesA)
//密钥转换成字节切片
keyT := []byte(keyA)
//生成AES加密块
blockT, errT := aes.NewCipher(keyT)
if errT != nil {
log.Fatal(errT)
}
var iv [aes.BlockSize]byte
//使用AES的OFB模式
streamT := cipher.NewOFB(blockT, iv[:])
//准备流式读取器
readerT := &cipher.StreamReader{S:streamT, R: inBufT}
//用于存放解密数据的缓冲区
outBufT := new(bytes.Buffer)
//实际进行解密的步骤
if _, errT := io.Copy(outBufT, readerT); errT!= nil {
log.Fatal(errT)
}
return string(outBufT.Bytes())
}
func main() {
//原文
textT := "This is an example."
fmt.Printf("原文:%#v\n", textT)
//密钥长度应为16、24或32个字节,分别对应AES-128、AES-192、AES-256这三个AES的细分算法
keyT := "abcd1234_$*&ui1!"
fmt.Printf("密钥:%#v\n", keyT)
//调用encryptByAES函数来加密
encBytesT := encryptByAES(textT, keyT)
fmt.Printf("加密后密文数据:%#v\n", encBytesT)
//调用decryptByAES来解密
decTextT := decryptByAES(encBytesT, keyT)
fmt.Printf("解密后还原的数据:%#v\n", decTextT)
}
代码 14‑6 用crypto/aes包实现AES加密、解密算法
代码14‑6中,将AES加密的算法封装进了encryptByAES函数中,将AES解密算法封装进了decryptByAES中,代码中都有详细的注释,我们再补充两点:
-> 这些加解密算法一般都是针对字节切片类型的数据的,本例是为了演示方便,原文和密钥都使用了字符串,但在加解密之前实际上都是转换成了字节切片再进行下一步操作的;
-> 密钥长度应为16、24或32个字节,分别对应AES-128、AES-192、AES-256这三个AES的细分算法,随着字节数的上升,加密强度将随之升高。本例中使用的密钥是16个字符长度的字符串,由于其中都是ASCII字符,因此转换成字节切片长度也是16,对应的细分算法应该是AES-128。
代码14‑6的运行结果是:
可以看到,多次加解密都得到了正确的结果。