password

package module
v0.11.0 Latest Latest
Warning

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

Go to latest
Published: Jan 25, 2025 License: BSD-3-Clause Imports: 21 Imported by: 0

README

Go workflow CMake workflow

simple-password-manager

Ever needed a simple key-value store with an encryption backend to handle your app passwords?

Look no further! This is a simple password manger (library) written in Go. You can use it with Go, REST calls and any other language that links with C.

And the best of it all: it's free - BSD licensed - just don't sue me if you loose your passwords (no pun intended, ha!)

Setup / Build

Go

go mod tidy automatically fetches the necessary dependencies when you add the import statement to your code (see also: Go's module support):

import "github.com/image357/password"

Alternatively, use go get in your project to prefetch all dependencies:

go get -u github.com/image357/password/...@latest
C/C++

You can use cmake to build and install the C interface library:

mkdir build; cd build
cmake -DCMAKE_INSTALL_PREFIX=/full/path/to/install/dir ..
cmake --build .
cmake --install .

Then, simply find the installed package in your CMakeLists.txt:

find_package(password)
message(STATUS "${password_DLL_FILE}")

add_executable(main main.cpp)
target_link_libraries(main PRIVATE password::cinterface)

On Windows you will need MinGW to build the library. This is because cgo doesn't support any other compiler backend yet. Once compiled, you can use the library with any compiler, though. You can also have a look at the release section to see if there are any pre-built binaries for your platform.

Usage

Go
package main

import (
    "fmt"
    "github.com/image357/password"
    "github.com/image357/password/log"
    "github.com/image357/password/rest"
)

func main() {
    // create password with id
    password.Overwrite("myid", "mypassword", "storage_key")
    
    // get password with id
    pwd, _ := password.Get("myid", "storage_key")
    fmt.Println(pwd)
    
    // start a multi password rest service on localhost:8080
    rest.StartMultiService(
        ":8080", "/prefix", "storage_key",
        func(string, string, string, string) bool { return true },
    )
    
    // make logging more verbose
    log.Level(log.LevelDebug)
}
C/C++:
#include <stdio.h>
#include <password/cinterface.h>

bool callback(cchar_t *token, cchar_t *ip, cchar_t *resource, cchar_t *id) {
    return true;
}

int main() {
    // create password with id 
    CPWD__Overwrite("myid", "mypassword", "storage_key");
    
    // get password with id
    char buffer[256];
    CPWD__Get("myid", "storage_key", buffer, 256);
    printf("%s\n", buffer);
    
    // start a multi password rest service on localhost:8080
    CPWD__StartMultiService(":8080", "/prefix", "storage_key", callback);
    
    // make logging more verbose
    CPWD__LogLevel(CPWD__LevelDebug);
    
    return 0;
}
Example Service

There is an example REST service, which you can use for testing. Install it with:

go install github.com/image357/password/cmd/exampleservice@latest

Warning: do not use this service for production use-cases. It doesn't have any access control and the storage key hides in plain sight!

REST

When you have your REST service running (see above) you can make calls with, e.g., python

import requests

# create password with id
requests.put("http://localhost:8080/prefix/overwrite", json={"id": "myid", "password": "mypassword", "accessToken": "some_token"})

# get password with id
r = requests.get("http://localhost:8080/prefix/get", json={"id": "myid", "accessToken": "some_token"})
print(r.content)

# output: b'{"password":"mypassword"}'

Details

API

The REST API mirrors the Go and C\C++ interface. This means that the signature is the same - with three exceptions:

  1. For REST, you need an accessToken. For Go/C/C++ you need a storage_key.
  2. The C/C++ API accepts result pointers and returns status codes. The Go API directly returns values and errors.
  3. The simple service does not require "id" properties and will not bind to Clean and List calls.

Here is a full overview:

Overwrite:

Go:   -> password.Overwrite(id string, password string, key string)
C/C++ -> CPWD__Overwrite(const char *id, const char *password, const char *key)
REST: -> (PUT) /prefix/overwrite

Example JSON for REST request:
{
    "accessToken": "my_token"
    "id": "my_id"
    "password": "my_password"
}

Return: {}

Get:

Go:   -> password.Get(id string, key string)
C/C++ -> CPWD__Get(const char *id, const char *key, char *buffer, int length)
REST: -> (GET) /prefix/get

Example JSON for REST request:
{
    "accessToken": "my_token"
    "id": "my_id"
}

Return: {"password": "stored_password"}

Check:

Go:   -> password.Get(id string, password string, key string)
C/C++ -> CPWD__Check(const char *id, const char *password, const char *key, bool *result)
REST: -> (GET) /prefix/check

Example JSON for REST request:
{
    "accessToken": "my_token"
    "id": "my_id"
    "password": "password_to_check"
}

Return: {"result": true/false}

Set:

Go:   -> password.Set(id string, oldPassword string, newPassword string, key string)
C/C++ -> CPWD__Set(const char *id, const char *oldPassword, const char *newPassword, const char *key)
REST: -> (PUT) /prefix/set

Example JSON for REST request:
{
    "accessToken": "my_token"
    "id": "my_id"
    "oldPassword": "password1"
    "newPassword": "password2"
}

Return: {}

Unset:

Go:   -> password.Unset(id string, password string, key string)
C/C++ -> CPWD__Unset(const char *id, const char *password, const char *key)
REST: -> (DELETE) /prefix/unset

Example JSON for REST request:
{
    "accessToken": "my_token"
    "id": "my_id"
    "password": "password_to_check"
}

Return: {}

Exists:

Go:   -> password.Exists(id string)
C/C++ -> CPWD__Exists(const char *id, bool *result)
REST: -> (GET) /prefix/exists

Example JSON for REST request:
{
    "accessToken": "my_token"
    "id": "my_id"
}

Return: {"result": true/false}

List:

Go:   -> password.List()
C/C++ -> CPWD__List(char *buffer, int length, const char *delim)
REST: -> (GET) /prefix/list

Example JSON for REST request:
{
    "accessToken": "my_token"
}

Return: {"ids": ["stored_id", "another_stored_id", ...]}

Delete:

Go:   -> password.Delete(id string)
C/C++ -> CPWD__Delete(const char *id)
REST: -> (DELETE) /prefix/delete

Example JSON for REST request:
{
    "accessToken": "my_token"
    "id": "my_id"
}

Return: {}

Clean:

Go:   -> password.Clean()
C/C++ -> CPWD__Clean()
REST: -> (DELETE) /prefix/clean

Example JSON for REST request:
{
    "accessToken": "my_token"
}

Return: {}
Storage

Files and folders - it's that simple. To make the storage backend cross-platform compatible, ids have the following constraints:

  1. Forward- and backward-slashes are treated as the same character.
  2. Upper- and lower-case characters are treated as the same character.

You can also switch to temporary (in-memory) storage or serialize to JSON (see below for full docs).

Encryption

Yes, the usual - AES256, hashed secrets, etc. For more info have a look at the source code.

Documentation

For full documentation see: docs

There are some additional convenience functions in Go and C/C++ that control storage path, logging, recovery mode and changing storage keys. Additionally, you can just explore the source code with any godoc compatible IDE.

Check it out!

Documentation

Overview

Package password provides a simple-password-manager library with an encryption backend to handle app passwords. For full documentation visit https://github.com/image357/password/blob/main/docs/password.md

Index

Constants

View Source
const DefaultFileEnding string = "pwd"

DefaultFileEnding is the default file extension for password files.

View Source
const DefaultStorePath = "./password"

DefaultStorePath is the default relative storage path of a file storage backend.

View Source
const RecoveryIdSuffix string = ".recovery"

RecoveryIdSuffix stores the id/file suffix that identifies recovery key files.

Variables

View Source
var Managers = map[string]*Manager{
	"default": NewManager(),
}

Managers stores a map of string identifiers for all created password managers. The identifier "default" always holds the default manager from GetDefaultManager. It can be set via SetDefaultManager. Do not manipulate directly.

Functions

func Check

func Check(id string, password string, key string) (bool, error)

Check an existing password for equality with the provided password. key is the encryption secret for storage.

func Clean

func Clean() error

Clean (delete) all stored passwords.

func Decrypt added in v0.7.0

func Decrypt(ciphertext string, secret string) (string, error)

Decrypt a given ciphertext in base64 representation with AES256. The secret is hashed with the custom Hash function. Galois Counter Mode is used. The nonce is retrieved as a prefix of the ciphertext.

func DecryptOTP added in v0.3.2

func DecryptOTP(cipherBytes []byte, secret []byte) string

DecryptOTP returns the decrypted message from a One-Time-Pad (OTP) encryption.

func Delete

func Delete(id string) error

Delete an existing password.

func DisableHashing added in v0.9.0

func DisableHashing()

DisableHashing will set the config variable Manager.HashPassword of the default password manager to false. This disables storage of hashed passwords.

func DisableRecovery added in v0.3.2

func DisableRecovery()

DisableRecovery will stop recovery key file storage alongside passwords.

func DumpJSON added in v0.8.4

func DumpJSON() (string, error)

DumpJSON serializes the storage backend to a JSON string.

func EnableHashing added in v0.9.0

func EnableHashing()

EnableHashing will set the config variable Manager.HashPassword of the default password manager to true. This enables storage of hashed passwords.

func EnableRecovery added in v0.3.2

func EnableRecovery(key string)

EnableRecovery will enforce recovery key file storage alongside passwords.

func Encrypt added in v0.7.0

func Encrypt(text string, secret string) (string, error)

Encrypt a given text with AES256 and return a base64 representation. The secret is hashed with the custom Hash function. Galois Counter Mode is used. The nonce is stored as a prefix of the ciphertext.

func EncryptOTP added in v0.3.2

func EncryptOTP(text string) ([]byte, []byte)

EncryptOTP returns a One-Time-Pad (OTP) encrypted message and its OTP secret.

func Exists added in v0.5.0

func Exists(id string) (bool, error)

Exists tests if a given id already exists in the storage backend.

func FilePath

func FilePath(id string) (string, error)

FilePath returns the storage filepath of a given password-id with system-specific path separators. It accepts system-unspecific or mixed id separators, i.e. forward- and backward-slashes are treated as the same character.

func Get

func Get(id string, key string) (string, error)

Get an existing password with id. key is the encryption secret for storage.

func GetStorePath

func GetStorePath() (string, error)

GetStorePath returns the current storage path with system-specific path separators.

func List

func List() ([]string, error)

List all stored password-ids.

func LoadJSON added in v0.8.4

func LoadJSON(input string) error

LoadJSON deserializes a JSON string into the storage backend.

func NormalizeId

func NormalizeId(id string) string

NormalizeId transforms path to lower case letters and normalizes the path separator

func Overwrite

func Overwrite(id string, password string, key string) error

Overwrite an existing password or create a new one. key is the encryption secret for storage.

func ReadFromDisk added in v0.8.2

func ReadFromDisk(path string) error

ReadFromDisk loads a FileStorage backend from disk into the current storage. Warning: This method does not block operations on the underlying storage backends (read/write/create/delete). You should stop operations manually before usage or ignore the reported error. Data consistency is guaranteed.

func RegisterDefaultManager added in v0.5.0

func RegisterDefaultManager(identifier string)

RegisterDefaultManager will register the current default password manger under the identifier and set a new default manager.

func RewriteKey added in v0.8.3

func RewriteKey(id string, oldKey string, newKey string) error

RewriteKey changes the storage key of a password from oldKey to newKey. Encryption hashes will be renewed. Stored metadata will be unchanged. If enabled, recovery entries will be recreated.

func Set

func Set(id string, oldPassword string, newPassword string, key string) error

Set an existing password-id or create a new one. oldPassword must match the currently stored password. key is the encryption secret for storage.

func SetDefaultManager added in v0.5.0

func SetDefaultManager(manager *Manager)

SetDefaultManager will overwrite the current default password manager with the provided one.

func SetStorePath

func SetStorePath(path string) error

SetStorePath accepts a new storage path with system-unspecific or mixed path separators.

func SetTemporaryStorage added in v0.8.0

func SetTemporaryStorage()

SetTemporaryStorage overwrites the current storage backend with a memory based one.

func Unset

func Unset(id string, password string, key string) error

Unset (delete) an existing password. password must match the currently stored password. key is the encryption secret for storage.

func WriteToDisk added in v0.8.2

func WriteToDisk(path string) error

WriteToDisk saves the current storage to files via FileStorage mechanisms. Warning: This method does not block operations on the underlying storage backends (read/write/create/delete). You should stop operations manually before usage or ignore the reported error. Data consistency is guaranteed.

Types

type FileStorage added in v0.5.0

type FileStorage struct {
	// contains filtered or unexported fields
}

FileStorage is a file based storage backend.

func NewFileStorage added in v0.5.0

func NewFileStorage() *FileStorage

NewFileStorage returns a default initialized storage backend for persistent files.

func (*FileStorage) Clean added in v0.5.0

func (f *FileStorage) Clean() error

Clean (delete) all stored passwords.

func (*FileStorage) Delete added in v0.5.0

func (f *FileStorage) Delete(id string) error

Delete an existing password.

func (*FileStorage) DumpJSON added in v0.8.4

func (f *FileStorage) DumpJSON() (string, error)

DumpJSON serializes the storage backend to a JSON string. Warning: This method does not block operations on the underlying storage backend (read/write/create/delete). You should stop operations manually before usage or ignore the reported error. Data consistency is guaranteed.

func (*FileStorage) Exists added in v0.5.0

func (f *FileStorage) Exists(id string) (bool, error)

Exists tests if a given id already exists in the storage backend.

func (*FileStorage) FilePath added in v0.5.0

func (f *FileStorage) FilePath(id string) string

FilePath returns the storage filepath of a given password-id with system-specific path separators. It accepts system-unspecific or mixed id separators, i.e. forward- and backward-slashes are treated as the same character.

func (*FileStorage) GetStorePath added in v0.5.0

func (f *FileStorage) GetStorePath() string

GetStorePath returns the current storage path with system-specific path separators.

func (*FileStorage) List added in v0.5.0

func (f *FileStorage) List() ([]string, error)

List all stored password-ids.

func (*FileStorage) LoadJSON added in v0.8.4

func (f *FileStorage) LoadJSON(input string) error

LoadJSON deserializes a JSON string into the storage backend. Warning: This method does not block operations on the underlying storage backend (read/write/create/delete). You should stop operations manually before usage or ignore the reported error. Data consistency is guaranteed.

func (*FileStorage) Retrieve added in v0.5.0

func (f *FileStorage) Retrieve(id string) (string, error)

Retrieve data from an existing file. id is converted to the corresponding filepath.

func (*FileStorage) SetStorePath added in v0.5.0

func (f *FileStorage) SetStorePath(path string)

SetStorePath accepts a new storage path with system-unspecific or mixed path separators.

func (*FileStorage) Store added in v0.5.0

func (f *FileStorage) Store(id string, data string) error

Store (create/overwrite) the provided data in a file. id is converted to the corresponding filepath. If necessary, subfolders are created.

type HashFunc added in v0.2.1

type HashFunc func(data []byte, salt []byte) [32]byte

HashFunc is a function signature. The Hash function will be called for password and secret hashing.

var Hash HashFunc = argon2iHash

Hash will calculate a 32 byte hash from a given byte slice. It is used for password and secret hashing. You can overwrite it with any function that meets the HashFunc signature. By default, it is set to a variant of argon2.Key.

type Manager added in v0.5.0

type Manager struct {
	// HashPassword signals if passwords will be stored as hashes.
	HashPassword bool
	// contains filtered or unexported fields
}

func GetDefaultManager added in v0.5.0

func GetDefaultManager() *Manager

GetDefaultManager returns the current default password manager.

func NewManager added in v0.5.0

func NewManager() *Manager

NewManager creates a new passwordManager instance and applies basic initialization.

func (*Manager) Check added in v0.5.0

func (m *Manager) Check(id string, password string, key string) (bool, error)

Check an existing password for equality with the provided password. key is the encryption secret for storage.

func (*Manager) Clean added in v0.5.0

func (m *Manager) Clean() error

Clean (delete) all stored passwords.

func (*Manager) Delete added in v0.5.0

func (m *Manager) Delete(id string) error

Delete an existing password.

func (*Manager) DisableRecovery added in v0.5.0

func (m *Manager) DisableRecovery()

DisableRecovery will stop recovery key file storage alongside passwords.

func (*Manager) EnableRecovery added in v0.5.0

func (m *Manager) EnableRecovery(key string)

EnableRecovery will enforce recovery key file storage alongside passwords.

func (*Manager) Exists added in v0.5.0

func (m *Manager) Exists(id string) (bool, error)

Exists tests if a given id already exists in the storage backend.

func (*Manager) Get added in v0.5.0

func (m *Manager) Get(id string, key string) (string, error)

Get an existing password with id. key is the encryption secret for storage.

func (*Manager) List added in v0.5.0

func (m *Manager) List() ([]string, error)

List all stored password-ids.

func (*Manager) Overwrite added in v0.5.0

func (m *Manager) Overwrite(id string, password string, key string) error

Overwrite an existing password or create a new one. key is the encryption secret for storage.

func (*Manager) RewriteKey added in v0.8.3

func (m *Manager) RewriteKey(id string, oldKey string, newKey string) error

RewriteKey changes the storage key of a password from oldKey to newKey. Encryption hashes will be renewed. Stored metadata will be unchanged. If enabled, recovery entries will be recreated.

func (*Manager) Set added in v0.5.0

func (m *Manager) Set(id string, oldPassword string, newPassword string, key string) error

Set an existing password-id or create a new one. oldPassword must match the currently stored password. key is the encryption secret for storage.

func (*Manager) Unset added in v0.5.0

func (m *Manager) Unset(id string, password string, key string) error

Unset (delete) an existing password. password must match the currently stored password. key is the encryption secret for storage.

type Storage added in v0.5.0

type Storage interface {
	// Store (create/overwrite) the provided data.
	Store(id string, data string) error

	// Retrieve data from an existing storage entry.
	Retrieve(id string) (string, error)

	// Exists tests if a given id already exists in the storage backend.
	Exists(id string) (bool, error)

	// List all stored password-ids.
	List() ([]string, error)

	// Delete an existing password.
	Delete(id string) error

	// Clean (delete) all stored passwords.
	Clean() error

	// DumpJSON serializes the storage backend to a JSON string.
	DumpJSON() (string, error)

	// LoadJSON deserializes a JSON string into the storage backend.
	LoadJSON(input string) error
}

type TemporaryStorage added in v0.8.0

type TemporaryStorage struct {
	// contains filtered or unexported fields
}

TemporaryStorage is a memory based storage backend.

func NewTemporaryStorage added in v0.8.0

func NewTemporaryStorage() *TemporaryStorage

NewTemporaryStorage returns a memory based storage backend.

func (*TemporaryStorage) Clean added in v0.8.0

func (t *TemporaryStorage) Clean() error

Clean (delete) all stored passwords.

func (*TemporaryStorage) Delete added in v0.8.0

func (t *TemporaryStorage) Delete(id string) error

Delete an existing password.

func (*TemporaryStorage) DumpJSON added in v0.8.4

func (t *TemporaryStorage) DumpJSON() (string, error)

DumpJSON serializes the storage backend to a JSON string.

func (*TemporaryStorage) Exists added in v0.8.0

func (t *TemporaryStorage) Exists(id string) (bool, error)

Exists tests if a given id already exists in the storage backend.

func (*TemporaryStorage) List added in v0.8.0

func (t *TemporaryStorage) List() ([]string, error)

List all stored password-ids.

func (*TemporaryStorage) LoadJSON added in v0.8.4

func (t *TemporaryStorage) LoadJSON(input string) error

LoadJSON deserializes a JSON string into the storage backend.

func (*TemporaryStorage) ReadFromDisk added in v0.8.2

func (t *TemporaryStorage) ReadFromDisk(path string) error

ReadFromDisk loads a FileStorage backend from disk into a temporary storage. Warning: This method does not block operations on the underlying storage backends (read/write/create/delete). You should stop operations manually before usage or ignore the reported error. Data consistency is guaranteed.

func (*TemporaryStorage) Retrieve added in v0.8.0

func (t *TemporaryStorage) Retrieve(id string) (string, error)

Retrieve data from an existing memory location.

func (*TemporaryStorage) Store added in v0.8.0

func (t *TemporaryStorage) Store(id string, data string) error

Store (create/overwrite) the provided data.

func (*TemporaryStorage) WriteToDisk added in v0.8.2

func (t *TemporaryStorage) WriteToDisk(path string) error

WriteToDisk saves the temporary storage to files via FileStorage mechanisms. Warning: This method does not block operations on the underlying storage backends (read/write/create/delete). You should stop operations manually before usage or ignore the reported error. Data consistency is guaranteed.

Directories

Path Synopsis
cmd

Jump to

Keyboard shortcuts

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