Last active
September 2, 2024 03:48
-
-
Save thinkclay/5760bd05cf18df2be2ef to your computer and use it in GitHub Desktop.
Basic Encryption and Decryption with a Golang Web Server Application
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"crypto/aes" | |
"crypto/cipher" | |
"encoding/base64" | |
"fmt" | |
"io/ioutil" | |
"log" | |
"net/http" | |
) | |
func main() { | |
/** | |
* GET or POST /server | |
* | |
* All requests will come through the /server route | |
* Each request should have a public key header and payload body | |
*/ | |
http.HandleFunc("/server", root) | |
log.Println("Listening for connections...") | |
log.Fatal(http.ListenAndServe(":3000", nil)) | |
} | |
func root(w http.ResponseWriter, r *http.Request) { | |
/** | |
* Public Key | |
* | |
* If we don't have an api key in the header, then we can't fulfill this request | |
* | |
* Normally we would lookup and retrieve our private key from a database | |
* using the public key to find the record, but for now, we'll just make certain | |
* that a public key is passed and use a fixed private key and initialization vector | |
*/ | |
publicKey := r.Header.Get("publicKey") | |
privateKey := []byte("53d07a9c3566360002020001") | |
initializationVector := []byte("53a1c59f62393700")[:aes.BlockSize] | |
if len(publicKey) == 0 { | |
Responder(w, r, 412, "The 'publicKey' request header was not found") | |
return | |
} | |
/** | |
* Received Payload | |
* | |
* Ensure that we received a payload and that | |
* the payload is encrypted with the private key | |
*/ | |
payload, err := ioutil.ReadAll(r.Body) | |
if err != nil || string(payload) == "" { | |
Responder(w, r, 422, "The request body was empty or unprocessable") | |
return | |
} | |
fmt.Println("\n\nPayload: ", string(payload)) | |
/** | |
* Encrypt the insecure payload | |
* | |
* We allocate the bytes array that represent both the encrypted and decrypted data | |
*/ | |
encrypted := make([]byte, len(payload)) | |
err = encrypt(encrypted, payload, privateKey, initializationVector) | |
if err != nil { | |
panic(err) | |
} | |
fmt.Println("\nEncrypted Payload: ", encode(encrypted)) | |
/** | |
* Decrypt the encrypted payload | |
*/ | |
decrypted := make([]byte, len(payload)) | |
err = decrypt(decrypted, encrypted, privateKey, initializationVector) | |
if err != nil { | |
panic(err) | |
} | |
fmt.Println("\nDecrypted Payload: ", string(decrypted)) | |
// Return the encrypted data to the sender | |
fmt.Fprintf(w, encode(encrypted)) | |
} | |
/** | |
* HTTP Error Handler | |
* | |
* Set the http status code and provide an error message | |
*/ | |
func Responder(w http.ResponseWriter, r *http.Request, status int, message string) { | |
w.WriteHeader(status) | |
log.Println(message) | |
fmt.Fprintf(w, message) | |
} | |
func encode(b []byte) string { | |
return base64.StdEncoding.EncodeToString(b) | |
} | |
func decode(s string) []byte { | |
data, err := base64.StdEncoding.DecodeString(s) | |
if err != nil { | |
panic(err) | |
} | |
return data | |
} | |
func encrypt(dst, src, key, iv []byte) error { | |
aesBlockEncryptor, err := aes.NewCipher([]byte(key)) | |
if err != nil { | |
return err | |
} | |
aesEncrypter := cipher.NewCFBEncrypter(aesBlockEncryptor, iv) | |
aesEncrypter.XORKeyStream(dst, src) | |
return nil | |
} | |
func decrypt(dst, src, key, iv []byte) error { | |
aesBlockEncryptor, err := aes.NewCipher([]byte(key)) | |
if err != nil { | |
return err | |
} | |
aesEncrypter := cipher.NewCFBEncrypter(aesBlockEncryptor, iv) | |
aesEncrypter.XORKeyStream(dst, src) | |
return nil | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment