DES加密常用的概念
- 加密模式
- ECB模式 全稱Electronic Codebook模式,譯為電子密碼本模式
- CBC模式 全稱Cipher Block Chaining模式,譯為密文分組連結模式
- CFB模式 全稱Cipher FeedBack模式,譯為密文回報模式
- OFB模式 全稱Output Feedback模式,譯為輸出回報模式。
- CTR模式 全稱Counter模式,譯為計數器模式。
-
初始向量
當加密第一個明文分組時,由于不存在 “前一個密文分組”,是以需要事先準備一個長度為一個分組的比特序列來代替 “前一個密文分組”,這個比特序列稱為初始化向量(InitializationVector),通常縮寫為 IV。
-
填充方式
當明文長度不為分組長度的整數倍時,需要在最後一個分組中填充一些資料使其湊滿一個分組長度。
-
NoPadding
API或算法本身不對資料進行處理,加密資料由加密雙方約定填補算法。例如若對字元串資料進行加解密,可以補充\0或者空格,然後trim
-
PKCS5Padding
加密前:資料位元組長度對8取餘,餘數為m,若m>0,則補足8-m個位元組,位元組數值為8-m,即差幾個位元組就補幾個位元組,位元組數值即為補充的位元組數,若為0則補充8個位元組的8
解密後:取最後一個位元組,值為m,則從資料尾部删除m個位元組,剩餘資料即為加密前的原文。
加密字元串為為AAA,則補位為AAA55555;加密字元串為BBBBBB,則補位為BBBBBB22;加密字元串為CCCCCCCC,則補位為CCCCCCCC88888888。
-
PKCS7Padding
PKCS7Padding 的填充方式和PKCS5Padding 填充方式一樣。隻是加密塊的位元組數不同。PKCS5Padding明确定義了加密塊是8位元組,PKCS7Padding加密快可以是1-255之間。
-
實作 DES 加密和解密
采用3DES、CBC模式、pkcs5padding,初始向量用key充當;另外,對于zero padding,還得約定好,對于資料長度剛好是block size的整數倍時,是否需要額外填充。
crypto/des包
Go中crypto/des包實作了 Data Encryption Standard (DES) and the Triple Data Encryption Algorithm (TDEA)。檢視該封包檔,發現相當簡單:定義了DES塊大小(8bytes),定義了一個KeySizeError。另外定義了兩個我們需要特别關注的函數,即
func NewCipher(key []byte) (cipher.Block, error)
func NewTripleDESCipher(key []byte) (cipher.Block, error)
他們都是用來獲得一個cipher.Block。從名字可以很容易知道,DES使用NewCipher,3DES使用NewTripleDESCipher。參數都是密鑰(key)
加密
使用DES加密
(des.NewCipher)
,加密模式為CBC
(cipher.NewCBCEncrypter(block, key))
,填充方式
PKCS5Padding
func DesEncrypt(origData, key []byte) ([]byte, error) {
block, err := des.NewCipher(key)
if err != nil {
return nil, err
}
origData = PKCS5Padding(origData, block.BlockSize())
blockMode := cipher.NewCBCEncrypter(block, key)
crypted := make([]byte, len(origData))
blockMode.CryptBlocks(crypted, origData)
return crypted, nil
}
解密
func DesDecrypt(crypted, key []byte) ([]byte, error) {
block, err := des.NewCipher(key)
if err != nil {
return nil, err
}
blockMode := cipher.NewCBCDecrypter(block, key)
origData := make([]byte, len(crypted))
blockMode.CryptBlocks(origData, crypted)
origData = PKCS5UnPadding(origData)
return origData, nil
}
des加密的詳細代碼
package main
import (
"bytes"
"crypto/cipher"
"crypto/des"
"encoding/base64"
"fmt"
)
func main() {
key := []byte("12345678")
result, err := DesEncrypt([]byte("hello world"), key)
if err != nil {
panic(err)
}
fmt.Println(base64.StdEncoding.EncodeToString(result))
origData, err := DesDecrypt(result, key)
if err != nil {
panic(err)
}
fmt.Println(string(origData))
}
func DesEncrypt(origData, key []byte) ([]byte, error) {
block, err := des.NewCipher(key)
if err != nil {
return nil, err
}
origData = PKCS5Padding(origData, block.BlockSize())
blockMode := cipher.NewCBCEncrypter(block, key)
crypted := make([]byte, len(origData))
blockMode.CryptBlocks(crypted, origData)
return crypted, nil
}
func DesDecrypt(crypted, key []byte) ([]byte, error) {
block, err := des.NewCipher(key)
if err != nil {
return nil, err
}
blockMode := cipher.NewCBCDecrypter(block, key)
origData := make([]byte, len(crypted))
blockMode.CryptBlocks(origData, crypted)
origData = PKCS5UnPadding(origData)
return origData, nil
}
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 次
unpadding := int(origData[length])
return origData[:(length - unpadding)]
}
3DES 加密及解密
加密
對比DES,發現隻是換了NewTripleDESCipher。不過,需要注意的是,密鑰長度必須24byte,否則直接傳回錯誤。
func TripleDesEncrypt(origData, key []byte) ([]byte, error) {
block, err := des.NewTripleDESCipher(key)
if err != nil {
return nil, err
}
origData = PKCS5Padding(origData, block.BlockSize())
blockMode := cipher.NewCBCEncrypter(block, key[])
crypted := make([]byte, len(origData))
blockMode.CryptBlocks(crypted, origData)
return crypted, nil
}
主函數
func main() {
// 3DES加解密
key := []byte("123456789012345678901234")
result, err := TripleDesEncrypt([]byte("hello world"), key)
if err != nil {
panic(err)
}
fmt.Println(base64.StdEncoding.EncodeToString(result))
origData, err := TripleDesDecrypt(result, key)
if err != nil {
panic(err)
}
fmt.Println(string(origData))
}
如果我們把主函數中
key
改為25位的
1234567890123456789012345
運作
go run 3des.go
,提示出現如下錯誤:
go rundes.go
panic: crypto/des: invalid key size
goroutine [running]:
詳細代碼
package main
import (
"bytes"
"crypto/cipher"
"crypto/des"
"encoding/base64"
"fmt"
)
func main() {
// 3DES加解密
key := []byte("123456789012345678901234")
result, err := TripleDesEncrypt([]byte("hello world"), key)
if err != nil {
panic(err)
}
fmt.Println(base64.StdEncoding.EncodeToString(result))
origData, err := TripleDesDecrypt(result, key)
if err != nil {
panic(err)
}
fmt.Println(string(origData))
}
// 3DES加密
func TripleDesEncrypt(origData, key []byte) ([]byte, error) {
block, err := des.NewTripleDESCipher(key)
if err != nil {
return nil, err
}
origData = PKCS5Padding(origData, block.BlockSize())
blockMode := cipher.NewCBCEncrypter(block, key[])
crypted := make([]byte, len(origData))
blockMode.CryptBlocks(crypted, origData)
return crypted, nil
}
// 3DES解密
func TripleDesDecrypt(crypted, key []byte) ([]byte, error) {
block, err := des.NewTripleDESCipher(key)
if err != nil {
return nil, err
}
blockMode := cipher.NewCBCDecrypter(block, key[])
origData := make([]byte, len(crypted))
blockMode.CryptBlocks(origData, crypted)
origData = PKCS5UnPadding(origData)
return origData, nil
}
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 次
unpadding := int(origData[length])
return origData[:(length - unpadding)]
}