1. 程式人生 > >Go語言ASE加密解密

Go語言ASE加密解密

基本概念

  • 密碼學中,塊密碼的工作模式(英語:mode of operation)允許使用同一個塊密碼金鑰對多於一塊的資料進行加密,並保證其安全性。
  • 塊密碼自身只能加密長度等於密碼塊長度的單塊資料,若要加密變長資料,則資料必須先被劃分為一些單獨的密碼塊。通常而言,最後一塊資料也需要使用合適填充方式將資料擴充套件到符合密碼塊大小的長度。
  • 一種工作模式描述了加密每一資料塊的過程,並常常使用基於一個通常稱為初始化向量的附加輸入值以進行隨機化,以保證安全。
  • 常見的模式有ECB,CBC,OFB,CFB,CTR和XTS等
  • 加密模式僅僅保證 機密性 ,對於保證 完整性 或未篡改,需要採用分離的訊息驗證碼,例如CBC-MAC。密碼學社群認識到了對專用的保證完整性的方法的需求,NIST因此提出了HMAC,CMAC和GMAC。
  • 在發現將認證模式與加密模式聯合起來的難度之後,密碼學社群開始研究結合了加密和認證的單一模式,這種模式被稱為認證加密模式(AE,Authenticated Encryption),或稱為authenc。AE模式的例子包括CCM,GCM[11],CWC,EAX,IAPM和OCB。

初始化向量(IV)

初始化向量(IV,Initialization Vector)是許多工作模式中用於隨機化加密的一塊資料,因此可以由相同的明文,相同的金鑰產生不同的密文,而無需重新產生金鑰,避免了通常相當複雜的這一過程。

初始化向量與金鑰相比有不同的安全性需求,因此IV通常無須保密,然而在大多數情況中,不應當在使用同一金鑰的情況下兩次使用同一個IV。對於CBC和CFB,重用IV會導致洩露明文首個塊的某些資訊,亦包括兩個不同訊息中相同的字首。對於OFB和CTR而言,重用IV會導致完全失去安全性。另外,在CBC模式中,IV在加密時必須是無法預測的;特別的,在許多實現中使用的產生IV的方法,例如SSL2.0使用的,即採用上一個訊息的最後一塊密文作為下一個訊息的IV,是不安全的。

填充

  • 部分模式(ECB和CBC)需要最後一塊在加密前進行填充
  • CFB,OFB和CTR模式不需要對長度不為密碼塊大小整數倍的訊息進行特別的處理。因為這些模式是通過對塊密碼的輸出與平文進行異或工作的。最後一個平文塊(可能是不完整的)與金鑰流塊的前幾個位元組異或後,產生了與該平文塊大小相同的密文塊。流密碼的這個特性使得它們可以應用在需要密文和平文資料長度嚴格相等的場合,也可以應用在以流形式傳輸資料而不便於進行填充的場合。
  • 舉例兩個填充程式碼
func PKCS5Padding(ciphertext []byte, blockSize int) []byte {
        padding := blockSize - len(ciphertext)%blockSize//需要padding的數目
        //只要少於256就能放到一個byte中,預設的blockSize=16(即採用16*8=128, AES-128長的金鑰)
        //最少填充1個byte,如果原文剛好是blocksize的整數倍,則再填充一個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)]
}

func ZeroPadding(ciphertext []byte, blockSize int) []byte {
        padding := blockSize - len(ciphertext)%blockSize
        padtext := bytes.Repeat([]byte{0}, padding)//用0去填充
        return append(ciphertext, padtext...)
}

func ZeroUnPadding(origData []byte) []byte {
        return bytes.TrimFunc(origData,
                func(r rune) bool {
                        return r == rune(0)
                })
}

常見模式

ECB(Electronic codebook)模式

加密:ecb_encrypt 解密:ecb_decrypt 對每個密碼塊應用祕鑰,缺點在於同樣的平文塊會被加密成相同的密文塊;因此,它不能很好的隱藏資料模式。在某些場合,這種方法不能提供嚴格的資料保密性,因此並不推薦用於密碼協議中。下面的例子顯示了ECB在密文中顯示平文的模式的程度:該影象的一個位圖版本(左圖)通過ECB模式可能會被加密成中圖,而非ECB模式通常會將其加密成下圖ECB2 而且由於每個塊分別加密,用它的協議本身不能提供資料完整性保護,易收到重放攻擊的影響。

CBC(Cipher-block chaining)模式

加密:cbc_encrypt 解密:cbc_decrypt 在CBC模式中,每個平文塊先與前一個密文塊進行異或後,再進行加密。在這種方法中,每個密文塊都依賴於它前面的所有平文塊。同時,為了保證每條訊息的唯一性,在第一個塊中需要使用初始化向量。

CBC是最為常用的工作模式。它的主要缺點在於加密過程是序列的,無法被並行化,而且訊息必須被填充到塊大小的整數倍。解決後一個問題的一種方法是利用密文竊取。

注意在加密時,平文中的微小改變會導致其後的全部密文塊發生改變,而在解密時,從兩個鄰接的密文塊中即可得到一個平文塊。因此,解密過程可以被並行化,而解密時,密文中一位的改變只會導致其對應的平文塊完全改變和下一個平文塊中對應位發生改變,不會影響到其它平文的內容。

程式碼例項:

package main

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

//填充字串(末尾)
func PaddingText1(str []byte, blockSize int) []byte {
	//需要填充的資料長度
	paddingCount := blockSize - len(str)%blockSize
	//填充資料為:paddingCount ,填充的值為:paddingCount
	paddingStr := bytes.Repeat([]byte{byte(paddingCount)}, paddingCount)
	newPaddingStr := append(str, paddingStr...)
	//fmt.Println(newPaddingStr)
	return newPaddingStr
}

//去掉字元(末尾)
func UnPaddingText1(str []byte) []byte {
	n := len(str)
	count := int(str[n-1])
	newPaddingText := str[:n-count]
	return newPaddingText
}
//---------------DES加密  解密--------------------
func EncyptogAES(src, key []byte) []byte {
	block,err:=aes.NewCipher(key)
	if err!= nil{
		fmt.Println(nil)
		return nil
	}
	src=PaddingText1(src,block.BlockSize())
	blockMode:=cipher.NewCBCEncrypter(block,key)
	blockMode.CryptBlocks(src,src)
	return src

}
func DecrptogAES(src,key[]byte) []byte {
	block,err:=aes.NewCipher(key)
	if err!= nil{
		fmt.Println(nil)
		return nil
	}
	blockMode:=cipher.NewCBCDecrypter(block,key)
	blockMode.CryptBlocks(src,src)
	src=UnPaddingText1(src)
	return  src
}

func main() {
	str:="山重水複疑無路,柳暗花明又一村!"
	fmt.Println("編碼的資料為:",str)
	key:=[]byte("12345678abcdefgh")
	src:=EncyptogAES([]byte(str),key)
	DecrptogAES(src,key)
	fmt.Println("解碼之後的資料為:",string(src))
	
}