In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-01-17 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)05/31 Report--
This article mainly introduces the relevant knowledge of "how to encrypt and decrypt files with go GCM gin middleware". The editor shows you the operation process through an actual case. The operation method is simple, fast and practical. I hope this article "how to encrypt and decrypt files with go GCM gin middleware" can help you solve the problem.
Encryption and decryption of aes's gcm mode
To enable encryption and decryption for existing systems, it is currently recommended to encrypt and decrypt aes's gcm mode. In microservices, if there are public methods to deal with reading data and writing returned data, it is relatively simple to modify the previous public methods, but in this way, local debugging is definitely plaintext, so it is necessary to judge that if the previous read data and write data are varied, it will be troublesome. Generally speaking, there is a gateway service in the micro-service system, so encryption and decryption are placed on the gateway service, roughly as follows:
Regular requests include GET,POST JSON, POST file, and POST Form forms, which usually return json or download file streams, so we need to intercept the request stream and return stream, receive the request flow decryption data and then rewrite it to the request stream, receive return stream encrypted data, and rewrite the return stream.
First, let's look at the aes encryption and decryption program aes.go.
Package aesimport ("crypto/aes"crypto/cipher"crypto/md5"crypto/rand"encoding/base64"encoding/hex"errors"io") / / encrypted string func GcmEncrypt (key, plaintext string) (string Error) {if len (key)! = 32 & & len (key)! = 24 & & len (key)! = 16 {return ", errors.New (" the length of key is error ")} if len (plaintext)
< 1 { return "", errors.New("plaintext is null") } keyByte := []byte(key) plainByte:=[]byte(plaintext) block, err := aes.NewCipher(keyByte) if err != nil { return "", err } aesGcm, err := cipher.NewGCM(block) if err != nil { return "", err } nonce := make([]byte, 12) if _, err := io.ReadFull(rand.Reader, nonce); err != nil { return "", err } seal := aesGcm.Seal(nonce, nonce, plainByte, nil) return base64.URLEncoding.EncodeToString(seal), nil}//解密字符串func GcmDecrypt(key, cipherText string) (string, error) { if len(key) != 32 && len(key) != 24 && len(key) != 16 { return "", errors.New("the length of key is error") } if len(cipherText) < 1 { return "", errors.New("cipherText is null") } cipherByte, err := base64.URLEncoding.DecodeString(cipherText) if err != nil { return "", err } if len(cipherByte) < 12 { return "", errors.New("cipherByte is error") } nonce, cipherByte := cipherByte[:12], cipherByte[12:] keyByte := []byte(key) block, err := aes.NewCipher(keyByte) if err != nil { return "", err } aesGcm, err := cipher.NewGCM(block) if err != nil { return "", err } plainByte, err := aesGcm.Open(nil, nonce, cipherByte, nil) if err != nil { return "", err } return string(plainByte), nil}//生成32位md5字串func GetAesKey(s string) string { h := md5.New() h.Write([]byte(s)) return hex.EncodeToString(h.Sum(nil))} 再来看看网关转发程序proxy.go package middlewareimport ( "fmt" "github.com/gin-gonic/gin" "github.com/valyala/fasthttp" "io/ioutil" "runtime/debug" "time")var fastClient *fasthttp.Clientfunc init() { fastClient = &fasthttp.Client{} fastClient.MaxIdemponentCallAttempts = 1 fastClient.ReadTimeout = time.Second * 60}func GetHttpClient() *fasthttp.Client { return fastClient}func GateWay() gin.HandlerFunc { return func(c *gin.Context) { defer func() { if e := recover(); e != nil { stack := debug.Stack() log("GateWay Recovery: err:%v, stack:%v", e, string(stack)) } }() err := Forward(c) if err != nil { response(c, 9999, "系统错误", err.Error()) } return }}func Forward(ctx *gin.Context) error { req := &fasthttp.Request{} //请求-获取服务地址 host := "http://localhost:8000/" + ctx.Request.URL.String() //请求-url req.SetRequestURI(host) //请求-header for k, v := range ctx.Request.Header { req.Header.Set(k, v[0]) } //请求-body data, err := ioutil.ReadAll(ctx.Request.Body) if err != nil { log("Forward err:%v", err) return fmt.Errorf("系统错误") } req.SetBody(data) //请求-方法 req.Header.SetMethod(ctx.Request.Method) //请求-发送 resp := &fasthttp.Response{} //请求-新增调用链 /* err = opentracing.GlobalTracer().Inject( opentracing.SpanFromContext(ctx.Request.Context()).Context(), opentracing.TextMap, HTTPHeadersCarrier{&req.Header}, ) */ err = GetHttpClient().Do(req, resp) if err != nil { log("Forward GetHttpClient DO err:%v", err) return fmt.Errorf("系统错误") } //请求-响应 ContentType := fmt.Sprintf("%s", resp.Header.Peek("Content-Type")) ctx.Data(resp.StatusCode(), ContentType, resp.Body()) return nil}type HTTPHeadersCarrier struct { *fasthttp.RequestHeader}func (c HTTPHeadersCarrier) Set(key, val string) { h := c.RequestHeader h.Add(key, val)} 最后来看一下gin的中间件crypto.go package middlewareimport ( "bytes" "demo/aes" "encoding/json" "errors" "fmt" "github.com/gin-gonic/gin" "io" "io/ioutil" "mime" "mime/multipart" "net/url" "runtime/debug" "strconv" "strings")type aesWriter struct { gin.ResponseWriter body *bytes.Buffer}func (w *aesWriter) Write(b []byte) (int, error) { return w.body.Write(b)}func (w *aesWriter) WriteString(s string) (int, error) { return w.body.WriteString(s)}//只有经过token 验证的才会加密 和解密//handleFile 表示是否处理上传文件, 默认网关不处理上传文件的encryptString数据, 如果处理会导致具体服务无法接收到具体参数func AesGcmDecrypt() gin.HandlerFunc { return func(c *gin.Context) { defer func() { if e := recover(); e != nil { stack := debug.Stack() log("AesGcmDecrypt Recovery: err:%v, stack:%v", e, string(stack)) } }() if c.Request.Method == "OPTIONS" { c.Next() } else { md5key := aes.GetAesKey("gavin12345678") log("AesGcmDecrypt start url:%s ,md5key:%s, Method:%s, Header:%+v", c.Request.URL.String(), md5key, c.Request.Method, c.Request.Header) handleAes(c, md5key) } }}//请求和返回都加密 解密func handleAes(c *gin.Context, md5key string) { contentType := c.Request.Header.Get("Content-Type") isJsonRequest := strings.Contains(contentType, "application/json") isFileRequest := strings.Contains(contentType, "multipart/form-data") isFormUrl := strings.Contains(contentType, "application/x-www-form-urlencoded") if c.Request.Method == "GET" { err := parseQuery(c, md5key) if err != nil { log("handleAes parseQuery err:%v", err) //这里输出应该密文 一旦加密解密调试好 这里就不会走进来 response(c, 2001, "系统错误", err.Error()) return } } else if isJsonRequest { err := parseJson(c, md5key) if err != nil { log("handleAes parseJson err:%v", err) //这里输出应该密文 一旦加密解密调试好 这里就不会走进来 response(c, 2001, "系统错误", err.Error()) return } } else if isFormUrl { err := parseForm(c, md5key) if err != nil { log("handleAes parseForm err:%v", err) //这里输出应该密文 一旦加密解密调试好 这里就不会走进来 response(c, 2001, "系统错误", err.Error()) return } } else if isFileRequest { err := parseFile(c, md5key) if err != nil { log("handleAes parseFile err:%v", err) //这里输出应该密文 一旦加密解密调试好 这里就不会走进来 response(c, 2001, "系统错误", err.Error()) return } } ///截取 response body oldWriter := c.Writer blw := &aesWriter{body: bytes.NewBufferString(""), ResponseWriter: c.Writer} c.Writer = blw // 走流程 c.Next() ///获取返回数据 responseByte := blw.body.Bytes() //日志 c.Writer = oldWriter //如果返回的不是json格式 那么直接返回,应为文件下载之类的不应该加密 if !isJsonResponse(c) { _, _ = c.Writer.Write(responseByte) return } ///加密 encryptStr, err := aes.GcmEncrypt(md5key, string(responseByte)) if err != nil { log("handleAes GcmEncrypt err:%v", err) response(c, 2001, "系统错误", err.Error()) return } _, _ = c.Writer.WriteString(encryptStr)}//处理jsonfunc parseJson(c *gin.Context, md5key string) error { //读取数据 body处理 payload, err := c.GetRawData() if err != nil { return err } ///解密body数据 请求的json是{"encryptString":{value}} value含有gcm的12字节nonce,实际长度大于32 if payload != nil && len(payload) >Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.