天天看點

secret 包新特性 | 多位密鑰支援 & 多種模式選擇

寫在前面

這是我封裝的一個加密庫,secret包,上層抽離接口,讓我們的更容易對敏感資料進行​

​脫敏處理​

​。

github位址:https://github.com/CocaineCong/secret

這裡就不再過多贅述​

​ AES/DES/3DES/RSA 等的加密算法​

​。

secret 包新特性 | 多位密鑰支援 & 多種模式選擇

這一次重點介紹一下新增的一些新特性,主要是在 AES 加密這一塊。

AES

1. 密鑰長度

我們新增了對密鑰程度的加密的選擇。可以選擇 128、192、256 三種長度的密鑰進行加密,更加靈活友善。

type AesKeyType uint64 
const (
  AesEncrypt128 AesKeyType = 128
  AesEncrypt192 AesKeyType = 192
  AesEncrypt256 AesKeyType = 256
)      

2. 加密模式

之前版本僅支援 CBC模式 的加密,這次我們擴充了 ​

​CFB / CTR / OFB ​

​ 三種模式。

讓我們加密模式的選擇更多樣化。

// AES 加密模式
const (
  AesModeTypeCBC AesModeType = "CBC" // Cipher Block Chaining
  AesModeTypeCFB AesModeType = "CFB" // Cipher FeedBack
  AesModeTypeCTR AesModeType = "CTR" // Counter
  AesModeTypeOFB AesModeType = "OFB" // Output FeedBack
)      

同樣的,為了相容更多的模式,我們擴充了AES對象。

type AesEncrypt struct {
  SpecialSign string // 加解密都會基于這一串字元,如果沒有會基于 AesBaseSpecialSign.
  Key         string // 密鑰,建議是 5-8位的密鑰

  IV string // 初始向量 16 位元組

  AesModeType AesModeType // 加密類型

  AesKeyType   AesKeyType // 加密類型
  AesKey       []byte     // AES 密鑰
  AesKeyLength int        // 加密長度

  PlainTextLength int // 加密對象的長度
}      

雖然字段增加多了,但是很多都是封裝實作的,不需要使用者将全部的參數都輸入來進行建構

使用者隻需要選擇傳入必要的參數即可,非常友善簡潔,甚至不需要輸入​

​iv​

舉個例子:

specialSign := "a1231243124124314vczxfda124sd"
key := "458796" // key 密鑰
aesEncrypt, _ := NewAesEncrypt(specialSign, key, "", AesEncrypt128, AesModeTypeCTR)      

我們隻是在原先的基礎上,增加了iv初始向量以及選擇加密的長度。

并且與之前一樣的加解密操作。

str := aesEncrypt.SecretEncrypt("this is a secret")
fmt.Println(str)
ans := aesEncrypt.SecretDecrypt(str)
fmt.Println(ans)      

以上的新加的功能都是基于AES的,目前DES是不太考慮加了,可能後續會新增3DES的加密mode。

這裡提一下關于兩個新加入的加密 mode ​

​CTR AND OFB ​

  • 加密

    這裡我們的CTR和OFB加密和解密都是可以​​

    ​直接一個New就完事​

    ​了,非常的簡潔和友善,與 CBC/CFB 不同,CBC/CFB 則需要區分 Encrypt 和 Decrypt。
// aesEncrypter CTR OR OFB 模式的加密
func (a *AesEncrypt) aesEncrypter(encodeStr string, block cipher.Block, mode AesModeType) (string, error) {
  cipherText := make([]byte, a.PlainTextLength)
  m := cipher.NewCTR(block, []byte(a.IV))
  if mode == AesModeTypeCFB {
    m = cipher.NewOFB(block, []byte(a.IV))
  }
  copy(cipherText, encodeStr)
  m.XORKeyStream(cipherText, cipherText)
  return hex.EncodeToString(cipherText), nil
}      
  • 解密
// aesDecrypter CTR OR OFB 模式的加密
func (a *AesEncrypt) aesDecrypter(decodeBytes []byte, block cipher.Block, mode AesModeType) (string, error) {
  m := cipher.NewCTR(block, []byte(a.IV))
  if mode == AesModeTypeCFB {
    m = cipher.NewOFB(block, []byte(a.IV))
  }
  plainTextCopy := make([]byte, a.PlainTextLength)
  copy(plainTextCopy, decodeBytes)
  m.XORKeyStream(plainTextCopy, plainTextCopy)
  return string(plainTextCopy), nil
}      

3. 拼接選擇

這一次我們抽離對 ​

​specialSign​

​​ 的填充操作。​

​目前還是裁剪,後面打算換成hash,并且将string 由 編碼的形式呈現​

如果這個 specialSign 加上 key

  • 不足對應的加密密鑰的長度,那麼我們會用 BaseSpecialSign 對specialSign 進行 填充。
  • 如果大于對應的加密密鑰的長度,我們會根據奇偶來判斷,是取字首還是字尾。
func formatSpecialSign(specialSign, key string, keyLength int) string {
  specialSignLength := len(specialSign)
  if specialSignLength+len(key) < keyLength {
    log.Printf("【WARN】 the length of specialSign and key less %v ", keyLength)
    if specialSignLength%2 == 0 {
      specialSign += BaseSpecialSign[:keyLength-len(specialSign)]
    } else {
      specialSign += BaseSpecialSign[BaseSpecialSignLength-keyLength:]
    }
  }
  if specialSignLength > keyLength {
    if specialSignLength%2 == 0 {
      specialSign = specialSign[:keyLength+1]
    } else {
      specialSign = specialSign[len(specialSign)-keyLength:]
    }
  }
  return specialSign
}      

下一個版本會解決的問題:

  1. hash 填充代替
  2. 3DES 支援多模式
  3. 性能測試