Skip to content

Instantly share code, notes, and snippets.

@Myestery
Last active December 29, 2023 13:17
Show Gist options
  • Save Myestery/8b16dece79b1066799a09b834a6e00ce to your computer and use it in GitHub Desktop.
Save Myestery/8b16dece79b1066799a09b834a6e00ce to your computer and use it in GitHub Desktop.
Golang AES 2 way encryption
package main
import (
"bytes"
"crypto/aes"
"crypto/cipher"
"encoding/base64"
"encoding/json"
"flag"
"fmt"
"os"
)
// OperationResult represents the result of an encryption or decryption operation
type OperationResult struct {
Result string `json:"result"`
Status bool `json:"status"`
Error string `json:"error,omitempty"`
}
// GetAESDecrypted decrypts given text in AES 256 CBC
func GetAESDecrypted(encrypted string, key string, iv string) (*OperationResult, *OperationResult) {
ciphertext, err := base64.StdEncoding.DecodeString(encrypted)
if err != nil {
return nil, &OperationResult{Status: false, Error: err.Error()}
}
block, err := aes.NewCipher([]byte(key))
if err != nil {
return nil, &OperationResult{Status: false, Error: err.Error()}
}
if len(ciphertext)%aes.BlockSize != 0 {
return nil, &OperationResult{Status: false, Error: "block size must be a multiple of 16"}
}
mode := cipher.NewCBCDecrypter(block, []byte(iv))
mode.CryptBlocks(ciphertext, ciphertext)
ciphertext = PKCS5UnPadding(ciphertext)
return &OperationResult{Result: string(ciphertext), Status: true}, nil
}
// PKCS5UnPadding pads a certain blob of data with necessary data to be used in AES block cipher
func PKCS5UnPadding(src []byte) []byte {
length := len(src)
unpadding := int(src[length-1])
return src[:(length - unpadding)]
}
// GetAESEncrypted encrypts given text in AES 256 CBC
func GetAESEncrypted(plaintext string, key string, iv string) (*OperationResult, *OperationResult) {
var plainTextBlock []byte
length := len(plaintext)
if length%16 != 0 {
extendBlock := 16 - (length % 16)
plainTextBlock = make([]byte, length+extendBlock)
copy(plainTextBlock[length:], bytes.Repeat([]byte{uint8(extendBlock)}, extendBlock))
} else {
plainTextBlock = make([]byte, length)
}
copy(plainTextBlock, plaintext)
block, err := aes.NewCipher([]byte(key))
if err != nil {
return nil, &OperationResult{Status: false, Error: err.Error()}
}
ciphertext := make([]byte, len(plainTextBlock))
mode := cipher.NewCBCEncrypter(block, []byte(iv))
mode.CryptBlocks(ciphertext, plainTextBlock)
result := base64.StdEncoding.EncodeToString(ciphertext)
return &OperationResult{Result: result, Status: true}, nil
}
func main() {
var (
plainText string
key string
iv string
encrypt bool
decrypt bool
)
flag.StringVar(&plainText, "text", "", "Text to encrypt or decrypt")
flag.StringVar(&key, "key", "my32digitkey12345678901234567890", "Encryption key (32 characters)")
flag.StringVar(&iv, "iv", "my16digitIvKey12", "Initialization vector (16 characters)")
flag.BoolVar(&encrypt, "encrypt", false, "Encrypt mode")
flag.BoolVar(&decrypt, "decrypt", false, "Decrypt mode")
flag.Parse()
if plainText == "" {
fmt.Println("Error: Specify the text using the -text flag.")
os.Exit(1)
}
if encrypt && decrypt {
fmt.Println("Error: Choose either -encrypt or -decrypt, not both.")
os.Exit(1)
}
if encrypt {
result, err := GetAESEncrypted(plainText, key, iv)
if err != nil {
resultJSON, _ := json.Marshal(err)
fmt.Println(string(resultJSON))
os.Exit(0)
}
resultJSON, _ := json.Marshal(result)
fmt.Println(string(resultJSON))
} else if decrypt {
result, err := GetAESDecrypted(plainText, key, iv)
if err != nil {
resultJSON, _ := json.Marshal(err)
fmt.Println(string(resultJSON))
os.Exit(0)
}
resultJSON, _ := json.Marshal(result)
fmt.Println(string(resultJSON))
} else {
fmt.Println("Error: Choose either -encrypt or -decrypt.")
os.Exit(0)
}
}
// go run crypto.go -decrypt -text "7xIb/yiNp8JsPQlmNhIk9Q==" -key "my32digitkey12345678901234567890" -iv "my16digitIvKey12"
// go run crypto.go -encrypt "xxxx" -key "|<b631h<f8nH7nGy4<8dO0TW{\)LPWq3" -iv "*e6-pyQyT9X2%HsI"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment