Skip to content

Commit 2ae1bdf

Browse files
committed
Add AES encryption and decryption commands for inventory management
1 parent 238fb2c commit 2ae1bdf

File tree

2 files changed

+145
-1
lines changed

2 files changed

+145
-1
lines changed

cmd/main.go

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,60 @@ var agentRunWorkflowCmd = &cobra.Command{
5353
},
5454
}
5555

56+
var inventoryCmd = &cobra.Command{
57+
Use: "inventory",
58+
Short: "Manage inventory with AES encryption",
59+
}
60+
61+
var encryptInventoryCmd = &cobra.Command{
62+
Use: "encrypt",
63+
Run: func(cmd *cobra.Command, args []string) {
64+
inventoryFile, _ := cmd.Flags().GetString("inventory")
65+
encryptionKey, _ := cmd.Flags().GetString("encryption-key")
66+
67+
encryptedInventory, err := storm.NewInventory().Encrypt(inventoryFile, encryptionKey)
68+
if err != nil {
69+
fmt.Println(err)
70+
71+
os.Exit(1)
72+
}
73+
74+
fmt.Println(*encryptedInventory)
75+
},
76+
}
77+
78+
var decryptInventoryCmd = &cobra.Command{
79+
Use: "decrypt",
80+
Run: func(cmd *cobra.Command, args []string) {
81+
encryptedInventory, _ := cmd.Flags().GetString("encrypted-inventory")
82+
encryptionKey, _ := cmd.Flags().GetString("encryption-key")
83+
format, _ := cmd.Flags().GetString("format")
84+
85+
var byteEncryptedInventory []byte
86+
var err error
87+
88+
if format == "file" {
89+
byteEncryptedInventory, err = os.ReadFile(encryptedInventory)
90+
if err != nil {
91+
fmt.Println(err)
92+
93+
os.Exit(1)
94+
}
95+
} else {
96+
byteEncryptedInventory = []byte(encryptedInventory)
97+
}
98+
99+
decryptedInventory, err := storm.NewInventory().Decrypt(string(byteEncryptedInventory), encryptionKey)
100+
if err != nil {
101+
fmt.Println(err)
102+
103+
os.Exit(1)
104+
}
105+
106+
fmt.Println(*decryptedInventory)
107+
},
108+
}
109+
56110
var agentInstallCmd = &cobra.Command{
57111
Use: "install",
58112
Run: func(cmd *cobra.Command, args []string) {
@@ -128,6 +182,16 @@ func main() {
128182
agentRunWorkflowCmd.Flags().IntP("format", "f", 1, "available options are; 1 => plain, 2 => struct, 3 => json")
129183
agentCmd.AddCommand(agentRunWorkflowCmd)
130184

185+
inventoryCmd.AddCommand(encryptInventoryCmd)
186+
encryptInventoryCmd.Flags().StringP("inventory", "i", "./inventory.yaml", "formatio storm inventory")
187+
188+
inventoryCmd.AddCommand(decryptInventoryCmd)
189+
decryptInventoryCmd.Flags().StringP("encrypted-inventory", "e", "./inventory.yaml.enc", "encrypted inventory file")
190+
decryptInventoryCmd.Flags().StringP("format", "f", "file", "available options are; plain, file")
191+
192+
inventoryCmd.PersistentFlags().StringP("encryption-key", "k", "", "encryption key")
193+
rootCmd.AddCommand(inventoryCmd)
194+
131195
runWorkflowCmd.Flags().BoolP("trash-workflow", "t", true, "remove workflow file if the workflow is complete")
132196
runWorkflowCmd.Flags().StringP("directory", "d", ".", "directory to run the workflow from")
133197
runWorkflowCmd.Flags().IntP("format", "f", 1, "available options are; 1 => plain, 2 => struct, 3 => json")

inventory.go

Lines changed: 81 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,20 @@
11
package storm
22

33
import (
4+
"crypto/aes"
5+
"crypto/cipher"
6+
"crypto/rand"
7+
"encoding/base64"
8+
"errors"
9+
"io"
410
"os"
511

612
"gopkg.in/yaml.v3"
713
)
814

915
type Inventory struct{}
1016

11-
func (c *Inventory) Load(file string) (*InventoryConfig, error) {
17+
func (i *Inventory) Load(file string) (*InventoryConfig, error) {
1218
fileContent, err := os.ReadFile(file)
1319
if err != nil {
1420
return nil, err
@@ -24,6 +30,80 @@ func (c *Inventory) Load(file string) (*InventoryConfig, error) {
2430
return config, nil
2531
}
2632

33+
func (i *Inventory) aes(encryptionKey string) (cipher.AEAD, error) {
34+
key := []byte(encryptionKey)
35+
if len(key) != 16 && len(key) != 24 && len(key) != 32 {
36+
return nil, errors.New("encryption key must be 16, 24, or 32 bytes long")
37+
}
38+
39+
block, err := aes.NewCipher(key)
40+
if err != nil {
41+
return nil, err
42+
}
43+
44+
gcm, err := cipher.NewGCM(block)
45+
if err != nil {
46+
return nil, err
47+
}
48+
49+
return gcm, nil
50+
}
51+
52+
func (i *Inventory) Encrypt(file string, encryptionKey string) (*string, error) {
53+
fileContent, err := os.ReadFile(file)
54+
if err != nil {
55+
return nil, err
56+
}
57+
58+
gcm, err := i.aes(encryptionKey)
59+
if err != nil {
60+
return nil, err
61+
}
62+
63+
// Create a nonce of the correct size
64+
nonce := make([]byte, gcm.NonceSize())
65+
if _, err := io.ReadFull(rand.Reader, nonce); err != nil {
66+
return nil, err
67+
}
68+
69+
// Encrypt and prepend nonce
70+
ciphertext := gcm.Seal(nonce, nonce, fileContent, nil)
71+
72+
// Encode the ciphertext to Base64 for safe storage
73+
encodedCiphertext := base64.StdEncoding.EncodeToString(ciphertext)
74+
return &encodedCiphertext, nil
75+
}
76+
77+
func (i *Inventory) Decrypt(ciphertext string, decryptionKey string) (*string, error) {
78+
gcm, err := i.aes(decryptionKey)
79+
if err != nil {
80+
return nil, err
81+
}
82+
83+
// Decode the Base64 ciphertext
84+
ciphertextBytes, err := base64.StdEncoding.DecodeString(ciphertext)
85+
if err != nil {
86+
return nil, err
87+
}
88+
89+
nonceSize := gcm.NonceSize()
90+
if len(ciphertextBytes) < nonceSize {
91+
return nil, errors.New("ciphertext too short")
92+
}
93+
94+
// Separate nonce and actual ciphertext
95+
nonce, encryptedMessage := ciphertextBytes[:nonceSize], ciphertextBytes[nonceSize:]
96+
97+
// Decrypt the ciphertext
98+
plaintext, err := gcm.Open(nil, nonce, encryptedMessage, nil)
99+
if err != nil {
100+
return nil, err
101+
}
102+
103+
decryptedFileContent := string(plaintext)
104+
return &decryptedFileContent, nil
105+
}
106+
27107
func NewInventory() *Inventory {
28108
return &Inventory{}
29109
}

0 commit comments

Comments
 (0)