ghoststring

package module
v0.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 18, 2022 License: MIT Imports: 13 Imported by: 0

README

ghoststring

Go Reference

A Go string wrapper type that is encrypted when JSONified. Encryption is symmetric using AES-256-GMC with per-string nonce.

usage

Typical usage assumes at least two systems that share a key. For example, two or more web services may not directly communicate, but are passed data via state transfer through a browser session to which they both need access without leaking to the browser.

Each instance of GhostString requires a non-empty namespace which must match a registered Ghostifyer, e.g.:

Declare a type that uses a GhostString as a field:

type Message struct {
	Recipient string                  `json:"recipient"`
	Content   ghoststring.GhostString `json:"content"`
	Mood      ghoststring.GhostString `json:"mood"`
}

Load a secret key from somewhere that meets your security requirements, such as from a mounted kubernetes secret:

secretKeyBytes, err := os.ReadFile("/path/to/secret-key")
if err != nil {
	return err
}

Register and set a Ghostifyer with the secret key and namespace in use:

_, err := ghoststring.SetGhostifyer("heck.example.org", string(secretKeyBytes))
if err != nil {
	return err
}

Use the declared type as with any other struct type:

msg := &Message{
	Recipient: "[email protected]",
	Content: ghoststring.GhostString{
		Namespace: "heck.example.org",
		String:    "We meet me at the fjord at dawn. Bring donuts, please.",
	},
	Mood: ghoststring.GhostString{
		Namespace: "heck.example.org",
		String:    "giddy",
	},
}

When the type instance is encoded to JSON, the GhostString fields will automatically encode to a JSON string type:

{
  "recipient": "[email protected]",
  "content": "👻:NTNjZjdmMWZjNzU2NTY1ODFkN2E4ZDI4aGVjay5leGFtcGxlLm9yZzo60XHqdSEbswpPbKLrDUuBZCrtUQLjmJ1NxHsqHMgBJjrB10O7JC4rwiMZw+wf/BOJGmu9ZCpMjgMpu18/VgDBpLn4n1nBNw==",
  "mood": "👻:YmYzZDVjNDVhNTUyMTA1Mzg0ZWU0NjI0aGVjay5leGFtcGxlLm9yZzo6SML6iqmwSoDhX3b2SQXsMLJPMHHS"
}

In the event of an unrecognized namespace, the GhostString fields will be encoded as empty strings, e.g.:

msg := &Message{
	Recipient: "[email protected]",
	Content: ghoststring.GhostString{
		Namespace: "heck.example.org",
		String:    "Next time I'm bringing the coffee.",
	},
	Mood: ghoststring.GhostString{
		Namespace: "wat.example.org",
		String:    "zzz",
	},
}

Because the "wat.example.org" namespace isn't registered, the output will look like this:

{
  "recipient": "[email protected]",
  "content": "👻:NTNjZjdmMWZjNzU2NTY1ODFkN2E4ZDI4aGVjay5leGFtcGxlLm9yZzo60XHqdSEbswpPbKLrDUuBZCrtUQLjmJ1NxHsqHMgBJjrB10O7JC4rwiMZw+wf/BOJGmu9ZCpMjgMpu18/VgDBpLn4n1nBNw==",
  "mood": ""
}

Any system that needs to read the encrypted contents must decode the JSON into a type that uses GhostString for the matching fields in a process where a matching Ghostifyer has been registered. Other systems may treat the values as opaque strings.

Documentation

Index

Examples

Constants

This section is empty.

Variables

View Source
var (
	Err = errors.New("ghoststring error")
)

Functions

This section is empty.

Types

type GhostString

type GhostString struct {
	String    string
	Namespace string
}

GhostString wraps a string with a JSON marshaller that uses a namespace-scoped encrypting Ghostifyer registered via SetGhostifyer

Example
package main

import (
	"encoding/json"
	"fmt"
	"regexp"
	"strings"
	"time"

	"github.com/rstudio/ghoststring"
)

func main() {
	if _, err := ghoststring.SetGhostifyer(
		"example",
		"correct horse battery staple",
	); err != nil {
		panic(err)
	}

	type DiaryEntry struct {
		Timestamp time.Time               `json:"timestamp"`
		Text      ghoststring.GhostString `json:"text"`
	}

	type Diary struct {
		Author  string       `json:"author"`
		Entries []DiaryEntry `json:"entries"`
	}

	enc, err := json.MarshalIndent(
		&Diary{
			Author: "Eagerly Anticipated",
			Entries: []DiaryEntry{
				{
					Timestamp: time.UnixMicro(4),
					Text: ghoststring.GhostString{
						Namespace: "example",
						String:    "Nights without you are so dark. I pray that someday you will return my flashlight.",
					},
				},
				{
					Timestamp: time.UnixMicro(-8001),
					Text: ghoststring.GhostString{
						Namespace: "unknown",
						String:    "We may never know.",
					},
				},
			},
		},
		"",
		"  ",
	)
	if err != nil {
		panic(err)
	}

	encString := string(enc)

	if strings.Contains(encString, "We may never know.") || strings.Contains(encString, "Nights without you") {
		panic("not ghostly enough: contains cleartext")
	}

	if !strings.Contains(encString, `"text": ""`) {
		panic("not ghostly enough: lacking empty ghoststring")
	}

	if matched, err := regexp.MatchString(`.+"text": "👻:[^"]+"`, encString); !matched || err != nil {
		panic("not ghostly enough: lacking non-empty ghoststring")
	}

	fmt.Println("no peeking")

}
Output:
no peeking

func (*GhostString) Equal

func (gs *GhostString) Equal(other *GhostString) bool

Equal compares this GhostString to another

func (*GhostString) IsValid

func (gs *GhostString) IsValid() bool

IsValid checks that the wrapped string value is non-empty and the namespace is valid

func (*GhostString) MarshalJSON

func (gs *GhostString) MarshalJSON() ([]byte, error)

MarshalJSON allows GhostString to fulfill the json.Marshaler interface. The lack of a namespace is considered an error.

func (*GhostString) UnmarshalJSON

func (gs *GhostString) UnmarshalJSON(b []byte) error

UnmarshalJSON allows GhostString to fulfill the json.Unmarshaler interface. The bytes are first unmarshaled as a string and then if non-empty are passed through an "unghostify" step.

type Ghostifyer

type Ghostifyer interface {
	Ghostify(*GhostString) (string, error)
	Unghostify(string) (*GhostString, error)
}

Ghostifyer encrypts and encodes a *GhostString into a string representation that is acceptable for inclusion in JSON. The structure of a ghostified string is:

{prefix}base64({nonce}{namespace}{namespace separator}{value})

func SetGhostifyer

func SetGhostifyer(namespace, key string) (Ghostifyer, error)

Directories

Path Synopsis
cmd
ghoststring command
internal
cmd/myths command
cmd/rectangles command

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL