需求:算法:des , 分组模式:CBC

des :
秘钥:8bytes
分组长度:8bytes

cbc:
1. 提供初始化向量,长度与分组长度相同,8bytes
2. 需要填充

加密分析

1. 创建并返回一个使用DES算法的cipher.Block接口。

func NewCipher(key []byte) (cipher.Block, error)
– 包名:des
– 参数:秘钥,8bytes
– 返回值:一个cipher.Block接口

type Block interface {
// 返回加密字节块的大小
BlockSize() int
// 加密src的第一块数据并写入dst,src和dst可指向同一内存地址
Encrypt(dst, src []byte)
// 解密src的第一块数据并写入dst,src和dst可指向同一内存地址
Decrypt(dst, src []byte)
}

2. 进行数据填充
//TODO

填充逻辑

举例:

3. 引入CBC模式, 返回一个密码分组链接模式的、底层用b加密的BlockMode接口,初始向量iv的长度必须等于b的块尺寸。
func NewCBCEncrypter(b Block, iv []byte) BlockMode
– 包名:cipher
– 参数1:cipher.Block
– 参数2:iv, initialize vector
– 返回值:分组模式,里面提供加解密方法

type BlockMode interface {
// 返回加密字节块的大小
BlockSize() int
// 加密或解密连续的数据块,src的尺寸必须是块大小的整数倍,src和dst可指向同一内存地址
CryptBlocks(dst, src []byte)
}
————————————————————
解密分析
1. 创建并返回一个使用DES算法的cipher.Block接口。

func NewCipher(key []byte) (cipher.Block, error)
– 包名:des
– 参数:秘钥,8bytes
– 返回值:一个cipher.Block接口

type Block interface {
// 返回加密字节块的大小
BlockSize() int
// 加密src的第一块数据并写入dst,src和dst可指向同一内存地址
Encrypt(dst, src []byte)
// 解密src的第一块数据并写入dst,src和dst可指向同一内存地址
Decrypt(dst, src []byte)
}

2. 返回一个密码分组链接模式的、底层用b解密的BlockMode接口,初始向量iv必须和加密时使用的iv相同。
func NewCBCDecrypter(b Block, iv []byte) BlockMode
– 包名:cipher
– 参数1:cipher.Block
– 参数2:iv, initialize vector
– 返回值:分组模式,里面提供加解密方法

type BlockMode interface {
// 返回加密字节块的大小
BlockSize() int
// 加密或解密连续的数据块,src的尺寸必须是块大小的整数倍,src和dst可指向同一内存地址
CryptBlocks(dst, src []byte)
}

3. 解密操作

4. 去除填充

package main

import (
	"bytes"
	"crypto/cipher"
	"crypto/des"
	"fmt"
)

//输入明文、密钥输出密文
func desCBCEncrypt(src,key []byte) []byte {
	fmt.Printf("加密开始,输入数据:%s\n",src)
	//1. 创建并返回一个使用DES算法的cipher.Block接口。
	block,err := des.NewCipher(key)
	if err != nil{
		panic(err)
	}
	fmt.Println("BlockSize is :",block.BlockSize())

	//2数据填充
	src = paddingInfo(src,block.BlockSize())
	fmt.Println(src)

	//3. 引入CBC模式, 返回一个密码分组链接模式的、底层用b加密的BlockMode接口,初始向量iv的长度必须等于b的块尺寸。
	iv := bytes.Repeat([]byte("1"),block.BlockSize())
	blockMode := cipher.NewCBCEncrypter(block,iv)

	//4、加密操作
	blockMode.CryptBlocks(src,src) //密文赋值,明文

	fmt.Printf("加密结束,数据为:%x\n",src)
	return src
}

//实现填充函数
func paddingInfo(src []byte,blockSize int) []byte {
	//1、得到明文长度
	length := len(src)

	//2、需要填充的数量
	remains := length % blockSize // 9%8 = 1
	paddingNum := blockSize-remains //8-1=填充7个需要
	fmt.Println(length,"-",blockSize)
	fmt.Printf("remains=%d,paddingnum=%d",remains,paddingNum)

	//3、将填充的数字转换为字符
	s1 := byte(paddingNum)
	fmt.Printf("s1 : %x\n", s1)

	//4、把字符拼接为数组
	s2 := bytes.Repeat([]byte{s1},paddingNum) //[]byte{0x35, '5', '5', '5, '5'}
	fmt.Printf("s2 : %x\n", s2)

	//5、把拼成的数组追加到src后面
	srcNew := append(src,s2...) //切片被打散传入 见bolg案例

	//6、返回新数组
	return srcNew
}

//解密函数
func desCBCDecrypt(cipherData,key []byte) []byte{
	fmt.Printf("解密开始,输入的数据为:%x\n", cipherData)
	//1. 创建并返回一个使用DES算法的cipher.Block接口。
	block, err := des.NewCipher(key)
	fmt.Printf("block size : %d\n", block.BlockSize())

	if err != nil{
		panic(err)
	}

	//引入CBC分组模式
	iv := bytes.Repeat([]byte("1"),block.BlockSize())
	blockMode := cipher.NewCBCDecrypter(block,iv)

	//解密操作
	blockMode.CryptBlocks(cipherData /*解密后的明文*/ , cipherData /*密文*/)

	fmt.Printf("没有去除填充的解密数据为%s\n", cipherData)

	//将数据的结尾填充去掉
	resultData := uppaddingInfo(cipherData)

	return resultData
}

//去除填充
func uppaddingInfo(plainText []byte) []byte {
	//1、获取长度
	length := len(plainText)
	if length == 0{
		return []byte{}
	}
	//2、获取最后一个字符
	last := plainText[length-1]
	//3、将字符转换为数字
	lastone := int(last)
	//4、切片获取需要的数据
	result := plainText[:length-lastone]
	return result
}

func main()  {
	//src := []byte("123456781")
	src := []byte("世界你好")
	key := []byte("12345678")
	jmData := desCBCEncrypt(src,key)

	//解密
	result := desCBCDecrypt(jmData,key)
	fmt.Printf("解密结束,数据为%s\n", result)
}