Last active
February 2, 2024 17:58
-
-
Save fuzzyami/f3a7231037166117a6fef9607960aee7 to your computer and use it in GitHub Desktop.
golang encyrpt, decrypt key with kms
This file contains hidden or 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
/* | |
The code below shows how to encrypt and then decrypt some plaintext into a cyphertext using | |
KMS's Encrypt/Decrypt functions and secretbox (https://godoc.org/golang.org/x/crypto/nacl/secretbox). | |
The plaintext message is sealed into a secretbox using a key that is generated by kmsClient.GenerateDataKey(). | |
Note that this procedure reuquires that a master key would *already exist in KMS* and that its arn/alias is specified. | |
The aws library assumes that the proper credentials can be found in the shared file (~/.aws/credentials) | |
and opts for the 'default' role. | |
Once sealed, the cyphertext is then unboxed, again by first getting the key from kms (kmsClient.Decrypt), | |
and then using that to decypher the text (secretbox.Open(..)) | |
Note that that the kms keyname isn't specified on Decrypt. I guess that the ciphertext contains some meta regarding | |
which key should be used to decrypt. | |
*/ | |
package main | |
import ( | |
"bytes" | |
"crypto/rand" | |
"encoding/gob" | |
"fmt" | |
"io/ioutil" | |
"github.com/aws/aws-sdk-go/aws" | |
"github.com/aws/aws-sdk-go/aws/session" | |
"github.com/aws/aws-sdk-go/service/kms" | |
"golang.org/x/crypto/nacl/secretbox" | |
"strings" | |
) | |
const ( | |
kmsKeyName = "tempKey" //must already exist in kms | |
) | |
func main() { | |
r := strings.NewReader("Go is a general-purpose language designed with systems programming in mind.") | |
plaintext, err := ioutil.ReadAll(r) | |
if err != nil { | |
panic(err) | |
} | |
fmt.Println("Plaintext: ", plaintext) | |
sess := session.Must(session.NewSession()) | |
kmsClient := kms.New(sess, aws.NewConfig().WithRegion("us-east-1")) | |
// Encrypt plaintext | |
encrypted, err := Encrypt(kmsClient, plaintext) // <-- to be implemented | |
if err != nil { | |
panic(err) | |
} | |
fmt.Println("Encrypted: ", encrypted) | |
// Decrypt ciphertext | |
kmsClient = kms.New(sess, aws.NewConfig().WithRegion("us-east-1")) | |
decrypted, err := Decrypt(kmsClient, encrypted) // <-- to be implemented | |
if err != nil { | |
panic(err) | |
} | |
fmt.Println("Decrypted: ", decrypted) | |
} | |
const ( | |
keyLength = 32 | |
nonceLength = 24 | |
) | |
type payload struct { | |
Key []byte | |
Nonce *[nonceLength]byte | |
Message []byte | |
} | |
func Encrypt(kmsClient *kms.KMS, plaintext []byte) ([]byte, error) { | |
// Generate data key | |
//provide either the key's arn OR its alias, as shown below: | |
//keyId := "arn:aws:kms:us-east-1:779993255822:key/bb1a147c-8600-4558-910d-8b841c8f7493" | |
keyId := "alias/" + kmsKeyName | |
keySpec := "AES_128" | |
dataKeyInput := kms.GenerateDataKeyInput{KeyId: &keyId, KeySpec: &keySpec} | |
dataKeyOutput, err := kmsClient.GenerateDataKey(&dataKeyInput) | |
if err == nil { // dataKeyOutput is now filled | |
fmt.Println(dataKeyOutput) | |
} else { | |
fmt.Println("error: ", err) | |
} | |
// Initialize payload | |
p := &payload{ | |
Key: dataKeyOutput.CiphertextBlob, | |
Nonce: &[nonceLength]byte{}, | |
} | |
// Set nonce | |
if _, err = rand.Read(p.Nonce[:]); err != nil { | |
return nil, err | |
} | |
// Create key | |
key := &[keyLength]byte{} | |
copy(key[:], dataKeyOutput.Plaintext) | |
// Encrypt message | |
p.Message = secretbox.Seal(p.Message, plaintext, p.Nonce, key) | |
buf := &bytes.Buffer{} | |
if err := gob.NewEncoder(buf).Encode(p); err != nil { | |
return nil, err | |
} | |
return buf.Bytes(), nil | |
} | |
func Decrypt(kmsClient *kms.KMS, ciphertext []byte) ([]byte, error) { | |
// Decode ciphertext with gob | |
var p payload | |
gob.NewDecoder(bytes.NewReader(ciphertext)).Decode(&p) | |
//Decrypt a ciphertext that was previously encrypted. | |
//Note that we dont actually specify the key name. | |
//I guess the ciphertext already encodes it? | |
dataKeyOutput, err := kmsClient.Decrypt(&kms.DecryptInput{ | |
CiphertextBlob: p.Key, | |
}) | |
if err == nil { // dataKeyOutput is now filled | |
fmt.Println(dataKeyOutput) | |
} else { | |
fmt.Println("error: ", err) | |
} | |
key := &[keyLength]byte{} | |
copy(key[:], dataKeyOutput.Plaintext) | |
// Decrypt message | |
var plaintext []byte | |
plaintext, ok := secretbox.Open(plaintext, p.Message, p.Nonce, key) | |
if !ok { | |
return nil, fmt.Errorf("Failed to open secretbox") | |
} | |
return plaintext, nil | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This is nearly an exact copy... https://gist.github.com/andreas/eea322d73ca21e66b55b