go语言实现对称加密
AES算法+CTR分组模式
加密思路
第一步:创建aes密码接口
- 创建一个cipher.Block接口
func NewCipher(key []byte) (cipher.Block, error)
参数:秘钥
返回值:一个分组接口
第二步:创建分组模式ctr
- crypto/cipher包
func NewCTR(block Block, iv []byte) Stream
参数1:填写分组接口
参数2:初始向量(大小与分组大小一致)
返回值:一个Stream接口对象
第三步:加密
- Stream的方法
XORKeyStream(dst, src []byte)
参数1:密文空间
参数2:明文
解密思路
与加密完全一致
代码实现
//输入明文,输出密文
func aesCtrEncrypt(plainText, key []byte) ([]byte, error) {
// 第一步:创建aes密码接口
block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
//第二步:创建分组模式ctr
// iv 要与算法长度一致,16字节
// 使用bytes.Repeat创建一个切片,长度为blockSize(),16个字符"1"
iv := bytes.Repeat([]byte("1"), block.BlockSize())
stream := cipher.NewCTR(block, iv)
//第三步:加密
dst := make([]byte, len(plainText))
stream.XORKeyStream(dst, plainText)
return dst, nil
}
//输入密文,得到明文
func aesCtrDecrypt(encryptData, key []byte) ([]byte, error) {
return aesCtrEncrypt(encryptData, key)
}
func main() {
//明文,需要加密的数据
src := "Stream接口代表一个流模式的加/解密器。"
//对称秘钥,aes,16字节
key := "1234567887654321" //16
// key := "12345678876543210" //17, 无效的
encryptData, err := aesCtrEncrypt([]byte(src), []byte(key))
if err != nil {
fmt.Println("加密出错err:", err)
return
}
fmt.Printf("encryptData: %x\n", encryptData)
//调用解密函数
plainText, err := aesCtrDecrypt(encryptData, []byte(key))
if err != nil {
fmt.Println("err:", err)
return
}
fmt.Printf("解密后的数据: %s\n", plainText)
}
DES算法+CBC分组模式
加密思路
第一步:创建des密码接口
- 创建一个cipher.Block接口
func NewCipher(key []byte) (cipher.Block, error)
参数:秘钥
返回值:一个分组接口
第二步:创建分组模式cbc
- crypto/cipher包
func NewCBCEncrypter(b Block, iv []byte) BlockMode
参数1:填写分组接口
参数2:初始向量(大小与分组大小一致)
返回值:一个BlockMode接口对象
第三步:填充
封装一个填充函数
-
得到分组之后剩余的长度
用数据对分组大小取余,得到分组之后的剩余长度
-
得到需要填充的个数
用分组大小减去剩余长度得到需要填充的个数
-
创建一个slice,包含n(需要填充的个数)个n(需要填充的个数)
注意要把数字转化为字符
-
将切片追加到数据中
第四步:加密
- BlockMode的方法
CryptBlocks(dst, src []byte)
参数1:密文空间
参数2:明文
解密思路
第一步:创建des密码接口
与加密一样
第二步:创建分组模式cbc
- crypto/cipher包
func NewCBCDecrypter(b Block, iv []byte) BlockMode
参数1:填写分组接口
参数2:初始向量(大小与分组大小一致)
返回值:一个BlockMode接口对象
第三步:解密
- BlockMode的方法
CryptBlocks(dst, src []byte)
参数1:明文空间
参数2:密文
第四步:去除填充
封装一个去除填充函数
-
获取最后一个字符
-
将字符转换为数字
-
截取切片
代码实现
func desCBCEncrypt(plainText /*明文*/, key []byte) ([]byte, error) {
//第一步:创建des密码接口, 输入秘钥,返回接口
block, err := des.NewCipher(key)
if err != nil {
return nil, err
}
//第二步:创建cbc分组
// 返回一个密码分组链接模式的、底层用b解密的BlockMode接口
// func NewCBCEncrypter(b Block, iv []byte) BlockMode
blockSize := block.BlockSize()
//创建一个8字节的初始化向量
iv := bytes.Repeat([]byte("1"), blockSize)
mode := cipher.NewCBCEncrypter(block, iv)
//第三步:填充
//TODO
plainText, err = paddingNumber(plainText, blockSize)
if err != nil {
return nil, err
}
//第四步:加密
// type BlockMode interface {
// // 返回加密字节块的大小
// BlockSize() int
// // 加密或解密连续的数据块,src的尺寸必须是块大小的整数倍,src和dst可指向同一内存地址
// CryptBlocks(dst, src []byte)
// }
//密文与明文共享空间,没有额外分配
mode.CryptBlocks(plainText /*密文*/, plainText /*明文*/)
return plainText, nil
}
//输入密文,得到明文
func desCBCDecrypt(encryptData, key []byte) ([]byte, error) {
//TODO
//第一步:创建des密码接口
block, err := des.NewCipher(key)
if err != nil {
return nil, err
}
//第二步:创建cbc分组
iv := bytes.Repeat([]byte("1"), block.BlockSize())
mode := cipher.NewCBCDecrypter(block, iv)
//第三步:解密
mode.CryptBlocks(encryptData /*明文*/, encryptData /*密文*/)
//第四步: 去除填充
//TODO
encryptData, err = unPaddingNumber(encryptData)
if err != nil {
return nil, err
}
// return []byte("Hello world"), nil
return encryptData, nil
}
//填充数据
func paddingNumber(src []byte, blockSize int) ([]byte, error) {
if src == nil {
return nil, errors.New("src长度不能小于0")
}
fmt.Println("调用paddingNumber")
//1. 得到分组之后剩余的长度 5
leftNumber := len(src) % blockSize //5
//2. 得到需要填充的个数 8 - 5 = 3
needNumber := blockSize - leftNumber //3
//3. 创建一个slice,包含3个3
b := byte(needNumber)
newSlice := bytes.Repeat([]byte{b}, needNumber) //newSlice ==》 []byte{3,3,3}
fmt.Printf("newSclie : %v\n", newSlice)
//4. 将新切片追加到src
src = append(src, newSlice...)
return src, nil
}
//解密后去除填充数据
func unPaddingNumber(src []byte) ([]byte, error) {
fmt.Println("调用unPaddingNumber")
//1. 获取最后一个字符
lastChar := src[len(src)-1] //byte(3)
//2. 将字符转换为数字
num := int(lastChar) //int(3)
//3. 截取切片(左闭右开)
return src[:len(src)-num], nil
}
func main() {
src := "一行白鹭上青天" //明文
key := "12345678" //秘钥
//加密处理
encryptData, err := desCBCEncrypt([]byte(src), []byte(key))
if err != nil {
fmt.Println("err:", err)
return
}
fmt.Printf("encryptData: %x\n", encryptData)
key = "12345678" //秘钥
//调用解密函数
plainText, err := desCBCDecrypt(encryptData, []byte(key))
if err != nil {
fmt.Println("err:", err)
return
}
fmt.Printf("解密后的数据: %s\n", plainText)
fmt.Printf("解密后的数据 hex : %x\n", plainText)
}