本例将使用一个 golang 的rest接口 接收一个文件上传,然后保存文件到磁盘
先来看golang的rest,不加密的情况
package main
import (
"fmt"
"io"
"net/http"
"os"
)
func main() {
http.HandleFunc("/hello", doLogic)
http.ListenAndServe(":3070", nil)
}
func doLogic(w http.ResponseWriter, r *http.Request) {
r.ParseMultipartForm(32 << 20) // 32MB
file, handler, err := r.FormFile("myfile")
if err != nil {
fmt.Println(err)
return
}
defer file.Close()
fmt.Fprintf(w, "%v", handler.Header)
f, err := os.OpenFile("/tmp2/"+handler.Filename, os.O_WRONLY|os.O_CREATE, 0666)
if err != nil {
fmt.Println(err)
return
}
defer f.Close()
io.Copy(f, file)
}
然后使用postman来上传一个helloworld文件
{
"info": {
"_postman_id": "a4becb7c-5daf-491a-991d-1e93d451a28d",
"name": "New Collection",
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
},
"item": [
{
"name": "New Request",
"request": {
"method": "POST",
"header": [
{
"key": "Content-Type",
"value": "multipart/form-data",
"type": "text"
}
],
"body": {
"mode": "formdata",
"formdata": [
{
"key": "myfile",
"type": "file",
"src": "/Users/lizhe/helloworld.txt"
}
]
},
"url": {
"raw": "192.168.194.191:3070/hello",
"host": [
"192",
"168",
"194",
"191"
],
"port": "3070",
"path": [
"hello"
]
}
},
"response": []
}
]
}
检查一下上传进来的内容
下面我们来创建 encrypt.go , 用来加密
package main
import (
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"fmt"
"io"
"io/ioutil"
)
func main() {
fmt.Println("Encryption Program v0.01")
text := []byte("this is a message need to be encrypted")
key := []byte("thisismypassword")
// 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))
// 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)
}
}
decrypt.go 用来解密
package main
import (
"crypto/aes"
"crypto/cipher"
"fmt"
"io/ioutil"
)
func main() {
fmt.Println("Decryption Program v0.01")
key := []byte("thisismypassword")
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))
}
密码错误的情况
密码正确的情况
最后把 main.go 、encrypt.go 和 encrypt.go 整合一下
main.go
package main
import (
"fmt"
"io"
"net/http"
"os"
)
func main() {
http.HandleFunc("/hello", doLogic)
http.ListenAndServe(":3070", nil)
}
func doLogic(w http.ResponseWriter, r *http.Request) {
r.ParseMultipartForm(32 << 20) // 32MB
sourceFile, handler, err := r.FormFile("myfile")
if err != nil {
fmt.Println(err)
return
}
defer sourceFile.Close()
fmt.Fprintf(w, "%v", handler.Header)
filePath := "/tmp2/" + handler.Filename
targetFile, err := os.OpenFile(filePath, os.O_WRONLY|os.O_CREATE, 0666)
if err != nil {
fmt.Println(err)
return
}
defer targetFile.Close()
io.Copy(targetFile, sourceFile)
rawContent := GetFileContent(filePath)
Encrypt(rawContent)
Decrypt("myfile.data")
}
fileUtil.go
package main
import (
"fmt"
"io/ioutil"
"os"
)
func GetFileContent(filePath string) []byte {
file, err := os.Open(filePath)
if err != nil {
panic(err)
}
defer file.Close()
content, _ := ioutil.ReadAll(file)
fmt.Println(string(content))
return []byte(string(content))
}
encrypt.go
package main
import (
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"fmt"
"io"
"io/ioutil"
)
func Encrypt(text []byte) {
fmt.Println("Encryption Program v0.01")
// text := []byte("this is a message need to be encrypted")
key := []byte("thisismypassword")
// 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))
// 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)
}
}
decrypt.go
package main
import (
"crypto/aes"
"crypto/cipher"
"fmt"
"io/ioutil"
)
func Decrypt(filePath string) {
fmt.Println("Decryption Program v0.01")
key := []byte("thisismypassword")
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))
}
在这个例子中,使用了golang的 AES 包
使用 postman 上传文件之后,会保存一个临时文件到服务器上,然后使用AES对文件内容加密,最后我们使用了decrypt.go 对内容进行了解密