Skip to content

Commit

Permalink
add secret service
Browse files Browse the repository at this point in the history
  • Loading branch information
asim committed Nov 17, 2022
1 parent 823af93 commit aaee29d
Show file tree
Hide file tree
Showing 12 changed files with 1,323 additions and 0 deletions.
2 changes: 2 additions & 0 deletions secret/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@

secret
27 changes: 27 additions & 0 deletions secret/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@

GOPATH:=$(shell go env GOPATH)
.PHONY: init
init:
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
go install github.com/micro/micro/v3/cmd/protoc-gen-micro@latest
go install github.com/micro/micro/v3/cmd/protoc-gen-openapi@latest

.PHONY: api
api:
protoc --openapi_out=. --proto_path=. proto/secret.proto

.PHONY: proto
proto:
protoc --proto_path=. --micro_out=. --go_out=:. proto/secret.proto

.PHONY: build
build:
go build -o secret *.go

.PHONY: test
test:
go test -v ./... -cover

.PHONY: docker
docker:
docker build . -t secret:latest
8 changes: 8 additions & 0 deletions secret/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
Encrypted secret storage

# Secret Service

Store secrets, tokens, passwords and key-value config in encrypted data storage.

Keys are individually allocated spaces for values. Values are encrypted at rest.
Values can be strings or JSON with path based lookup if the latter.
44 changes: 44 additions & 0 deletions secret/config/examples.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@

{
"set": [{
"title": "Set a value",
"description": "Set allows you to set a value",
"run_check": true,
"idempotent": true,
"request": {
"key": "foo",
"value": "bar"
},
"response": {}
}],
"get": [{
"title": "Get a value",
"description": "Get returns a value",
"run_check": true,
"request": {
"key": "foo"
},
"response": {
"key": "foo",
"value": "bar"
}
}],
"delete": [{
"title": "Delete a value",
"description": "Delete a value",
"run_check": true,
"request": {
"key": "foo"
},
"response": {}
}],
"list": [{
"title": "List all secrets",
"description": "List all the stored secrets",
"run_check": true,
"request": {},
"response": {
"keys": ["foo"]
}
}]
}
6 changes: 6 additions & 0 deletions secret/config/publicapi.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"name": "secret",
"icon": "🗝️",
"category": "storage",
"display_name": "Secrets"
}
3 changes: 3 additions & 0 deletions secret/config/service.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"key": "UTlzQWNHaFFSOEdRcHFIWVBUQk9rSnQ4TFluaUt4MmU="
}
70 changes: 70 additions & 0 deletions secret/handler/encryption.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package handler

import (
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"encoding/hex"
"fmt"
"io"
)

// encrypt/decrypt functions are taken from https://www.melvinvivas.com/how-to-encrypt-and-decrypt-data-using-aes/

func encrypt(stringToEncrypt string, key []byte) (string, error) {
plaintext := []byte(stringToEncrypt)

//Create a new Cipher Block from the key
block, err := aes.NewCipher(key)
if err != nil {
return "", err
}

//Create a new GCM - https://en.wikipedia.org/wiki/Galois/Counter_Mode
//https://golang.org/pkg/crypto/cipher/#NewGCM
aesGCM, err := cipher.NewGCM(block)
if err != nil {
return "", err
}

//Create a nonce. Nonce should be from GCM
nonce := make([]byte, aesGCM.NonceSize())
if _, err = io.ReadFull(rand.Reader, nonce); err != nil {
return "", err
}

//Encrypt the data using aesGCM.Seal
//Since we don't want to save the nonce somewhere else in this case, we add it as a prefix to the encrypted data. The first nonce argument in Seal is the prefix.
ciphertext := aesGCM.Seal(nonce, nonce, plaintext, nil)
return fmt.Sprintf("%x", ciphertext), nil
}

func decrypt(encryptedString string, key []byte) (string, error) {
enc, _ := hex.DecodeString(encryptedString)

//Create a new Cipher Block from the key
block, err := aes.NewCipher(key)
if err != nil {
return "", err
}

//Create a new GCM
aesGCM, err := cipher.NewGCM(block)
if err != nil {
return "", err
}

//Get the nonce size
nonceSize := aesGCM.NonceSize()

//Extract the nonce from the encrypted data
nonce, ciphertext := enc[:nonceSize], enc[nonceSize:]

//Decrypt the data
plaintext, err := aesGCM.Open(nil, nonce, ciphertext, nil)
if err != nil {
return "", err
}

return fmt.Sprintf("%s", plaintext), nil
}
Loading

0 comments on commit aaee29d

Please sign in to comment.