mirror of
https://github.com/darmiel/yaxc.git
synced 2024-09-20 06:46:13 +08:00
Implemented encryption (#2)
This commit is contained in:
parent
1c9ca72384
commit
92a2259f30
86
internal/common/encryption.go
Normal file
86
internal/common/encryption.go
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
package common
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto/aes"
|
||||||
|
"crypto/cipher"
|
||||||
|
"crypto/rand"
|
||||||
|
"encoding/base64"
|
||||||
|
"errors"
|
||||||
|
"io"
|
||||||
|
"math"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
errKeyEmpty = errors.New("key empty")
|
||||||
|
errKeyLength = errors.New("invalid key length")
|
||||||
|
errNonceLength = errors.New("invalid nonce length")
|
||||||
|
bytesEmpty []byte
|
||||||
|
)
|
||||||
|
|
||||||
|
func Encrypt(textStr, keyStr string) (res []byte, err error) {
|
||||||
|
gcm, err := getGCM(keyStr)
|
||||||
|
if err != nil {
|
||||||
|
return bytesEmpty, err
|
||||||
|
}
|
||||||
|
nonce := make([]byte, gcm.NonceSize())
|
||||||
|
if _, err = io.ReadFull(rand.Reader, nonce); err != nil {
|
||||||
|
return bytesEmpty, err
|
||||||
|
}
|
||||||
|
seal := gcm.Seal(nonce, nonce, []byte(textStr), nil)
|
||||||
|
res = []byte(base64.StdEncoding.EncodeToString(seal))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func Decrypt(textStr, keyStr string) (res []byte, err error) {
|
||||||
|
text, err := base64.StdEncoding.DecodeString(textStr)
|
||||||
|
if err != nil {
|
||||||
|
return bytesEmpty, err
|
||||||
|
}
|
||||||
|
gcm, err := getGCM(keyStr)
|
||||||
|
if err != nil {
|
||||||
|
return bytesEmpty, err
|
||||||
|
}
|
||||||
|
nonceSize := gcm.NonceSize()
|
||||||
|
if len(text) < nonceSize {
|
||||||
|
return bytesEmpty, errNonceLength
|
||||||
|
}
|
||||||
|
nonce, encrypted := text[:nonceSize], text[nonceSize:]
|
||||||
|
plain, err := gcm.Open(nil, nonce, encrypted, nil)
|
||||||
|
if err != nil {
|
||||||
|
return bytesEmpty, err
|
||||||
|
}
|
||||||
|
return plain, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
////
|
||||||
|
|
||||||
|
func getGCM(keyStr string) (cipher.AEAD, error) {
|
||||||
|
key, err := getKey(keyStr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
block, err := aes.NewCipher(key)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return cipher.NewGCM(block)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getKey(keyStr string) (key []byte, err error) {
|
||||||
|
key = []byte(keyStr)
|
||||||
|
if len(key) <= 0 {
|
||||||
|
return key, errKeyEmpty
|
||||||
|
}
|
||||||
|
if len(key) < 32 {
|
||||||
|
rep := math.Ceil(32.0 / float64(len(keyStr)))
|
||||||
|
key = bytes.Repeat([]byte(keyStr), int(rep))
|
||||||
|
}
|
||||||
|
if len(key) > 32 {
|
||||||
|
key = key[:32]
|
||||||
|
}
|
||||||
|
if len(key) != 32 {
|
||||||
|
return key, errKeyLength
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
package server
|
package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/darmiel/yaxc/internal/common"
|
||||||
"github.com/gofiber/fiber/v2"
|
"github.com/gofiber/fiber/v2"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
@ -8,32 +9,43 @@ import (
|
||||||
func (s *yAxCServer) handlePostAnywhere(ctx *fiber.Ctx) (err error) {
|
func (s *yAxCServer) handlePostAnywhere(ctx *fiber.Ctx) (err error) {
|
||||||
path := ctx.Params("anywhere")
|
path := ctx.Params("anywhere")
|
||||||
|
|
||||||
|
// Read content
|
||||||
bytes := ctx.Body()
|
bytes := ctx.Body()
|
||||||
if s.MaxBodyLength > 0 && len(bytes) > s.MaxBodyLength {
|
if s.MaxBodyLength > 0 && len(bytes) > s.MaxBodyLength {
|
||||||
return s.errBodyLen
|
return s.errBodyLen
|
||||||
}
|
}
|
||||||
content := string(bytes)
|
content := string(bytes)
|
||||||
|
|
||||||
// custom ttl
|
// TTL
|
||||||
ttl := s.DefaultTTL
|
ttl := s.DefaultTTL
|
||||||
|
|
||||||
if q := ctx.Query("ttl"); q != "" {
|
if q := ctx.Query("ttl"); q != "" {
|
||||||
if ttl, err = time.ParseDuration(q); err != nil {
|
if ttl, err = time.ParseDuration(q); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if ttl is valid
|
// Encryption
|
||||||
|
if q := ctx.Query("secret"); q != "" {
|
||||||
|
// fail on error
|
||||||
|
encrypt, err := common.Encrypt(content, q)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
content = string(encrypt)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if ttl is valid
|
||||||
if (s.MinTTL != 0 && s.MinTTL > ttl) || (s.MaxTTL != 0 && s.MaxTTL < ttl) {
|
if (s.MinTTL != 0 && s.MinTTL > ttl) || (s.MaxTTL != 0 && s.MaxTTL < ttl) {
|
||||||
return ctx.Status(400).SendString("ERROR: TTL out of range")
|
return ctx.Status(400).SendString("ERROR: TTL out of range")
|
||||||
}
|
}
|
||||||
|
|
||||||
// set contents
|
// Set contents
|
||||||
if err := s.Backend.Set(path, content, ttl); err != nil {
|
if err := s.Backend.Set(path, content, ttl); err != nil {
|
||||||
return ctx.Status(400).SendString("ERROR: " + err.Error())
|
return ctx.Status(400).SendString("ERROR: " + err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Info("Received", content, "to", path, "with a ttl of", ttl)
|
log.Debug(ctx.IP(), "updated", path)
|
||||||
|
|
||||||
return ctx.Status(200).SendString(content)
|
return ctx.Status(200).SendString(content)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,7 +55,16 @@ func (s *yAxCServer) handleGetAnywhere(ctx *fiber.Ctx) (err error) {
|
||||||
if res, err = s.Backend.Get(path); err != nil {
|
if res, err = s.Backend.Get(path); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
log.Info("Send", res, "to", ctx.IP(), "requesting", path)
|
|
||||||
|
// Encryption
|
||||||
|
if q := ctx.Query("secret"); q != "" {
|
||||||
|
// do not fail on error
|
||||||
|
if encrypt, err := common.Decrypt(res, q); err == nil {
|
||||||
|
res = string(encrypt)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debug(ctx.IP(), "requested", path)
|
||||||
|
|
||||||
if res == "" {
|
if res == "" {
|
||||||
ctx.Status(404)
|
ctx.Status(404)
|
||||||
|
|
Loading…
Reference in a new issue