對稱加密算法AES原理及實現

AES是作為DES的替代標準出現的,全稱Advanced Encryption Standard,即:高級加密標準。AES加密算法,經歷了公開的選拔,最終2000年,由比利時密碼學家Joan Daemen和Vincent Rijmen設計的Rijndael算法被選中,成為了AES標準。
  AES明文分組長度為128位,即16個字節,密鑰長度可以為16個字節、24個字節、或32個字節,即128位密鑰、192位密鑰、或256位密鑰。

總體結構

AES中沒有使用Feistel網絡,其結構稱為SPN結構。
  
  和DES相同,AES也由多個輪組成,其中每個輪分為SubBytes、ShiftRows、MixColumns、AddRoundKey 4個步驟,即:字節代替、行移位、列混淆和輪密鑰加。根據密鑰長度不同,所需輪數也不同,128位、192位、256位密鑰,分別需要10輪、12輪和14輪。第1輪之前有一次AddRoundKey,即輪密鑰加,可以視為第0輪;之后1至N-1輪,執行SubBytes、ShiftRows、MixColumns、AddRoundKey;最后一輪僅包括:SubBytes、MixColumns、AddRoundKey。
  
AES總體結構示意圖:
  


結構示意圖

分組密碼

密碼算法可以分為分組密碼和流密碼兩種

  • 分組密碼(block cipher)是每次只能處理特定長度的一塊數據的一類密碼算法,這里的“一塊”就稱為分組(block)。一個分組的比特數就稱為分組長度(block lenght)。

    例如 DES和3DES的分組長度都是64比特。AES的分組長度為128比特。

  • 流密碼(stream cipher)是對數據流進行連續處理的一類密碼算法。流密碼中一般以1比特、8比特、或32比特等為單位進行加密和解密。

分組密碼處理完一個分組就結束了,因此不需要通過內部狀態來記錄加密的進度;相對地,流密碼是對一串數據進行連續處理,因此需要保持內部狀態。

模式

分組密碼算法只能加密固定長度的分組,但是我們需要加密的明文長度可能會超過分組密碼的分組長度,這時就需要對分組密碼算法進行迭代,以便將一段很長的明文全部加密。而迭代的方法就稱為分組密碼的模式(mode)。

  • ECB模式:Electronic CodeBook mode(電子密碼模式)
  • CBC模式:Cipher Block Chaining mode(密碼分組鏈接模式)
  • CFB模式:Cipher FeedBack mode(密文反饋模式)
  • OFB模式:Output FeedBack mode(輸出反饋模式)
  • CTR模式:CounTeR mode(計數器模式)

ECB模式存在很高的風險,下面舉例后面4中模式的使用.
加密的過程中使用了隨機流,所以每次加密的密文都不一樣

CBC模式

func main() {


    key := "1234567890asdfgh"
    data := "hollo, world!"

    cry := AesCBCEncrypt([]byte(data), []byte(key))
    fmt.Println(hex.EncodeToString(cry))

    oriData := AESCBCDECriypt(cry, []byte(key))
    fmt.Println(string(oriData))

}
// AES也是對稱加密 AES 是 DES 的替代品
// AES 密鑰長度 只能是 16、24、32 字節
//加密
func AesCBCEncrypt(org []byte, key []byte) []byte  {

    //校驗密鑰
    block,_ := aes.NewCipher(key)

    //按照公鑰長度 進行分組補碼
    org = PKCS7Padding(org, block.BlockSize())

    //設置CBC的加密模式
    blockMode := cipher.NewCBCEncrypter(block, key)

    //加密處理
    crypted := make([]byte, len(org))
    blockMode.CryptBlocks(crypted, org)

    return crypted
}

//解密
func AESCBCDECriypt(criptText []byte, key []byte) []byte  {

    //校驗key的有效性
    block,_:=aes.NewCipher(key)
    //通過CBC模式解密
    blockMode:=cipher.NewCBCDecrypter(block,key)

    //實現解密
    origData:=make([]byte,len(criptText))
    blockMode.CryptBlocks(origData,criptText)

    //去碼
    origData = PKCS7UnPadding(origData)
    return origData
}





//PKCS5 分組長度只能為8
//PKCs7 分組長度 1- 255

func PKCS7Padding(org []byte, blockSize int) []byte  {

    pad := blockSize-len(org)%blockSize
    padArr := bytes.Repeat([]byte{byte(pad)}, pad)
    return  append(org, padArr...)

}

func PKCS7UnPadding(cryptText []byte) []byte  {
    
    length := len(cryptText)
    lastByte := cryptText[length - 1]
    return cryptText[:length-int(lastByte)]
    
}

輸出

ffa22c136fd3e944255d43e255c98ecc
hollo, world!

CFB模式

func main()  {


    key := []byte("1234567890asdfgh")
    data := []byte("abc hello world!")
    cry := AESCFBEncrypt(data, key)

    fmt.Println(hex.EncodeToString(cry))
    //fmt.Println(base64.StdEncoding.EncodeToString(cry))

    ori := AESCFBDecrypt(cry, key)
    fmt.Println(string(ori))

}

//CFB分組模式加密
func AESCFBEncrypt(oriData []byte, key []byte) []byte  {

    //校驗密鑰
    block,_ := aes.NewCipher(key)

    //拆分iv和密文
    cipherText := make([]byte, aes.BlockSize + len(oriData))

    iv := cipherText[:aes.BlockSize]

    //向iv切片數組初始化 reader(隨機內存流)
    io.ReadFull(rand.Reader, iv)

    //設置加密模式CFB
    stream := cipher.NewCFBEncrypter(block,iv)

    //加密
    stream.XORKeyStream(cipherText[aes.BlockSize:], oriData)

    return  cipherText


}

//解密
func AESCFBDecrypt(cryptText []byte, key []byte) []byte {

    //校驗密鑰
    block,_ := aes.NewCipher(key)

    //拆分iv 和密文
    iv := cryptText[:aes.BlockSize]
    cipherText := cryptText[aes.BlockSize:]


    //設置解密模式
    stream := cipher.NewCFBDecrypter(block, iv)

    var des = make([]byte, len(cipherText))

    //解密
    stream.XORKeyStream(des, cipherText)

    return des
}

輸出

92e5c5d7bc54b337a7edbb548ee1a62c8c3c079b71f465a3f0566c0d74b8d513
abc hello world!

OFB模式

func main()  {

    key := []byte("1234567890asdfgh")
    data := []byte("abcd hello world!")
    cry := AESOFBEncrypt(data, key)

    fmt.Println(hex.EncodeToString(cry))

    ori := AESOFBDecrypt(cry, key)
    fmt.Println(string(ori))
}

//AES OFB分組加密模式  CTR也是一樣
func AESOFBEncrypt(plaintxt []byte, key []byte) []byte  {

    //校驗密鑰
    block,_ := aes.NewCipher(key)

    cipherText := make([]byte, aes.BlockSize + len(plaintxt))

    iv := cipherText[:aes.BlockSize]

    //向iv切片數組初始化 reader(隨機內存流)
    io.ReadFull(rand.Reader, iv)

    //設置加密模式CFB
    stream := cipher.NewOFB(block,iv)

    //加密
    stream.XORKeyStream(cipherText[aes.BlockSize:], plaintxt)

    return  cipherText

}


//解密
func AESOFBDecrypt(cryptText []byte, key []byte) []byte {

    //校驗密鑰
    block,_ := aes.NewCipher(key)

    //拆分iv 和 密文
    iv := cryptText[:aes.BlockSize]
    plaintxt := make([]byte, len(cryptText)-aes.BlockSize)


    //設置解密模式
    stream := cipher.NewOFB(block, iv)

    //解密
    stream.XORKeyStream(plaintxt, cryptText[aes.BlockSize:])

    return plaintxt
}

輸出

9ee409f8513e3fcba2f1ba726da0b2a5d80251efa073544220b44c8e8fee18fce4
abcd hello world!

CTR模式

func main()  {

    key := []byte("1234567890asdfgh")
    data := []byte("abcd hello world!")
    cry := AESCTREncrypt(data, key)

    fmt.Println(hex.EncodeToString(cry))

    ori := AESCTRDecrypt(cry, key)
    fmt.Println(string(ori))
}

//AES CTR分組加密模式
func AESCTREncrypt(plaintxt []byte, key []byte) []byte  {

    //校驗密鑰
    block,_ := aes.NewCipher(key)

    cipherText := make([]byte, aes.BlockSize + len(plaintxt))

    iv := cipherText[:aes.BlockSize]

    //向iv切片數組初始化 reader(隨機內存流)
    io.ReadFull(rand.Reader, iv)

    //設置加密模式CTR
    stream := cipher.NewCTR(block,iv)

    //加密
    stream.XORKeyStream(cipherText[aes.BlockSize:], plaintxt)

    return  cipherText

}


//解密
func AESCTRDecrypt(cryptText []byte, key []byte) []byte {

    //校驗密鑰
    block,_ := aes.NewCipher(key)

    //拆分iv 和 密文
    iv := cryptText[:aes.BlockSize]
    plaintxt := make([]byte, len(cryptText)-aes.BlockSize)


    //設置解密模式
    stream := cipher.NewCTR(block, iv)

    //解密
    stream.XORKeyStream(plaintxt, cryptText[aes.BlockSize:])

    return plaintxt
}

輸出

c645da2d14896d2b75d41a538a5a3efe3c7721f51f2eb2e92b0c5b8ba141caf534
abcd hello world!
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 目錄一、對稱加密?1、對稱加密是什么?2、對稱加密的優點?3、對稱加密的問題?4、對稱加密的應用場景?5、對稱加密...
    意一ineyee閱讀 62,134評論 8 110
  • 這篇文章主要講述在Mobile BI(移動商務智能)開發過程中,在網絡通信、數據存儲、登錄驗證這幾個方面涉及的加密...
    雨_樹閱讀 2,701評論 0 6
  • 本文主要介紹移動端的加解密算法的分類、其優缺點特性及應用,幫助讀者由淺入深地了解和選擇加解密算法。文中會包含算法的...
    蘋果粉閱讀 11,586評論 5 29
  • 概述 之前一直對加密相關的算法知之甚少,只知道類似DES、RSA等加密算法能對數據傳輸進行加密,且各種加密算法各有...
    Henryzhu閱讀 3,055評論 0 14
  • 對稱加密算法,即加密和解密使用一樣的密鑰的加解密算法。分組密碼(block cipher),是每次只能處理特定長度...
    linjinhe閱讀 12,017評論 3 16