需求
加密存储用户数据,实现即使数据库泄露,也能保证用户数据的安全。
思路
- 使用
AES
处理普通数据。 使用
Argon2
处理特殊数据。以加密后是否需要解密为标准区分:
加密后需要解密的,为普通数据(手机号、邮箱)。
反之,为特殊数据(登录密码)。
实现
AES处理普通数据
AES,Advanced Encryption Standard,高级加密标准。
加密
func AESEncrypt(plainText []byte) ([]byte, error) {
// 判空
if len(plainText) == 0 {
return plainText, nil
}
// 生成数据块接口
block, err := aes.NewCipher([]byte(key))
if err != nil {
return nil, err
}
// AES以128比特(16字节)为单位进行分组加密
// 若最后的分组不足16字节,需补足至16字节
if len(plainText)%block.BlockSize() > 0 {
// 计算缺口(1-15)
lack := block.BlockSize() - len(plainText)%block.BlockSize()
// 生成填充的bytes数组
padding := bytes.Repeat([]byte{byte(lack)}, lack)
// 填充
plainText = append(plainText, padding...)
}
// 生成CBC模式的加密接口
encrypter := cipher.NewCBCEncrypter(
block, ([]byte(key))[:block.BlockSize()],
)
// 加密
cipherText := make([]byte, len(plainText))
encrypter.CryptBlocks(cipherText, plainText)
return cipherText, nil
}
解密
func AESDecrypt(cipherText []byte) ([]byte, error) {
// 判空
if len(cipherText) == 0 {
return cipherText, nil
}
// 生成数据块接口
block, err := aes.NewCipher([]byte(key))
if err != nil {
return nil, err
}
// 生成CBC模式的解密接口
decrypter := cipher.NewCBCDecrypter(
block, ([]byte(key))[:block.BlockSize()],
)
// 解密
plainText := make([]byte, len(cipherText))
decrypter.CryptBlocks(plainText, cipherText)
// 剔除加密时填充的部分
if plainText[len(plainText)-1] < 16 {
plainText = plainText[:(len(plainText) - int(plainText[len(plainText)-1]))]
}
return plainText, nil
}
Argon2处理特殊数据
Argon2,密码散列竞赛冠军算法,是比bcrypt
、scrypt
更可靠的密码散列算法。
go get -u golang.org/x/crypto/argon2
// 定义盐
salt := "some salt"
// 基于Argon2id生成密码的散列值
key := argon2.IDKey([]byte("some password"), salt, 1, 64*1024, 4, 32)
// 将key编码为base64字符串
data := base64.StdEncoding.EncodeToString(key)
Password Hashing Competition
phc-winner-argon2
golang/crypto
常用密码技术 | 爱编程的大丙
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。