数据库身份证号加密密码加密_使用密码加密数据

本文介绍了如何使用密码对数据库中的身份证号等敏感信息进行加密,确保数据的安全性。通过引用的Go语言文章,展示了数据库加密的实现方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

数据库身份证号加密密码加密

介绍 (Introduction)

When we’re encrypting data, typically we will create a random key that is able to decrypt that data. In some specific cases one wants to use a user specified key to decrypt that data like a password. However, the key that is used for cryptographic algorithms typically needs to be at least 32 bytes. But, it is likely that our password won’t make that criteria, so we need to have a solution for that. Recently, I needed such a method, and in this post I’ll lay out what I’ve done in order to solve it. But before we get into the nitty-gritty.

当我们加密数据时,通常我们将创建一个能够解密该数据的随机密钥。 在某些特定情况下,您想使用用户指定的密钥来解密该数据,例如密码。 但是,用于加密算法的密钥通常需要至少32个字节。 但是,很可能我们的密码不能满足该条件,因此我们需要一个解决方案。 最近,我需要这样一种方法,在这篇文章中,我将列出解决该问题的方法。 但是在我们深入了解之前。

DISCLAIMER: I’m not an expert at encryption, I’ve mentioned the sources that I’ve used to come to the solutions provided in this post. I implore you read/watch those sources to better understand it. And, as such if there are any errors in the post/code please let me know or leave a comment so I can update it, so that there is no perpetuation of wrong methods/techniques.

免责声明 :我不是加密方面的专家,我已经提到过我用于本文中提供的解决方案的资源。 我恳请您阅读/观看这些资料,以更好地理解它。 并且,因此,如果邮编/代码中有任何错误,请让我知道或发表评论,以便我进行更新,这样就不会永久保留错误的方法/技术。

OK, since we’ve got that out of the way, let’s begin! (Note: you can also view this post here)

好的,既然我们已经解决了这个问题,那就开始吧! (注意:您也可以在此处查看此帖子)

加密 (Encrypt)

Let’s first start with encrypting our data. We’ll start with creating the Encrypt function that will accept a key and a data argument. Based on that we will encrypt the data that can be decrypted using the key. First, we will generate that key by using 32 random bytes, later on we'll replace that with our password. Below, shows the code that is able to encrypt our data, provided by a generated key.

首先让我们加密数据。 我们将从创建Encrypt函数开始,该函数将接受keydata参数。 基于此,我们将加密可以使用key解密的数据。 首先,我们将使用32个随机字节来生成该密钥,然后将其替换为密码。 下面显示了能够加密我们的数据的代码,该代码由生成的密钥提供。

import (
"crypto/aes"
"crypto/cipher"
"crypto/rand"
)
func Encrypt(key, data []byte) ([]byte, error) {
blockCipher, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
gcm, err := cipher.NewGCM(blockCipher)
if err != nil {
return nil, err
}
nonce := make([]byte, gcm.NonceSize())
if _, err = rand.Read(nonce); err != nil {
return nil, err
}
ciphertext := gcm.Seal(nonce, nonce, data, nil)
return ciphertext, nil
}

So, let’s go over the code, and inspect what we’re doing.

因此,让我们看一下代码,检查我们在做什么。

func Encrypt(key, data []byte) ([]byte, error)

First, we start by creating our Encrypt function, and it will accept a key and a data argument. We'll be using a byte slice instead of an io.Reader as the data argument. While using io.Reader would allow us to use the Encrypt function with every other type that implements the io.Reader interface. (Ryer 2015) It is however because of the nature of io.Reader, being a stream of data, that when we want to decrypt the ciphertext, we need to see it in its entirety. A solution would be to break the stream into discrete chunks, however this would add significant complexity to the problem.¹ (Isom 2015)

首先,我们从创建我们的Encrypt函数开始,它将接受一个key和一个data参数。 我们将使用byte片而不是io.Reader作为data参数。 在使用io.Reader ,我们可以将Encrypt函数与其他所有实现io.Reader接口的类型一起使用。 ( 2015年 ,赖尔)但是由于io.Reader的本质(作为数据流),当我们想要解密ciphertext ,我们需要完整地查看它。 一种解决方案是将流分成离散的块,但这将大大增加问题的复杂性。 ¹ (Isom 2015 )

blockCipher, err := aes.NewCipher(key)

We’re initializing the block cipher based on the key that we provided. Here we're using the crypto/aes² package that implements the AES³ (Advanced Encryption Standard) encryption algorithm. AES is a symmetric-key encryption algorithm, that will be secure enough for modern use cases. Additionally, AES uses hardware acceleration on most platforms, so it'll be pretty fast to use. (Tankersley 2016)

我们正在根据提供的key初始化分组密码。 这里,我们使用的crypto/aes ²包实现了AES ³ (高级加密标准)加密算法。 AES是一种对称密钥加密算法,对于现代用例而言,它将足够安全。 此外,AES在大多数平台上都使用硬件加速,因此使用起来会非常快。 (Tankersley 2016 )

gcm, err := cipher.NewGCM(blockCipher)

Here we’re wrapping the block cipher, with a specific mode. We do this because we shouldn’t use a cipher.Block interface directly. This is because the block cipher only encrypts 16 bytes of data, nothing more. So if you would call blockCiper.Encrypt() it would only encrypt the first 16 bytes. Thus we need something on top of that, and wrap the block cipher, and those are called modes. Again we have several modes to choose from, and here we're going to use the Galois Counter Mode (GCM), with a standard nonce length.

在这里,我们使用特定的模式包装分组密码。 我们这样做是因为我们不应该直接使用cipher.Block接口。 这是因为分组密码仅加密16个字节的数据,仅此而已。 因此,如果您调用blockCiper.Encrypt() ,它将仅加密前16个字节。 因此,我们需要最重要的东西,并包装分组密码,这些被称为mode 。 同样,我们有几种模式可供选择,在这里,我们将使用具有标准随机数长度的Galois计数器模式 (GCM)

Only GCM provides authenticated encryption, and it implements the cipher.AEAD interface (Authenticated Encryption with Associated Data). Authenticated encryption means that not only is your data going to be confidential, secret, and encrypted, it's also now going to be tamper proof. If someone alters the ciphertext you will not then be able to validly decrypt it. When you're using authenticated encryption and someone messes with your data it just fails to decrypt. (Tankersley 2016; Isom 2015)

只有GCM提供认证加密,并实现了cipher.AEAD接口(认证加密与相关数据) 。 经过身份验证的加密意味着不仅您的数据将是机密,机密和加密的,而且现在也将是防篡改的。 如果有人更改了ciphertext您将无法对其进行有效解密。 当您使用经过身份验证的加密时,如果有人弄乱了您的数据,它将无法解密。 (Tankersley 2016 ; Isom 2015 )

nonce := make([]byte, gcm.NonceSize())
if _, err = rand.Read(nonce); err != nil {
return nil, err
}

Before we can encrypt our bytes we need to generate a randomized nonce, and its length is specified by the GCM. The nonce stands for: number once used, and it's a piece of data that should not be repeated and only used once in combination with any particular key. Meaning: don't repeat the combination of a key and a nonce more than once. But, how do you keep track of that? If we use sufficiently large numbers for a nonce we should probably be fine for this use-case. (Isom 2015; Viega and Messier 2003, 134-35) We do that by using Go's crypto/rand package to read randomized bytes into the nonce byte slice.

在加密字节之前,我们需要生成一个随机nonce ,其长度由GCM指定。 nonce代表: 一次使用过的number ,它是不应该重复的数据,只能与任何特定键结合使用一次。 含义:不要重复重复keynonce的组合。 但是,您如何跟踪呢? 如果我们为nonce使用足够大的数字,则在此用例下应该会很好。 (ISOM 2015年 ; Viega和Messier 2003 ,134-35),我们通过使用Go的crypto/rand包读取的字节随机进入nonce字节片。

encryptedData := gcm.Seal(nonce, nonce, bData, nil)

The nonce that we're going to use for encrypting our data, is also needed to decrypt it. So we need to be able to refer to it while decrypting, and one of the strategies is to add it to the encrypted data. In this example we will prepend the nonce to the encrypted data. We do that by passing in the nonce as the first argument dst of the Seal function, and as such the encrypted data will be appended to it. We can do this because the nonce doesn't have to be secret, it just has to be unique. (Tankersley 2016)

我们还需要使用nonce来解密数据。 因此,我们需要能够在解密时引用它,而策略之一就是将其添加到加密数据中。 在此示例中,我们将在nonce添加加密数据。 我们通过将nonce作为Seal函数的第一个参数dst传递来完成,因此将加密数据附加到该函数。 我们能做到这一点,因为nonce不必是秘密的,它只是必须是唯一的。 (Tankersley 2016 )

解密 (Decrypt)

Now, we’re able to encrypt our data, and let’s implement the Decrypt function.

现在,我们可以加密数据,并实现Decrypt函数。

import (
"crypto/aes"
"crypto/cipher"
)func Decrypt(key, data []byte) ([]byte, error) {
blockCipher, err := aes.NewCipher(key)
if err != nil {
return nil, err
} gcm, err := cipher.NewGCM(blockCipher)
if err != nil {
return nil, err
} nonce, ciphertext := data[:gcm.NonceSize()], data[gcm.NonceSize():] plaintext, err := gcm.Open(nil, nonce, ciphertext, nil)
if err != nil {
return nil, err
} return plaintext, nil
}

Again let’s go over the code and check what it does. It is largely the same code as the Encrypt function, so let's inspect the parts that differ.

再次让我们检查代码并检查它的作用。 它与Encrypt函数在很大程度上是相同的代码,因此让我们检查不同的部分。

nonce, ciphertext := data[:gcm.NonceSize()], data[gcm.NonceSize():]

Remember from the last section, that we prepended the nonce to the data using gcm.Seal to create the ciphertext? Now we need to split those parts so we can use them independently. And we're creating those part by slicing the data based on the size of the nonce that gcm provides.

还记得从上一节开始,我们使用gcm.Sealnonce放在data gcm.Seal以创建ciphertext吗? 现在我们需要拆分这些部分,以便我们可以独立使用它们。 我们通过根据gcm提供的nonce的大小对data进行切片来创建这些部分。

plaintext, err := gcm.Open(nil, nonce, ciphertext, nil)

Now, we’re using gcm.Open to decrypt the ciphertext into plaintext.

现在,我们使用gcm.Openciphertext解密为plaintext

(Key)

We’ve been passing in a key to both the Encrypt and Decrypt functions, but we have yet to make it, so let's do that.

我们一直在为EncryptDecrypt函数传递key ,但是我们还没有做到这一点,所以让我们开始吧。

import (
"crypto/rand"
)func GenerateKey() ([]byte, error) {
key := make([]byte, 32) _, err := rand.Read(key)
if err != nil {
return nil, err
} return key, nil
}

Here we’re generating a random key using Go's crypto/rand package. For AES we need a key that has the length of 32 bytes, so we make a byte slice of size 32. Then we let rand.Read() fill the slice with random bytes.¹⁰

在这里,我们使用Go的crypto/rand软件包生成了一个随机key 。 对于AES,我们需要一个长度为32个字节的key ,因此我们制作了一个大小为32的字节片。然后让rand.Read()用随机字节填充rand.Read()¹⁰

Now we have enough to encrypt and decrypt some data, so let’s put it all together and test it out:

现在我们有足够的加密和解密某些数据,因此让我们将它们放在一起并进行测试:

// crypto.go
package mainimport (
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"encoding/hex"
"fmt"
"log"
)func Encrypt(key, data []byte) ([]byte, error) {
blockCipher, err := aes.NewCipher(key)
if err != nil {
return nil, err
} gcm, err := cipher.NewGCM(blockCipher)
if err != nil {
return nil, err
} nonce := make([]byte, gcm.NonceSize())
if _, err = rand.Read(nonce); err != nil {
return nil, err
} ciphertext := gcm.Seal(nonce, nonce, data, nil) return ciphertext, nil
}func Decrypt(key, data []byte) ([]byte, error) {
blockCipher, err := aes.NewCipher(key)
if err != nil {
return nil, err
} gcm, err := cipher.NewGCM(blockCipher)
if err != nil {
return nil, err
} nonce, ciphertext := data[:gcm.NonceSize()], data[gcm.NonceSize():] plaintext, err := gcm.Open(nil, nonce, ciphertext, nil)
if err != nil {
return nil, err
} return plaintext, nil
}func GenerateKey() ([]byte, error) {
key := make([]byte, 32) _, err := rand.Read(key)
if err != nil {
return nil, err
} return key, nil
}func main() {
data := []byte("our super secret text") key, err := GenerateKey()
if err != nil {
log.Fatal(err)
} ciphertext, err := Encrypt(key, data)
if err != nil {
log.Fatal(err)
} fmt.Printf("ciphertext: %s\n", hex.EncodeToString(ciphertext)) plaintext, err := Decrypt(key, ciphertext)
if err != nil {
log.Fatal(err)
} fmt.Printf("plaintext: %s\n", plaintext)
}

And, we can run this example with:

并且,我们可以使用以下示例运行此示例:

$ go run crypto.go

Now, we have enough to encrypt and decrypt our data with a randomized key. This is cool and now we have a key that allows us to encrypt and decrypt our data. But that means that the key now becomes our password and weren't able to choose it ourselves, additionally it has a length of 32 bytes.

现在,我们已经足够使用随机密钥来加密和解密data 。 这很酷,现在我们有了一个key ,可以用来加密和解密data 。 但这意味着key现在变成了我们的密码,无法自己选择,此外它的长度为32个字节。

But, as mentioned in the start of the post, we want to be able to encrypt and decrypt the data by providing our own key namely a password that we've chosen to use. We will be doing that in the following section.

但是,正如文章开头所述,我们希望能够通过提供我们自己的key即我们选择使用的密码)来加密和解密数据。 我们将在下一节中进行说明。

密码 (Password)

Now, the aes.NewCipher() needs a 16, 24, or a 32 byte key, and in this example we are using a 32 byte key. However, our password likely isn't going to be 32 bytes. So we need to transform our password to a suitable key. And we do that by using a key derivation function (KDF)¹¹ to 'stretch' the password to make it a suitable cryptographic key. This key-stretching¹² characterizes itself by being slow. This is done in order to make it that, an attacker needs to spend a lot of resources to attempt to brute force an attack the on the password. We have several options for KDF's: Argon2¹³, scrypt¹⁴, bcrypt¹⁵, and pbkdf2¹⁶. Choosing one depends on several factors, but mainly how safe it is.¹⁷ ¹⁸ ¹⁹ ²⁰ ²¹ ²²

现在, aes.NewCipher()需要一个aes.NewCipher()或32字节的key ,在此示例中,我们使用32字节的key 。 但是,我们的密码可能不会是32个字节。 因此,我们需要将密码转换为合适的key 。 同时,我们也通过使用密钥导出函数 (KDF) ¹¹为“拉伸”的密码,使其合适的加密密钥。 此键拉伸¹²由正在缓慢为特色。 这样做是为了使攻击者需要花费大量资源来尝试对密码进行强行攻击。 我们对KDF的几种选择:Argon2 ¹³ ,scrypt ¹⁴ ,bcrypt ¹⁵和PBKDF2 ¹⁶ 。 选择一个取决于多个因素,但主要取决于它的安全性。 ¹⁷ ¹⁸ ¹⁹ ²⁰ ²¹ ²²

Typically in a KDF we have a password, a salt, and an iterations argument. The salt²³ is used to prevent an attacker from just storing password/key pairs, and prevents an attacker from precomputing a dictionary of derived keys, as a different salt yields a different output. Each password has to be checked with the salt used to derive the key. (Isom 2015; Wikipedia 2020) The salt is related to the nonce in that it also needs to be randomly generated. And as with the nonce, the salt doesn't need to be secret, it needs to be unique. The iterations argument or the difficulty parameter, signifies how many times to repeat the process. This is because, even with salt, a dictionary attack is still possible, but with the iterations count, it will slow down the time it takes to compute a key from a password. (Viega and Messier 2003, 141-42)

通常,在KDF中,我们有一个password ,一个salt和一个iterations参数。 salt ³”用于防止攻击者仅存储密码/密钥对,并防止攻击者预先计算派生密钥的字典,因为不同的盐会产生不同的输出。 每个密码都必须与用于导出密钥的salt一起检查。 (Isom 2015 ; Wikipedia 2020 ) saltnonce ,因为它也需要随机生成。 与noncesalt不必是秘密的,它必须是唯一的。 iterations参数或难度参数表示重复该过程多少次。 这是因为,即使使用salt ,仍然可以进行字典攻击 ,但是随着iterations次数的增加,它将减慢从密码计算key所需的时间。 (Viega和Messier 2003 ,141-42)

In this example we’ll be using scrypt, so let’s see how we can implement that into our program.

在此示例中,我们将使用scrypt ,因此让我们看看如何将其实现到程序中。

import (
"crypto/rand" "golang.org/x/crypto/scrypt"
)func DeriveKey(password, salt []byte) ([]byte, []byte, error) {
if salt == nil {
salt = make([]byte, 32)
if _, err := rand.Read(salt); err != nil {
return nil, nil, err
}
} key, err := scrypt.Key(password, salt, 1048576, 8, 1, 32)
if err != nil {
return nil, nil, err
} return key, salt, nil
}

Again let’s go over the code and see what it does.

再次让我们看一下代码,看看它能做什么。

func DeriveKey(password, salt []byte) ([]byte, []byte, error)

Here we accept the password as a slice of bytes as the argument, and we return the resulting key, and salt.

在这里,我们接受密码(作为字节的一部分)作为参数,并返回结果keysalt

salt := make([]byte, 32)
if _, err := rand.Read(salt); err != nil {
return err
}

Just like our Encrypt function, we'll be creating the salt with 32 random bytes.

就像我们的Encrypt函数一样,我们将使用32个随机字节来创建salt

key, err := scrypt.Key(password, salt, 1048576, 8, 1, 32)

Here we’re using the scrypt package from golang.org/x/ library.²⁴ From the documentation we can read that the Key function accepts the following arguments:

在这里,我们使用来自golang.org/x/库的scrypt包。 ²⁴从文档,我们可以读到, Key函数接受以下参数:

func Key(password, salt []byte, N, r, p, keyLen int) ([]byte, error)

The arguments password and salt speak for themselves. N is the number of iterations. In a presentation given by C. Percival it is recommended that for interactive logins 16384 (2^14) iterations, and for file encryption 1048576 (2^20) iterations are used. (Percival 2005a, 2005b; Isom 2015) The arguments r and p must satisfy r * p < 2^30, if it doesn't satisfy the limits, the function returns a nil byte slice and an error. (Golang Documentation 2020). The r argument defines the relative memory cost parameter it controls the blocksize in the underlying hash, the recommended value is 8. The p argument is the relative CPU cost parameter and the recommended value for this is 1. (Isom 2015; Percival 2005a) The keyLen argument defines the length of the bytes that are returned as key, as discussed this will be 32 bytes.

参数passwordsalt言自明。 N是迭代次数。 在C. Percival提供的演示中,建议对交互式登录使用16384(2 ^ 14)个迭代,对于文件加密,建议使用1048576(2 ^ 20)迭代。 (Percival 2005a2005b ; Isom 2015 )参数rp必须满足r * p <2 ^ 30,如果不满足限制,则该函数将返回nil个字节切片和一个错误。 (Golang文档2020 )。 r参数定义了它控制底层哈希中的块大小的相对内存成本参数,建议值为p参数是相对CPU成本参数,为此的建议值为1。(Isom 2015 ; Percival 2005a ) keyLen参数定义作为键返回的字节的长度,如所讨论的,这将是32个字节。

结果 (Result)

Now that we’ve created our DeriveKey function we need to update our code to support it. So let's do that, it should resemble the code below:

现在,我们已经创建了DeriveKey函数,我们需要更新代码以支持它。 因此,让我们这样做,它应该类似于以下代码:

// scrypt.go
package mainimport (
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"crypto/sha256"
"encoding/hex"
"fmt"
"log" "golang.org/x/crypto/scrypt"
)func Encrypt(key, data []byte) ([]byte, error) {
key, salt, err := DeriveKey(key, nil)
if err != nil {
return nil, err
} blockCipher, err := aes.NewCipher(key)
if err != nil {
return nil, err
} gcm, err := cipher.NewGCM(blockCipher)
if err != nil {
return nil, err
} nonce := make([]byte, gcm.NonceSize())
if _, err = rand.Read(nonce); err != nil {
return nil, err
} ciphertext := gcm.Seal(nonce, nonce, data, nil) ciphertext = append(ciphertext, salt...) return ciphertext, nil
}func Decrypt(key, data []byte) ([]byte, error) {
salt, data := data[len(data)-32:], data[:len(data)-32] key, _, err := DeriveKey(key, salt)
if err != nil {
return nil, err
} blockCipher, err := aes.NewCipher(key)
if err != nil {
return nil, err
} gcm, err := cipher.NewGCM(blockCipher)
if err != nil {
return nil, err
} nonce, ciphertext := data[:gcm.NonceSize()], data[gcm.NonceSize():] plaintext, err := gcm.Open(nil, nonce, ciphertext, nil)
if err != nil {
return nil, err
} return plaintext, nil
}func DeriveKey(password, salt []byte) ([]byte, []byte, error) {
if salt == nil {
salt = make([]byte, 32)
if _, err := rand.Read(salt); err != nil {
return nil, nil, err
}
} key, err := scrypt.Key(password, salt, 1048576, 8, 1, 32)
if err != nil {
return nil, nil, err
} return key, salt, nil
}func main() {
var (
password = []byte("mysecretpassword")
data = []byte("our super secret text")
) ciphertext, err := Encrypt(password, data)
if err != nil {
log.Fatal(err)
} fmt.Printf("ciphertext: %s\n", hex.EncodeToString(ciphertext)) plaintext, err := Decrypt(password, ciphertext)
if err != nil {
log.Fatal(err)
} fmt.Printf("plaintext: %s\n", plaintext)
}

And, we’re able to run and test it:

并且,我们能够运行和测试它:

# First we need to get the scrypt package
$ go get -u golang.org/x/crypto/scrypt$ go run scrypt.go

We’ve updated some parts, so let’s go over it.

我们已经更新了一些部分,所以让我们复习一下。

key, salt, err := DeriveKey(key, nil)

In the Encrypt function we create our key by passing in our password, which is contained in the key argument. We pass in nil as the salt argument, that is because we want to create the salt since it is the first time we encrypt our data.

Encrypt函数中,我们通过传入密码(包含在key参数中)来创建key 。 我们传入nil作为salt参数,这是因为我们要创建salt因为这是我们第一次加密data

ciphertext = append(ciphertext, salt...)

Additionally, in the Encrypt function, we append the salt to our ciphertext.

另外,在Encrypt函数中,我们将salt附加到ciphertext

salt, data := data[len(data)-32:], data[:len(data)-32]

And, because we append the salt to the ciphertext, we need to split and slice it in the Decrypt function, because we're going to use it in the DeriveKey function.

并且,由于我们将salt附加到ciphertext ,因此我们需要在Decrypt函数中对其进行分割和切片,因为我们将在DeriveKey函数中使用它。

key, _, err := DeriveKey(key, salt)

As you can see here we pass in the salt to the DeriveKey function and we'll be able to retrieve the key that we used in order to encrypt our data.

如您所见,我们将盐传递给DeriveKey函数,并且我们将能够检索用于加密数据的key

结论 (Conclusion)

With that, we’ve created two ways in order to encrypt and decrypt our data in Go. First we’ve encrypted our data by using the AES encryption algorithm, for which we’ve created a randomized key to be used for decrypting our data. Subsequently, we’ve updated our code to support using a password as our key. We’ve done that by key-stretching our password using a key derivation function, and we’ve used scrypt to achieve that. Hopefully, you found this post useful, and again I advice you to read and watch the sources that I’ve listed, and check out other sources to get a good overview on how to correctly and securely encrypt your data, and if you have any suggestions let me know.

这样,我们创建了两种方法来加密和解密Go中的数据。 首先,我们使用AES加密算法对数据进行了加密,为此我们创建了一个随机密钥来解密数据。 随后,我们更新了代码以支持使用密码作为密钥。 我们使用密钥派生函数通过密钥扩展口令来实现这一点,并且我们使用scrypt实现了这一点。 希望您发现这篇文章很有用,我再次建议您阅读和观看我列出的资源,并查看其他资源以获得关于如何正确,安全地加密数据以及是否有任何数据的良好概述。建议让我知道。

脚注 (Footnotes)

[1] Some references on how to implement encryption with streams: Reddit Comment; Michael Turner — Encrypting Streams in Go; Minio — Github Issue

[1]关于如何使用流实现加密的一些参考: Reddit Comment ; Michael Turner-Go中的加密流 Minio — Github问题

[2] Go Documentation: AES

[2] 转到文档:AES

[3] Wikipedia: AES

[3] 维基百科:AES

[4] Computerphile — AES Explained

[4] Computerphile — AES解释了

[5] Wikipedia: GCM

[5] 维基百科:GCM

[6] Go Documentation: AEAD

[6]查阅文档:AEAD

[7] Go Documentation: rand.Read

[7]查阅文档:rand.Read

[8] Go Source Code: GCM

[8] 转到源代码:GCM

[9] Go Source Code: GCM

[9] 转到源代码:GCM

[10] Go Documentation: rand.Read

[10]查阅文档:rand.Read

[11] Wikipedia: KDF

[11] 维基百科:KDF

[12] Wikipedia: Key Stretching

[12] 维基百科:密钥扩展

[13] Wikipedia: Argon2

[13] 维基百科:Argon2

[14] Wikipedia: scrypt

[14] 维基百科:scrypt

[15] Wikipedia: bcrypt

[15] 维基百科:bcrypt

[16] Wikipedia: pbkdf2

[16] 维基百科:pbkdf2

[17] Michele Prezioso — Password Hashing: PBKDF2, Scrypt, Bcrypt

[17] Michele Prezioso-密码哈希:PBKDF2,Scrypt,Bcrypt

[18] Michele Prezioso — Password Hashing: Scrypt, Bcrypt and ARGON2

[18] Michele Prezioso-密码哈希:Scrypt,Bcrypt和ARGON2

[19] StackExchange — What’s the difference between PBKDF and SHA and why use them together?

[19] StackExchange-PBKDF和SHA之间有什么区别,为什么要同时使用它们?

[20] Github — Bitwarden Issue 52

[20] GitHub-Bitwarden第52期

[21] Github — Bitwarden Issue 589

[21] Github-Bitwarden第589期

[22] Wikipedia: pbkdf2 alternatives

[22] 维基百科:pbkdf2替代品

[23] Wikipedia: Salt (cryptography)

[23] Wikipedia:Salt(密码学)

[24] Go Documentation: scrypt

[24]查阅文档:scrypt

翻译自: https://itnext.io/encrypt-data-with-a-password-in-go-b5366384e291

数据库身份证号加密密码加密

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值