golang密文存储

需求 【golang密文存储】加密存储用户数据,实现即使数据库泄露,也能保证用户数据的安全。
思路

  • 使用AES处理普通数据。
  • 使用Argon2处理特殊数据。
    以加密后是否需要解密为标准区分:
    加密后需要解密的,为普通数据(手机号邮箱)。
    反之,为特殊数据(登录密码)。
实现 AES处理普通数据
AES,Advanced Encryption Standard,高级加密标准。
// AES key,16、24或者32位,依次对应AES-128、AES-192和AES-256。 const key = "1234567887654321"// AES加密 func AESEncrypt(plainText []byte) ([]byte, error) { block, err := aes.NewCipher([]byte(key)) // 使用AES key生成cipher.Block接口 if err != nil { return nil, err } plainText = pkcs5Append(plainText, block.BlockSize())// 填充最后一个分组的数据 blockMode := cipher.NewCBCEncrypter(block, ([]byte(key))[:block.BlockSize()]) // 生成BlockMode接口 cipherText := plainText blockMode.CryptBlocks(cipherText, plainText) // 加密 return cipherText, nil }// AES解密 func AESDecrypt(cipherText []byte) ([]byte, error) { block, err := aes.NewCipher([]byte(key)) // 使用AES key生成cipher.Block接口 if err != nil { return nil, err } blockMode := cipher.NewCBCEncrypter(block, ([]byte(key))[:block.BlockSize()]) // 生成BlockMode接口 plainText := cipherText blockMode.CryptBlocks(plainText, cipherText) // 解密 plainText = pkcs5Trim(plainText) return plainText, nil }// 使用PKCS#5算法填充最后一个分组的数据 func pkcs5Append(ciphertext []byte, blockSize int) []byte { padding := blockSize - (len(ciphertext) % blockSize)// 计算最后一个分组缺多少个字节 padText := bytes.Repeat([]byte{byte(padding)}, padding) // 创建一个大小为padding的切片, 每个字节的值为padding newText := append(ciphertext, padText...)// 将padText添加到原始数据的后边, 将最后一个分组缺少的字节数补齐 return newText }// 删除填充的数据 func pkcs5Trim(origData []byte) []byte { length := len(origData)// 计算数据的总长度 number := int(origData[length-1])// 根据填充的字节值得到填充的次数 return origData[:(length - number)] // 将尾部填充的number个字节去掉 }

Argon2处理特殊数据
Argon2,密码散列竞赛冠军算法,是比bcryptscrypt更可靠的密码散列算法。
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
常用密码技术 | 爱编程的大丙

    推荐阅读