Skip to content

Instantly share code, notes, and snippets.

@daison12006013
Last active May 17, 2024 08:50
Show Gist options
  • Save daison12006013/b8eff28902592c8e9f577874236f9e18 to your computer and use it in GitHub Desktop.
Save daison12006013/b8eff28902592c8e9f577874236f9e18 to your computer and use it in GitHub Desktop.
Encrypt/Obfuscate payload Javascript to Golang
package main
import (
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"encoding/binary"
"encoding/hex"
"encoding/json"
"fmt"
"io"
"log"
"net/http"
"runtime"
"time"
"github.com/patrickmn/go-cache"
)
var c = cache.New(3*time.Second, 5*time.Second)
type ErrorStatus struct {
Error error
Message string
Status int
}
func generateKeyHandler(w http.ResponseWriter, r *http.Request) {
key := make([]byte, 32)
if _, err := rand.Read(key); err != nil {
panic(ErrorStatus{
Error: err,
Message: "rand.Read(...) Error: " + err.Error(),
Status: http.StatusInternalServerError,
})
}
keyStr := hex.EncodeToString(key)
c.Set(keyStr, key, cache.DefaultExpiration)
json.NewEncoder(w).Encode(map[string]string{"key": keyStr})
}
func enableCors(w *http.ResponseWriter) {
(*w).Header().Set("Access-Control-Allow-Origin", "*")
(*w).Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")
(*w).Header().Set("Access-Control-Allow-Headers", "Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization")
}
type Payload struct {
Data string `json:"data"`
Key string `json:"key"`
}
func decryptData(encryptedData, key string) (map[string]interface{}, error) {
// Convert the hex-encoded key to bytes.
keyBytes, err := hex.DecodeString(key)
if err != nil {
return nil, fmt.Errorf("failed to decode key: %v", err)
}
// Convert the hex-encoded encrypted data to bytes.
encryptedBytes, err := hex.DecodeString(encryptedData)
if err != nil {
return nil, fmt.Errorf("failed to decode encrypted data: %v", err)
}
// Create the AES block cipher.
block, err := aes.NewCipher(keyBytes)
if err != nil {
return nil, fmt.Errorf("failed to create cipher: %v", err)
}
// Initialize the counter (CTR) mode with a starting value of 5.
// Creating the nonce with the initial counter value.
nonce := make([]byte, aes.BlockSize)
binary.BigEndian.PutUint64(nonce[aes.BlockSize-8:], uint64(5))
stream := cipher.NewCTR(block, nonce)
// Decrypt the data.
decryptedBytes := make([]byte, len(encryptedBytes))
stream.XORKeyStream(decryptedBytes, encryptedBytes)
// Convert the decrypted bytes to a string.
decryptedText := string(decryptedBytes)
// Parse the JSON from the decrypted string.
var result map[string]interface{}
err = json.Unmarshal([]byte(decryptedText), &result)
if err != nil {
return nil, fmt.Errorf("failed to unmarshal JSON: %v", err)
}
return result, nil
}
func payloadHandler(w http.ResponseWriter, r *http.Request) {
var payload Payload
body, err := io.ReadAll(r.Body)
if err != nil {
panic(ErrorStatus{
Error: err,
Message: "io.ReadAll(...) Error: " + err.Error(),
Status: http.StatusBadRequest,
})
}
err = json.Unmarshal(body, &payload)
if err != nil {
panic(ErrorStatus{
Error: err,
Message: "json.Unmarshal(...) Error: " + err.Error(),
Status: http.StatusBadRequest,
})
}
_, found := c.Get(payload.Key)
if !found {
panic(ErrorStatus{
Error: fmt.Errorf("invalid key"),
Message: "Invalid key",
Status: http.StatusBadRequest,
})
}
data, err := decryptData(payload.Data, payload.Key)
if err != nil {
panic(ErrorStatus{
Error: err,
Message: "decryptData(...) Error: " + err.Error(),
Status: http.StatusBadRequest,
})
}
// fmt.Fprintf(w, "Received data: %+v", json.MarshalIndent(data, "", " "))
json.NewEncoder(w).Encode(data)
w.Header().Set("Content-Type", "application/json")
}
func corsMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
enableCors(&w)
if r.Method == "OPTIONS" {
w.WriteHeader(http.StatusOK)
return
}
next.ServeHTTP(w, r)
})
}
func main() {
mux := http.NewServeMux()
mux.HandleFunc("/generate-key", generateKeyHandler)
mux.HandleFunc("/payload", payloadHandler)
handler := corsMiddleware(mux)
fmt.Println("Server is listening on port 8080...")
log.Fatal(http.ListenAndServe(":8080", logRequestErrors(handler)))
}
func logRequestErrors(handler http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
defer func() {
if err := recover(); err != nil {
errStatus, ok := err.(ErrorStatus)
if ok {
log.Printf("Request error: %v", errStatus.Message)
http.Error(w, errStatus.Message, errStatus.Status)
} else {
log.Printf("Unknown error: %v", err)
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
}
// Find the file and line number of the panic
const size = 64 << 10
buf := make([]byte, size)
buf = buf[:runtime.Stack(buf, false)]
_, file, line, _ := runtime.Caller(1)
fmt.Printf("\npanic occurred in file %s at line %d: %v: %s", file, line, err, buf)
}
}()
handler.ServeHTTP(w, r)
})
}
const apiUrl = 'http://localhost:8080';
async function getEncryptionKey() {
const response = await fetch(`${apiUrl}/generate-key`);
const data = await response.json();
return data.key;
}
function encryptData(data, key) {
let jsonBytes = aesjs.utils.utf8.toBytes(JSON.stringify(data));
let keyBytes = aesjs.utils.hex.toBytes(key);
let aesCtr = new aesjs.ModeOfOperation.ctr(keyBytes, new aesjs.Counter(5));
let encryptedBytes = aesCtr.encrypt(jsonBytes);
let encryptedData = aesjs.utils.hex.fromBytes(encryptedBytes);
return encryptedData;
}
async function sendDataToServer(data) {
const key = await getEncryptionKey();
const encryptedData = encryptData(data, key);
const response = await fetch(`${apiUrl}/payload`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ key: key, data: encryptedData })
});
if (response.ok) {
console.log('Data sent successfully.');
} else {
console.error('Error sending data.');
}
}
document.addEventListener('DOMContentLoaded', async () => {
var data = {
"name": "John Doe",
"email": "johndoe@email.com"
};
try {
await sendDataToServer(data);
} catch (error) {
console.error('Error:', error);
}
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment