Commit 707a1784 authored by Rosbit Xu's avatar Rosbit Xu

Initial commit

parents
Pipeline #1072 failed with stages
package aesutil
import (
"encoding/base64"
"encoding/json"
"net/http"
"bytes"
)
func NewAesEncryptor(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
aesKey := r.Header.Get("X-Aes-Key")
if len(aesKey) == 0 {
next(w, r)
return
}
arw := &aesResponseWriter{
aesKey: aesKey,
body: &bytes.Buffer{},
header: make(http.Header),
code: http.StatusOK,
}
next(arw, r)
arw.doFinal(w)
}
type aesResponseWriter struct {
aesKey string
body *bytes.Buffer
header http.Header
code int
wroteHeader bool
}
func (arw *aesResponseWriter) doFinal(w http.ResponseWriter) {
if arw.body.Len() > 0 {
arw.header.Set("X-Aes-Encrypted", "true")
arw.header.Set("Content-Type", "application/json")
}
h := w.Header()
for k, v := range arw.header {
for _, vv := range v {
h.Add(k, vv)
}
}
w.WriteHeader(arw.code)
// response body -> aes-crypt-with-key -> base64 encoded -> EncryptedMsg -> {"encrypted-msg": EncryptedMsg}
key, _ := base64.StdEncoding.DecodeString(arw.aesKey)
text := arw.body.Bytes()
if result, err := AesEncrypt(key, text); err == nil {
json.NewEncoder(w).Encode(map[string]interface{}{
"encrypted-msg": base64.StdEncoding.EncodeToString(result),
})
} else {
w.Write(text)
}
}
func (arw *aesResponseWriter) WriteHeader(code int) {
if arw.wroteHeader {
return
}
arw.wroteHeader = true
arw.code = code
}
func (arw *aesResponseWriter) Write(b []byte) (int, error) {
if !arw.wroteHeader {
arw.WriteHeader(http.StatusOK)
}
return arw.body.Write(b)
}
func (arw *aesResponseWriter) Header() http.Header {
return arw.header
}
package aesutil
import (
"github.com/rosbit/go-aes"
)
func AesEncrypt(key, text []byte) ([]byte, error) {
return goaes.AesEncrypt(text, key)
}
package rsautil
import (
"crypto/rsa"
"crypto/x509"
"encoding/pem"
"io/ioutil"
"fmt"
)
func ParsePrivateKey(priKeyFile string) (pri *rsa.PrivateKey, err error) {
b, e := ioutil.ReadFile(priKeyFile)
if e != nil {
err = e
return
}
block, _ := pem.Decode(b)
if block == nil {
err = fmt.Errorf("failed to parse %s", priKeyFile)
return
}
return x509.ParsePKCS1PrivateKey(block.Bytes)
}
func ParsePublicKey(pubKeyFile string) (pub *rsa.PublicKey, err error) {
b, e := ioutil.ReadFile(pubKeyFile)
if e != nil {
err = e
return
}
block, _ := pem.Decode(b)
if block == nil {
err = fmt.Errorf("failed to parse %s", pubKeyFile)
return
}
pubInterface, e := x509.ParsePKIXPublicKey(block.Bytes)
if e != nil {
err = e
return
}
if pub, ok := pubInterface.(*rsa.PublicKey); !ok {
return nil, fmt.Errorf("unknown format")
} else {
return pub, nil
}
}
package rsautil
import (
"crypto/rand"
"crypto/rsa"
)
type FnConvert func([]byte) ([]byte, error)
func CreatePrivateKeyDecryptor(privateKeyFile string) (FnConvert, error) {
priv, err := ParsePrivateKey(privateKeyFile)
if err != nil {
return nil, err
}
return func(cipherData []byte) (origData []byte, err error) {
return rsa.DecryptPKCS1v15(rand.Reader, priv, cipherData)
}, nil
}
func CreatePublicKeyEncryptor(publicKeyFile string) (FnConvert, error) {
pub, err := ParsePublicKey(publicKeyFile)
if err != nil {
return nil, err
}
return func(origData []byte) (cipherData []byte, err error) {
return rsa.EncryptPKCS1v15(rand.Reader, pub, origData)
}, nil
}
package rsautil
import (
"encoding/base64"
"encoding/json"
"io/ioutil"
"net/http"
"bytes"
"time"
)
// encrypt:
// JSON -> {"origin": JSON, "aes-key": "random-key-base64-encoded", "timestamp": xxx} -> RSA crypted with public key -> Base64 encoded
// -> EncryptedMsg -> {"encrypted-msg": EncryptedMsg}
//
// decrpt:
// {"encrypted-msg": EncryptedMsg} -> EncryptedMsg -> Base64 decoded -> RSA decrypted with private key
// -> {"origin": JSON, "aes-key": "random-key-base64-encoded", "timestamp": xxx} -> JSON & random-aes-key-base64-encoded
func RsaPrivateDecryptor(privateKeyFile string) func(http.ResponseWriter, *http.Request, http.HandlerFunc) {
rsaDecrypt, err := CreatePrivateKeyDecryptor(privateKeyFile)
if err != nil {
panic(err)
}
return func(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
if r.Body == nil {
next(w, r)
return
}
if r.Header.Get("Content-Type") != "application/json" {
next(w, r)
return
}
copiedBody, err := ioutil.ReadAll(r.Body)
if err != nil {
next(w, r)
return
}
var encBody struct {
EncrytedMsg string `json:"encrypted-msg"`
}
if err = json.Unmarshal(copiedBody, &encBody); err != nil {
r.Body = ioutil.NopCloser(bytes.NewReader(copiedBody))
next(w, r)
return
}
if len(encBody.EncrytedMsg) == 0 {
r.Body = ioutil.NopCloser(bytes.NewReader(copiedBody))
next(w, r)
return
}
eBody, err := base64.StdEncoding.DecodeString(encBody.EncrytedMsg)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
plainBody, err := rsaDecrypt(eBody)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
var j struct {
Origin map[string]interface{} `json:"origin"`
AesKey string `json:"aes-key"`
Timestamp int64 `json:"timestamp"`
}
if err = json.Unmarshal(plainBody, &j); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
if j.Origin == nil {
http.Error(w, "no origin item", http.StatusBadRequest)
return
}
if len(j.AesKey) == 0 {
http.Error(w, "no aes-key item", http.StatusBadRequest)
return
}
timestamp := time.Unix(j.Timestamp, 0)
now := time.Now()
minTime, maxTime := now.Add(-10 * time.Second), now.Add(5 * time.Second)
if timestamp.Before(minTime) {
http.Error(w, "timestamp expired", http.StatusBadRequest)
return
}
if timestamp.After(maxTime) {
http.Error(w, "future timestamp", http.StatusBadRequest)
return
}
originJson, _ := json.Marshal(j.Origin)
r.ContentLength = int64(len(originJson))
r.Body = ioutil.NopCloser(bytes.NewReader(originJson))
r.Header.Set("X-Aes-Key", j.AesKey)
next(w, r)
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment