Documentation ¶
Overview ¶
Package secret provides a library to safely store key/value pairs into an encrypted file on disk.
Encryption ¶
The data are encrypted using AES-256 and the GCM (Galois/Counter Mode) mode. The encryption key is derived from the store passphrase using the PBKDF2 algorithm.
Binary Format ¶
The secret store uses the following binary format:
2 bytes for the revision stored as an unsigned int on 16bits encoded in little endian 32 bytes for the salt used by key derivation algorithm (PBKDF2) All other bytes are used to store the encrypted data. There is no limit for the size. The first 12 bytes are used to store the nonce required by the AES-GCM cipher.
Before the encryption, the key/value pairs are encoded using the following format:
{key:base64(value)}
The key can only contains alphanumeric characters, dashes ("-") and underscores ("_"). The value has no limitation and is encoded using standard base 64 encoding.
Limitation ¶
The store is not optimized for huge amount of data nor for high performance.
Security ¶
All the security relies on the passphrase. It is therefore highly recommended to use a strong passphrase, preferably generated with a strong generator.
Example ¶
package main import ( "fmt" "log" "os" "path/filepath" "github.com/e-XpertSolutions/go-secret/secret" ) func main() { path := filepath.Join(os.TempDir(), "secret.store") defer os.Remove(path) passphrase := "strong_passphrase" // Open the secret store. Since it does not exist, it will create it. store, err := secret.OpenStore(path, passphrase) if err != nil { log.Print("[error] ", err) return } defer store.Close() // Store a password. err = store.Put("password", []byte("my_very_secret_password")) if err != nil { log.Print("[error] ", err) return } // List all keys present in the store, which should only be "password" in // this case. keys, err := store.Keys() if err != nil { log.Print("[error] ", err) return } fmt.Println("Keys:", keys) // Retrieve the stored password. value, err := store.Get("password") if err != nil { log.Print("[error] ", err) return } fmt.Println("Retrieved password:", string(value)) fmt.Println("Delete password") // Delete the password from the store. err = store.Delete("password") if err != nil { log.Print("[error] ", err) return } // Since "password" has been deleted, there should be no keys in the store. keys, err = store.Keys() if err != nil { log.Print("[error] ", err) return } fmt.Println("Keys:", keys) }
Output: Keys: [password] Retrieved password: my_very_secret_password Delete password Keys: []
Index ¶
Examples ¶
Constants ¶
const CurrentRevision uint16 = 1
CurrentRevision represents the version of the store format. The value must be incremented for every a change that breaks the compatibility with the existing binary format.
Variables ¶
var ErrNotFound = errors.New("record not found")
ErrNotFound is returned by Get when the key does not exist in the store.
Functions ¶
This section is empty.
Types ¶
type Store ¶
type Store struct {
// contains filtered or unexported fields
}
A Store holds key/value pairs that are securely stored into an encrypted file on disk. The store is safe for concurrent use.
func OpenStore ¶
OpenStore opens an existing store located at the given path and protected with the given passphrase.
If the store does not exist, it creates a new one at the path and protected with the passphrase.
func (*Store) Delete ¶
Delete deletes the value for a key in the store. If the key does not exist no error is returned.
func (*Store) Get ¶
Get returns the value in the store for a key. If no value is present, ErrNotFound returned.