加密之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
}