区块链100篇之对称加密

版权声明: https://blog.csdn.net/weixin_37504041/article/details/90583922

对称加密

对称加密是比较好理解的,将一个密钥通过加密算法对明文进行运算得到一个密文,使用同样的密钥作为解密算法的输入对密文进行解密即可得到原文,如下图所示:
在这里插入图片描述
从这里我们可以看出对称加密有几个要素,分别是明文、加密算法、密钥、密文以及解密算法,明文即原始数据,密钥与明文一起作为加密算法的输入,是将明文进行打乱的规则,当然它也是跟密文一起作为解密算法的输入。密文自然就是加密算法得到的结果,这些都好理解,这里重点是讲加解密算法及模式。

分类

对称加密可以分为流加密分组加密,流加密即是每次都对数据流中的一个bit或者byte进行加密,加密的过程明文称为明文流,密钥流由密钥流生成器生成,通过加密算法使用密钥流对明文流进行加密得到密文流;流加密比较典型的算法有RC4。

分组加密(通常也成为块加密)是将明文进行分组,加密算法对每个分组分别加密,通常明文分组和加密后得到的密文分组等长。

分组加密

因为分组加密比较常用,所以这里就不介绍流加密了,分组密码常用的有DES、3DES以及AES,分组大小常用的是64bit(8字节)和128bit(16字节),如DES就是使用64bit的分组大小来加密的(其实实际上是56bit,因为DES每隔7bit就会设置一个检查错误的bit),DES的加密过程如下图所示:
在这里插入图片描述
3DES算法很好理解,就是3次DES加解密的组合;AES算法的分组长度是128bit,是目前比较推荐使用的对称加密算法,加解密过程跟DES差不多,就是把64bit改为128bit。

分组密码模式

分组密码的加密模式大致上有ECB、CBC、OFB以及CFB,这里只讲ECB与CBC模式。

ECB模式

在这里插入图片描述
从上图可以看出ECB模式下所有的分组都是并行执行,互不干扰,所以如果有一组加密失败了也不会影响其他分组的加密,这便是ECB模式的优点,但也正是分组之间相互不影响,所以如果增加、删除一个分组或者对几个分组进行重组 ,解密过程还是会正常执行,这就导致了解密出的明文与一开始发送的原文不一致,会干扰接受者对明文的理解;除此之外相同明文会得到相同的密文,导致攻击者可以以此为线索进行破译。

CBC模式

CBC模式就是将明文分组与前一个密文分组进行XOR(按位异或)运算,也就是说下一个明文分组的加密要依赖于前一个密文分组,一组扣一组,所以这种模式也被称为链模式。这种模式下即使是相同的明文也不一定计算出相同的密文,这就弥补了ECB模式的缺点。CBC模式的加密过程如下:
在这里插入图片描述
当然CBC模式也是有缺点的,比如需要引入初始化向量(这个向量的长度与明文分组的长度一致),还有就是它是串行计算,执行效率自然要比ECB模式低,关于CBC的更多细节可以参考这篇文章《CBC模式解读》。

代码操作

下面使用Go语言来对对称加密中的CBC模式(DES算法为例)进行代码演示,为了代码简短有点其中返回的err不进行处理,直接使用"_"来代替。

package main

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

func main() {
   var key = "12345678"
   var info = "Hello World!"

   Enc_str := EncryptDES_CBC(info, key)
   fmt.Println(Enc_str)
   Dec_str := DecryptDES_CBC(Enc_str, key)
   fmt.Println(Dec_str)
}

//CBC加密
func EncryptDES_CBC(src, key string) string {
   data := []byte(src)
   keyByte := []byte(key)
   // 创建并返回一个使用DES算法的cipher.Block接口
   block, _ := des.NewCipher(keyByte)
   // 对最后一个明文分组进行字节填充
   data = PKCS5Padding(data, block.BlockSize())
   //暂时使用密钥作为向量(不建议这样使用),初始向量的长度与明文的长度一致,DES与3DES是字节,而AES一般是16字节
   iv := keyByte 
   //获取CBC加密模式
   mode := cipher.NewCBCEncrypter(block, iv)
   // 创建一个切片,加密后的数据就写到这个切片中形成一个块
   out := make([]byte, len(data))
   mode.CryptBlocks(out, data)
   return fmt.Sprintf("%X", out)
}

//CBC解密
func DecryptDES_CBC(src, key string) string {
   keyByte := []byte(key)
   data, _ := hex.DecodeString(src)
   block, _ := des.NewCipher(keyByte)
   iv := keyByte 
   mode := cipher.NewCBCDecrypter(block, iv)
   plaintext := make([]byte, len(data))
   mode.CryptBlocks(plaintext, data)
   plaintext = PKCS5UnPadding(plaintext)
   return string(plaintext)
}

//明文填充算法,因为最后一个明文分组如果不够字节需要进行填充,DES与3DES需填充满8字节,而AES需填充满16字节
func PKCS5Padding(ciphertext []byte, blockSize int) []byte {
   padding := blockSize - len(ciphertext)%blockSize
   padtext := bytes.Repeat([]byte{byte(padding)}, padding)
   return append(ciphertext, padtext...)
}

//明文减码算法,与加密相反,解密过程中需要将填充上去的字节去掉
func PKCS5UnPadding(origData []byte) []byte {
   length := len(origData)
   unpadding := int(origData[length-1])
   return origData[:(length - unpadding)]
}

Output:

C37551BB77F741D0B7C3165F4391A0BB
Hello World!

3DES算法只需把des.NewCipher改为des.NewTripleDESCipher即可,而AES算法需引入crypto/aes包,并将des.NewCipher改为aes.NewCipher即可,代码思路都一样,关于API描述可参看《Go语言中文网》。关于对称加密的知识就暂时讲到这里。

猜你喜欢

转载自blog.csdn.net/weixin_37504041/article/details/90583922