溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

DES--------Golang對稱加密之模式問題實戰(zhàn)

發(fā)布時間:2020-06-16 15:47:43 來源:網(wǎng)絡(luò) 閱讀:14966 作者:asd1123509133 欄目:編程語言

1. 背景

近期項目在對接第三方產(chǎn)品,傳輸過程中涉及到數(shù)據(jù)加密, 數(shù)據(jù)加密流程為:

  • 發(fā)送數(shù)據(jù)DES加密
  • DES加密后的數(shù)據(jù)進(jìn)行base64編碼
  • 發(fā)送,接受數(shù)據(jù)
  • 接受讀取的數(shù)據(jù)進(jìn)行base64解碼
  • base64解碼完的數(shù)據(jù)機(jī)型DES解密

    由于采用golang對接,文檔且無說明情況下,默認(rèn)采用CBC模式加解密,導(dǎo)致很長時間對接不上。
    后通過對方Java Demo代碼查看得知采用ECB加密模式,Java默認(rèn)DES算法使用DES/ECB/PKCS5Padding工作方式,在GO語言中因為ECB的脆弱性,DES的ECB模式是故意不放出來的,但實際情況中有時我們并不需要那么安全。

DES介紹

DES 使用一個 56 位的密鑰以及附加的 8 位奇偶校驗位,產(chǎn)生最大 64 位的分組大小。這是一個迭代的分組密碼,使用稱為 Feistel 的技術(shù),其中將加密的文本塊分成兩半。使用子密鑰對其中一半應(yīng)用循環(huán)功能,然后將輸出與另一半進(jìn)行"異或"運算;接著交換這兩半,這一過程會繼續(xù)下去,但最后一個循環(huán)不交換。DES 使用 16 個循環(huán),使用異或,置換,代換,移位操作四種基本運算。

DES常見加密模式

CBC(加密分組鏈接模式)

密文分組鏈接方式,這是golang和.NET封裝的DES算法的默認(rèn)模式,它比較麻煩,加密步驟如下:

  1. 首先將數(shù)據(jù)按照8個字節(jié)一組進(jìn)行分組得到D1D2......Dn(若數(shù)據(jù)不是8的整數(shù)倍,就涉及到數(shù)據(jù)補(bǔ)位了)
  2. 第一組數(shù)據(jù)D1與向量I異或后的結(jié)果進(jìn)行DES加密得到第一組密文C1(注意:這里有向量I的說法,ECB模式下沒有使用向量I)
  3. 第二組數(shù)據(jù)D2與第一組的加密結(jié)果C1異或以后的結(jié)果進(jìn)行DES加密,得到第二組密文C2
  4. 之后的數(shù)據(jù)以此類推,得到Cn
  5. 按順序連為C1C2C3......Cn即為加密結(jié)果。
  • 數(shù)據(jù)補(bǔ)位一般有NoPadding和PKCS7Padding(JAVA中是PKCS5Padding)填充方式,PKCS7Padding和PKCS5Padding實際只是協(xié)議不一樣,根據(jù)相關(guān)資料說明:PKCS5Padding明確定義了加密塊是8字節(jié),PKCS7Padding加密快可以是1-255之間。但是封裝的DES算法默認(rèn)都是8字節(jié),所以可以認(rèn)為他們一樣。數(shù)據(jù)補(bǔ)位實際是在數(shù)據(jù)不滿8字節(jié)的倍數(shù),才補(bǔ)充到8字節(jié)的倍數(shù)的填充過程。

  • NoPadding填充方式:算法本身不填充,比如.NET的padding提供了有None,Zeros方式,分別為不填充和填充0的方式。

  • PKCS7Padding(PKCS5Padding)填充方式:為.NET和JAVA的默認(rèn)填充方式,對加密數(shù)據(jù)字節(jié)長度對8取余為r,如r大于0,則補(bǔ)8-r個字節(jié),字節(jié)為8-r的值;如果r等于0,則補(bǔ)8個字節(jié)8。比如:

加密字符串為為AAA,則補(bǔ)位為AAA55555;加密字符串為BBBBBB,則補(bǔ)位為BBBBBB22;加密字符串為CCCCCCCC,則補(bǔ)位為CCCCCCCC88888888。

ECB(電子密碼本模式)

電子密本方式,這是JAVA封裝的DES算法的默認(rèn)模式,就是將數(shù)據(jù)按照8個字節(jié)一段進(jìn)行DES加密或解密得到一段8個字節(jié)的密文或者明文,最后一段不足8個字節(jié),則補(bǔ)足8個字節(jié)(注意:這里就涉及到數(shù)據(jù)補(bǔ)位了)進(jìn)行計算,之后按照順序?qū)⒂嬎闼玫臄?shù)據(jù)連在一起即可,各段數(shù)據(jù)之間互不影響。

CFB(加密反饋模式)

加密反饋模式克服了需要等待8個字節(jié)才能加密的缺點,它采用了分組密碼作為流密碼的密鑰流生成器;

OFB(輸出反饋模式)

與CFB模式不同之處在于, 加密位移寄存器與密文無關(guān)了,僅與加密key和加密算法有關(guān);
做法是不再把密文輸入到加密移位寄存器,而是把輸出的分組密文(Oi)輸入到一位寄存器;

DES加密之golang的CBC和ECB模式代碼實現(xiàn)

CBC和ECB模式加密

func DesECBEncrypt(data, key []byte)([]byte, error) {
    block, err := des.NewCipher(key)
    if err != nil {
        return nil, err
    }
    bs := block.BlockSize()
    data = PKCS5Padding(data, bs)
    if len(data)%bs != 0 {
        return nil, errors.New("Need a multiple of the blocksize")
    }
    out := make([]byte, len(data))
    dst := out
    for len(data) > 0 {
        block.Encrypt(dst, data[:bs])
        data = data[bs:]
        dst = dst[bs:]
    }
    return out, nil
}

func DesCBCEncrypt(origData, key []byte) ([]byte, error) {
    block, err := des.NewCipher(key)
    if err != nil {
        return nil, err
    }
    origData = PKCS5Padding(origData, block.BlockSize())
    // origData = ZeroPadding(origData, block.BlockSize())
    blockMode := cipher.NewCBCEncrypter(block, key)
    crypted := make([]byte, len(origData))
    // 根據(jù)CryptBlocks方法的說明,如下方式初始化crypted也可以
    // crypted := origData
    blockMode.CryptBlocks(crypted, origData)
    return crypted, nil
}

func PKCS5Padding(ciphertext []byte, blockSize int) []byte {
    padding := blockSize - len(ciphertext)%blockSize
    padtext := bytes.Repeat([]byte{byte(padding)}, padding)
    return append(ciphertext, padtext...)
}

CBC和ECB模式解密

func DesECBDecrypt(data, key []byte)([]byte, error) {
    block, err := des.NewCipher(key)
    if err != nil {
        return nil, err
    }
    bs := block.BlockSize()
    if len(data)%bs != 0 {
        return nil, errors.New("crypto/cipher: input not full blocks")
    }
    out := make([]byte, len(data))
    dst := out
    for len(data) > 0 {
        block.Decrypt(dst, data[:bs])
        data = data[bs:]
        dst = dst[bs:]
    }
    out = PKCS5UnPadding(out)
    return out, nil
}

func DesCBCDecrypt(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))
    origData := crypted
    blockMode.CryptBlocks(origData, crypted)
    //origData = PKCS5UnPadding(origData)

    origData = PKCS5UnPadding(origData)
    return origData, nil
}

func PKCS5UnPadding(origData []byte) []byte {
    length := len(origData)
    unpadding := int(origData[length-1])
    return origData[:(length - unpadding)]
}

總結(jié)

以需求驅(qū)動技術(shù),技術(shù)本身沒有優(yōu)略之分,只有業(yè)務(wù)之分。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI