AES-CBC加密与解密

2,123 阅读3分钟
1.原理:
  • 加密:

  • 解密:与加密过程相反 在CBC模式中,每个平文块先与前一个密文块进行异或后,再进行加密。在这种方法中,每个密文块都依赖于它前面的所有平文块。同时,为了保证每条消息的唯一性,在第一个块中需要使用初始化向量IV。

  • 串行加密,并行解密

    CBC是最为常用的工作模式。它的主要缺点在于加密过程是串行的,无法被并行化,而且消息必须被填充到块大小的整数倍。解决后一个问题的一种方法是利用密文窃取。

    密文窃取:

    1. CBC-CS1:最末两个块做挪动和特殊处理。当最末分组完整时,等价于CBC。
    2. CBC-CS2:当最末分组不完整时,把CBC-CS1的最末两个块交换位置;否则,保持CBC-CS1处理结果。
    3. CBC-CS3:无条件将CBC-CS1的最末两个块交换位置。

    注意在加密时,平文中的微小改变会导致其后的全部密文块发生改变,而在解密时,从两个邻接的密文块中即可得到一个平文块。因此,解密过程可以被并行化,而解密时,密文中一位的改变只会导致其对应的平文块完全改变和下一个平文块中对应位发生改变,不会影响到其它平文的内容。
    2.example

    type user struct {
       Username      string    `json:"username"`
       Password      string    `json:"password"`
       PhoneNumber   string    `json:"phoneNumber"`
    }
    
    func main(){
       u := user{Username: "Bob",Password: "123456",PhoneNumber: "13803456712"}
       //加密
       key := []byte("123223")
       uByte,err :=aesCbcEncrypt(&u,key)
       if err != nil{
          fmt.Println("encrypt ocurr error",err.Error())
       }
       fmt.Println("Encrypt data:",uByte)
       //解密
       res,err1 :=aesCbcDncrypt(uByte,key)
       if err1 != nil{
          fmt.Println("dncrypt ocurr error",err.Error())
       }
       fmt.Println("Dncrypt data:",res)
    }
    //填充
    func pKCS7Padding(ciphertext []byte, blockSize int) []byte {
       padding := blockSize - len(ciphertext) % blockSize
       padtext := bytes.Repeat([]byte{byte(padding)}, padding)
       return append(ciphertext, padtext...)
    }
    
    //解填充
    func pKCS7UnPadding2(origData []byte) ([]byte, bool) {
       length := len(origData)
       unpadding := int(origData[length-1])
       diff := length - unpadding
       if diff < 0 {
          return nil, false
       }
       if math.Abs(float64(diff)) > float64(length) {
          return nil, false
       }
       return origData[:(length - unpadding)], true
    }
    //加密AES-128,AES-196,AES-256对应16,24,32
    func aesCbcEncrypt(u *user,key []byte)([]byte,error) {
       key = pKCS7Padding(key,aes.BlockSize)
    
       uByte,err := json.Marshal(u)
       //扩充用户数据
       uByte = pKCS7Padding(uByte,aes.BlockSize)
       if err != nil{
          fmt.Println("occur a error",err.Error())
       }
       ciphertext := make([]byte, aes.BlockSize+len(uByte))
       block,err1 := aes.NewCipher(key)
       if err1 != nil{
          fmt.Println("occur a error",err1.Error())
          return nil,err
       }
       iv := ciphertext[:aes.BlockSize]
       mode := cipher.NewCBCEncrypter(block,iv)
       mode.CryptBlocks(uByte,uByte)
       return uByte,nil
    }
    //解密
    func aesCbcDncrypt(uByte []byte,key []byte)(interface{},error){
       key = pKCS7Padding(key,aes.BlockSize)
       block,err1 := aes.NewCipher(key)
       if err1 != nil{
          fmt.Println("occur a error",err1.Error())
          return nil,err1
       }
    
       blockSize := block.BlockSize()
    
       ciphertext := make([]byte, aes.BlockSize+len(uByte))
       iv1 := ciphertext[:aes.BlockSize]
    
       if len(uByte)%blockSize != 0 {
          fmt.Println("encrypt data is not multi blocksize!")
          return nil, errors.New("encrypt data is not multi blocksize!")
       }
    
       mode1 := cipher.NewCBCDecrypter(block, iv1)
       origData := make([]byte, len(uByte))
    
       mode1.CryptBlocks(uByte, uByte)
       //解填充
       origData,isOk := pKCS7UnPadding2(uByte)
       if !isOk{
          fmt.Printf("Dencrypt fail,pk7 error,data,%s\n",uByte)
          return nil,errors.New("Dencrypt fail,pk7 error")
       }
       var result = struct {
          Username      string    `json:"username"`
          Password      string    `json:"password"`
          PhoneNumber   string    `json:"phoneNumber"`
       }{}
    
       err2 :=json.Unmarshal(origData,&result)
       if err2 != nil{
          fmt.Println("occur error",err2.Error())
          return nil,err2
       }
       return result,nil
    }
    

    运行结果:

    Encrypt data: [76 32 97 14 99 152 40 111 32 206 124 54 162 128 93 91 171 55 164 175 175 201 156 116 40 8 199 107 50 195 162 126 41 238 180 55 47 210 20 2 19 155 195 97 181 199 201 155 117 21 17 164 148 54 3 22 51 107 45 13 24 213 90 229 244 151 13 136 27 85 80 49 79 252 34 113 82 246 153 213]
    Dncrypt data: {Bob 123456 13803456712}