Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion cmd/ghostpass/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,13 +84,21 @@ func main() {
Usage: "Name of secret store to create locally",
Aliases: []string{"n"},
},
&cli.IntFlag{
Name: "entries",
Usage: "Number of deniable entries to also create for each field added",
Aliases: []string{"e"},
},
},
Action: func(c *cli.Context) error {
name := c.String("name")
if name == "" {
return errors.New("Name to secret store not specified")
}

// deniable entries is optional
entries := c.Int("entries")

col := color.New(color.FgWhite).Add(color.Bold)
col.Printf("\n[*] Initializing new secret store `%s` [*]\n\n", name)

Expand All @@ -103,7 +111,7 @@ func main() {
}

// create new secret store
store, err := ghostpass.InitStore(name, masterkey)
store, err := ghostpass.InitStore(name, masterkey, entries)
if err != nil {
return err
}
Expand Down
40 changes: 23 additions & 17 deletions ser.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,12 @@ func StationaryUnmarshal(checksum [32]byte, serialized []byte) (*SecretStore, er

// turn the serialized JSON back into a partially initialized state for a SecretStore
var ss struct {
Version int `json:"version"`
StoreState string `json:"state"`
Name string `json:"name"`
Fields map[string]*Field `json:"fields"`
Version int `json:"version"`
StoreState string `json:"state"`
Name string `json:"name"`
Fields map[string]*Field `json:"fields"`
EntrySize int `json:"entrysize"`
DeniableEntries map[string][]*Field `json:"entries"`
}
err := json.Unmarshal(serialized, &ss)
if err != nil {
Expand All @@ -38,11 +40,13 @@ func StationaryUnmarshal(checksum [32]byte, serialized []byte) (*SecretStore, er

// return the SecretStore as if nothing changed
return &SecretStore{
Version: ss.Version,
StoreState: ss.StoreState,
Name: ss.Name,
SymmetricKey: checksum[:],
Fields: ss.Fields,
Version: ss.Version,
StoreState: ss.StoreState,
Name: ss.Name,
SymmetricKey: checksum[:],
Fields: ss.Fields,
EntrySize: ss.EntrySize,
DeniableEntries: ss.DeniableEntries,
}, nil
}

Expand Down Expand Up @@ -109,6 +113,8 @@ func PlainsightUnmarshal(checksum [32]byte, encoded []byte) (*SecretStore, error
}

// return the SecretStore as if nothing changed
// we do not include the deniable entries attributes, since the user may have used a
// bogus symmetric key.
return &SecretStore{
Version: ss.Version,
StoreState: StoreStationary,
Expand Down Expand Up @@ -147,15 +153,15 @@ func (ss *SecretStore) PlainsightMarshal() ([]byte, error) {

// serialize into a byte array for compression
data, err := json.Marshal(&struct {
Version int `json:"version"`
StoreState string `json:"state"`
Name string `json:"name"`
Fields map[string][]byte `json:"fields"`
Version int `json:"version"`
StoreState string `json:"state"`
Name string `json:"name"`
Fields map[string][]byte `json:"fields"`
}{
Version: Version,
StoreState: StorePlainsight,
Name: ss.Name,
Fields: encfields,
Version: Version,
StoreState: StorePlainsight,
Name: ss.Name,
Fields: encfields,
})

if err != nil {
Expand Down
51 changes: 38 additions & 13 deletions store.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,12 @@ type SecretStore struct {
// internal state of the store with all the available secrets
Fields map[string]*Field `json:"fields"`

// represents the number of deniable secrets
EntrySize int `json:"entrysize"`

// stores the deniable entries to be created per field, if not 0
DeniableEntries map[string][]*Field `json:"entries"`

// TODO: notes for genercized information to distribute
}

Expand All @@ -77,7 +83,7 @@ type SecretStore struct {

// Initializes a new `SecretStore` given a name and master symmetric key that is secured. Will
// create a new store if name does not exist, otherwise will read and return the existing one.
func InitStore(name string, pwd *memguard.Enclave) (*SecretStore, error) {
func InitStore(name string, pwd *memguard.Enclave, entrysize int) (*SecretStore, error) {

// initialize path to database, return empty buffer
dbpath := fmt.Sprintf("%s/%s.gp", MakeWorkspace(), name)
Expand Down Expand Up @@ -105,13 +111,23 @@ func InitStore(name string, pwd *memguard.Enclave) (*SecretStore, error) {
// destroy original plaintext key
defer key.Destroy()

// determine if we need to create space for deniable entries
var entries map[string][]*Field
if entrysize == 0 {
entries = make(map[string][]*Field)
} else {
entries = nil
}

// if not, create an empty SecretStore
return &SecretStore{
Version: Version,
StoreState: StoreStationary,
Name: name,
SymmetricKey: checksum[:],
Fields: make(map[string]*Field),
Version: Version,
StoreState: StoreStationary,
Name: name,
SymmetricKey: checksum[:],
Fields: make(map[string]*Field),
EntrySize: entrysize,
DeniableEntries: entries,
}, nil
}

Expand Down Expand Up @@ -218,18 +234,27 @@ func (ss *SecretStore) AddField(service string, username string, pwd *memguard.E
return nil
}

// Given an existing field, attempt to encrypt a deniable credential pair, an derive a "deniability" key for
// plausible deniability. (TODO)
// Given an existing field that supports deniable entries, check and add a new deniable field to the secret store corresponding
// to the same service. Adds only once, and should be called iteratively until the threshold is met.
func (ss *SecretStore) AddDeniableField(service string, username string, pwd *memguard.Enclave) error {
// check to see if the field exists
// check to see if store is configured to add deniable entries
if ss.DeniableEntries == nil {
return errors.New("store not configured to use deniable entries")
}

// check to see if the field exists, since we cannot create deniable entries for something that isnt original
if !ss.FieldExists(service) {
return errors.New("cannot find entry given the service name provided")
}

// TODO
// if exists, update it with the deniable secret
//field.AddDeniableSecret(username, pwd)
//ss.Fields[service] = field
// initialize a new field from the given parameters
field, err := NewField(ss.SymmetricKey, username, pwd)
if err != nil {
return err
}

// add deniable entry for that specific key
_ = append(ss.DeniableEntries[service], field)
return nil
}

Expand Down