跳转到主要内容

目标


在本教程结束时,您将能够……

  • 使用 AES 加密文本 - Go 中的高级加密标准
  • 然后,我们将研究将此加密消息写入文件
  • 最后,我们将看看如何使用共享密钥解密此消息

由此,您应该能够构建自己的简单加密系统,该系统可以执行各种操作,例如加密文件系统上的文件并使用只有您知道的密码来保护它们,或者为您正在工作的系统的各个部分添加简单加密上。

介绍


我们将从查看 AES 或高级加密标准开始,因为这是我们将用于加密和解密 Go 程序中的信息的标准。

然后我们将构建一个非常简单的加密程序,它将从命令行接收一个密码短语,并将其与 AES 结合使用来加密一段文本。

完成此操作后,我们将创建一个对应程序,该程序将使用我们用于加密文本的相同密码来解密这段文本。

AES - 高级加密标准


因此,AES 或高级加密标准是一种对称密钥加密算法,最初由两位比利时密码学家 Joan Daemen 和 Vincent Rijmen 开发。

如果您想在任何程序中使用加密并且不太确定它们有何不同,那么 AES 绝对是最安全的选择,因为它既高效又易于使用。

注意 - 我将在以后的教程中介绍其他加密技术,因此请确保您在 Twitter 上关注我:@Elliot_f

对称密钥加密


如果您还没有遇到过对称密钥加密这个术语,请不要害怕,这是一个相对简单的概念,它本质上允许两方使用共享密钥来加密和解密信息。

我们的加密客户端


好的,让我们进入我们选择的代码编辑器并开始编写一些代码!

我们将首先创建一个名为 encrypt.go 的新文件,该文件将包含来自命令行的密码短语,然后在将其写入文件之前使用它来加密一些文本。

让我们从简单地使用预设密钥加密一段文本并打印出结果开始。一旦我们掌握了这一点,我们就可以引入更多的复杂性:

package main

import (
    "crypto/aes"
    "crypto/cipher"
    "crypto/rand"
    "fmt"
    "io"
)

func main() {
    fmt.Println("Encryption Program v0.01")

    text := []byte("My Super Secret Code Stuff")
    key := []byte("passphrasewhichneedstobe32bytes!")

    // generate a new aes cipher using our 32 byte long key
    c, err := aes.NewCipher(key)
    // if there are any errors, handle them
    if err != nil {
        fmt.Println(err)
    }

    // gcm or Galois/Counter Mode, is a mode of operation
    // for symmetric key cryptographic block ciphers
    // - https://en.wikipedia.org/wiki/Galois/Counter_Mode
    gcm, err := cipher.NewGCM(c)
    // if any error generating new GCM
    // handle them
    if err != nil {
        fmt.Println(err)
    }

    // creates a new byte array the size of the nonce
    // which must be passed to Seal
    nonce := make([]byte, gcm.NonceSize())
    // populates our nonce with a cryptographically secure
    // random sequence
    if _, err = io.ReadFull(rand.Reader, nonce); err != nil {
        fmt.Println(err)
    }

    // here we encrypt our text using the Seal function
    // Seal encrypts and authenticates plaintext, authenticates the
    // additional data and appends the result to dst, returning the updated
    // slice. The nonce must be NonceSize() bytes long and unique for all
    // time, for a given key.
    fmt.Println(gcm.Seal(nonce, nonce, text, nil))
}

因此,如果我们尝试使用 go run encrypt.go 运行它,您应该会看到它会打印出 Hello World 和代表我们加密文本的字节数组。

现在让我们尝试通过添加对 ioutil.WriteFile 的调用来将其写入文件,以代替我们最后的 fmt.Println 语句:

// the WriteFile method returns an error if unsuccessful
err = ioutil.WriteFile("myfile.data", gcm.Seal(nonce, nonce, text, nil), 0777)
// handle this error
if err != nil {
  // print it out
  fmt.Println(err)
}


有关在 Go 中读取和写入文件的更多信息,我建议您查看我恰当命名的文章 - 在 Go 中读取和写入文件。

测试一下


一旦我们完成对 encrypt.go 文件的这些更改,我们可以尝试对其进行测试:

$ go run encrypt.go


如果成功运行,您应该会在项目目录中看到一个名为 myfile.data 的新文件。如果你打开它,你应该会看到你的加密结果!

我们的解密客户端


既然我们已经介绍了加密并将我们的加密消息写入文件,现在让我们看看从该文件中读取并尝试使用相同的共享密钥对其进行解密。

我们将从使用 ioutil.ReadFile('myfile.data') 开始,以便将加密文本作为字节数组读取。一旦我们有了这个字节数组,我们随后就可以按照与加密方面非常相似的步骤进行操作。

  1. 首先,我们需要使用 aes.NewCipher 函数创建一个新的密码,传入我们的共享密钥作为它的主要参数。
  2. 接下来,我们需要生成我们的 GCM
  3. 之后,我们需要使用 gcm.NonceSize() 获取我们的 Nonce 大小
  4. 最后,我们将使用 gcm.Open() 函数解密我们的加密密文,该函数返回我们的明文和/或错误(如果有)。
package main

import (
    "crypto/aes"
    "crypto/cipher"
    "fmt"
    "io/ioutil"
)

func main() {
    fmt.Println("Decryption Program v0.01")

    key := []byte("passphrasewhichneedstobe32bytes!")
    ciphertext, err := ioutil.ReadFile("myfile.data")
    // if our program was unable to read the file
    // print out the reason why it can't
    if err != nil {
        fmt.Println(err)
    }

    c, err := aes.NewCipher(key)
    if err != nil {
        fmt.Println(err)
    }

    gcm, err := cipher.NewGCM(c)
    if err != nil {
        fmt.Println(err)
    }

    nonceSize := gcm.NonceSize()
    if len(ciphertext) < nonceSize {
        fmt.Println(err)
    }

    nonce, ciphertext := ciphertext[:nonceSize], ciphertext[nonceSize:]
    plaintext, err := gcm.Open(nil, nonce, ciphertext, nil)
    if err != nil {
        fmt.Println(err)
    }
    fmt.Println(string(plaintext))
}

测试一下


太棒了,所以现在我们已经完成了解密.go 程序的编写,我们可以尝试一下。

$ go run decrypt.go
Decryption Program v0.01
My Super Secret Code Stuff


从输出中可以看出,我们已经能够成功读取 myfile.data 文件的加密内容,然后使用我们的共享密钥对其进行解密。

挑战 - 加密文件系统


如果您对挑战感兴趣,测试您在本教程中学到的内容的一种很酷的方法是尝试扩展我们在上面创建的现有程序,以使用密码加密和解密提供给它的任何文件。

您可以将其转换为接受标志和文件路径作为输入并以加密形式将它们输出到您当前位置的 CLI。


结论


因此,在本教程中,我们成功地介绍了一些很酷的概念,例如对称加密算法,以及如何使用高级加密标准和密钥来加密和解密信息。

我写这篇文章很开心,希望你喜欢它!如果你这样做了,或者如果你有任何反馈,那么我很乐意在下面的评论部分听到它!

文章链接