寫在前面
這是我封裝的一個加密庫,secret包,上層抽離接口,讓我們的更容易對敏感資料進行 脫敏處理
。
github位址:https://github.com/CocaineCong/secret
這裡就不再過多贅述
AES/DES/3DES/RSA 等的加密算法
。
這一次重點介紹一下新增的一些新特性,主要是在 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加密和解密都是可以
了,非常的簡潔和友善,與 CBC/CFB 不同,CBC/CFB 則需要區分 Encrypt 和 Decrypt。直接一個New就完事
// 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
}
下一個版本會解決的問題:
- hash 填充代替
- 3DES 支援多模式
- 性能測試