227-加密之DES加密CBC模式






加密之DES加密CBC模式



我们来试试通过DES算法加密
配合的是CBC分组模式



我们先把基本的三个步骤和方法写出来
1.明文
2.加密
3.密文



func main() {

	text := "你好!世界! hello world"
	key := "abcabc123123"
	iv := "iviviv123123"

	cipherText := EncryptByDESAndCBC(text)

	fmt.Println(cipherText)
}

func EncryptByDESAndCBC(text string) string {
	var cipherText string

	//加密

	return cipherText
}


text是明文
key是秘钥
iv是我们用CBC模式要用到的initial vector初始向量

然后我们在EncryptByDESAndCBC这个方法中
实现一下DES配合CBC加密


func main() {

	text := "你好!世界! hello world"
	key := "abcabc123123"
	iv := "iviviv123123"

	cipherText := EncryptByDESAndCBC(text, key, iv)

	fmt.Println(cipherText)
}

func EncryptByDESAndCBC(text string, key string, iv string) string {
	textBytes := []byte(text)
	keyBytes := []byte(key)
	ivBytes := []byte(iv)

	var cipherText string

	//加密
	//1. 创建并返回一个使用DES算法的cipher.Block接口
	//使用des调用NewCipher获取block接口
	block, err := des.NewCipher(keyBytes)
	if err != nil {
		panic(err)
	}

	//2. 创建CBC分组模式
	//使用cipher调用NewCBCDecrypter获取blockMode接口
	blockMode := cipher.NewCBCDecrypter(block, ivBytes)

	//3. 加密
	//这里的两个参数为什么都是textBytes
	//第一个是目标,第二个是源
	//也就是说将第二个进行加密,然后放到第一个里面
	//如果我们重新定义一个密文cipherTextBytes
	//那么就是blockMode.CryptBlocks(cipherTextBytes, textBytes)
	blockMode.CryptBlocks(textBytes, textBytes)

	cipherText = string(textBytes)

	return cipherText
}





我们运行一下
发现报错了
看一下
panic: crypto/des: invalid key size 12
说我们的key的size是不对的
我们看一下源码
// NewCipher creates and returns a new cipher.Block.
func NewCipher(key []byte) (cipher.Block, error) {
	if len(key) != 8 {
		return nil, KeySizeError(len(key))
	}

	c := new(desCipher)
	c.generateSubkeys(key)
	return c, nil
}

我们看到
如果key的长度不是8
那么就会报错

所以我们改一下
key := "abcabc12"



我们再运行一下
又报错了
看一下
panic: cipher.NewCBCDecrypter: IV length must equal block size
说IV的长度必须和块的长度一致
ok
我们查看一下des的块长度
我们看一下des的源码
发现
// The DES block size in bytes.
const BlockSize = 8

这里已经将BlockSize块长度设为8个字节
是常量
不能修改
所以我们修改一下IV的长度
iv := "iviviv12"





然后我们再运行一下
又又又报错了
我们看一下
panic: crypto/cipher: input not full blocks
说我们输入的块,没有满
我们来看一下源码

func TestCryptBlocks(t *testing.T) {
	buf := make([]byte, 16)
	block, _ := aes.NewCipher(buf)

	mode := cipher.NewCBCDecrypter(block, buf)
	mustPanic(t, "crypto/cipher: input not full blocks", func() { mode.CryptBlocks(buf, buf[:3]) })
	mustPanic(t, "crypto/cipher: output smaller than input", func() { mode.CryptBlocks(buf[:3], buf) })

	mode = cipher.NewCBCEncrypter(block, buf)
	mustPanic(t, "crypto/cipher: input not full blocks", func() { mode.CryptBlocks(buf, buf[:3]) })
	mustPanic(t, "crypto/cipher: output smaller than input", func() { mode.CryptBlocks(buf[:3], buf) })
}


我们再看CryptBlocks方法

func (x *cbcEncrypter) CryptBlocks(dst, src []byte) {
	if len(src)%x.blockSize != 0 {
		panic("crypto/cipher: input not full blocks")
	}


我们发现如果取余blockSize不为0
就会报错



那么我们需要把我们的明文text进行补齐

我们来写一个方法

func MakeBlocksFull(src []byte, blockSize int) []byte {

	//1. 获取src的长度, blockSize对于des是8
	length := len(src)

	//2. 对blockSize进行取余数, 4
	remains := length % blockSize

	//3. 获取要填的数量 = blockSize - 余数
	paddingNumber := blockSize - remains //4

	//4. 将填充的数字转换成字符, 4, '4', 创建了只有一个字符的切片
	//s1 = []byte{'4'}
	s1 := []byte{byte(paddingNumber)}

	//5. 创造一个有4个'4'的切片
	//s2 = []byte{'4', '4', '4', '4'}
	s2 := bytes.Repeat(s1, paddingNumber)

	//6. 将填充的切片追加到src后面
	s3 := append(src, s2...)

	return s3
}



func EncryptByDESAndCBC(text string, key string, iv string) string {
	textBytes := []byte(text)
	keyBytes := []byte(key)
	ivBytes := []byte(iv)

	textBytes = MakeBlocksFull(textBytes, 8)





然后我们运行一下
成功了
得到的密文是
�9���Č��K�*n~AՄ�Ț��&��t








然后我们试一下把这个密文解密一下

func MakeBlocksOrigin(src []byte) []byte {

	//1. 获取src长度
	length := len(src)

	//2. 得到最后一个字符
	lastChar := src[length-1] //'4'

	//3. 将字符转换为数字
	number := int(lastChar) //4

	//4. 截取需要的长度
	return src[:length-number]
}

func DecryptByDESAndCBC(cipherText []byte, key, iv string) string {

	textBytes := cipherText
	keyBytes := []byte(key)
	ivBytes := []byte(iv)

	//1. 创建并返回一个使用DES算法的cipher.Block接口。
	block, err := des.NewCipher(keyBytes)
	if err != nil {
		panic(err)
	}

	//2. 创建CBC分组模式
	blockMode := cipher.NewCBCDecrypter(block, ivBytes)

	//3. 解密
	blockMode.CryptBlocks(textBytes, textBytes)

	//4. 去掉填充数据 (注意去掉填充的顺序是在解密之后)
	plainText := MakeBlocksOrigin(textBytes)

	return string(plainText)
}







最后我们看一下完整代码


func main() {

	text := "你好!世界! hello world"
	key := "abcabc12"
	iv := "iviviv12"

	cipherTextBytes := EncryptByDESAndCBC(text, key, iv)
	fmt.Println(cipherTextBytes)

	newText := DecryptByDESAndCBC(cipherTextBytes, key, iv)
	fmt.Println(newText)

}

func DecryptByDESAndCBC(cipherText []byte, key, iv string) string {

	textBytes := cipherText
	keyBytes := []byte(key)
	ivBytes := []byte(iv)

	//1. 创建并返回一个使用DES算法的cipher.Block接口。
	block, err := des.NewCipher(keyBytes)
	if err != nil {
		panic(err)
	}

	//2. 创建CBC分组模式
	blockMode := cipher.NewCBCDecrypter(block, ivBytes)

	//3. 解密
	blockMode.CryptBlocks(textBytes, textBytes)

	//4. 去掉填充数据 (注意去掉填充的顺序是在解密之后)
	plainText := MakeBlocksOrigin(textBytes)

	return string(plainText)
}

func EncryptByDESAndCBC(text string, key string, iv string) []byte {

	textBytes := []byte(text)
	keyBytes := []byte(key)
	ivBytes := []byte(iv)

	//加密
	//1. 创建并返回一个使用DES算法的cipher.Block接口
	//使用des调用NewCipher获取block接口
	block, err := des.NewCipher(keyBytes)
	if err != nil {
		panic(err)
	}

	//2. 填充数据,将输入的明文构造成8的倍数
	textBytes = MakeBlocksFull(textBytes, 8)

	//3. 创建CBC分组模式,返回一个密码分组链接模式的、底层用b加密的BlockMode接口,初始向量iv的长度必须等于b的块尺寸
	//使用cipher调用NewCBCDecrypter获取blockMode接口
	blockMode := cipher.NewCBCEncrypter(block, ivBytes)

	//3. 加密
	//这里的两个参数为什么都是textBytes
	//第一个是目标,第二个是源
	//也就是说将第二个进行加密,然后放到第一个里面
	//如果我们重新定义一个密文cipherTextBytes
	//那么就是blockMode.CryptBlocks(cipherTextBytes, textBytes)
	blockMode.CryptBlocks(textBytes, textBytes)

	return textBytes

}

func MakeBlocksOrigin(src []byte) []byte {

	//1. 获取src长度
	length := len(src)

	//2. 得到最后一个字符
	lastChar := src[length-1] //'4'

	//3. 将字符转换为数字
	number := int(lastChar) //4

	//4. 截取需要的长度
	return src[:length-number]
}

func MakeBlocksFull(src []byte, blockSize int) []byte {

	//1. 获取src的长度, blockSize对于des是8
	length := len(src)

	//2. 对blockSize进行取余数, 4
	remains := length % blockSize

	//3. 获取要填的数量 = blockSize - 余数
	paddingNumber := blockSize - remains //4

	//4. 将填充的数字转换成字符, 4, '4', 创建了只有一个字符的切片
	//s1 = []byte{'4'}
	s1 := []byte{byte(paddingNumber)}

	//5. 创造一个有4个'4'的切片
	//s2 = []byte{'4', '4', '4', '4'}
	s2 := bytes.Repeat(s1, paddingNumber)

	//6. 将填充的切片追加到src后面
	s3 := append(src, s2...)

	return s3
}







 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值