password

package module
v0.6.0 Latest Latest
Warning

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

Go to latest
Published: Dec 17, 2024 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"
    "log/slog"
)

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(slog.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.
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 and recovery mode. Additionally, you can just explore the source code with any godoc compatible IDE.

Check it out!

Documentation

Index

Constants

View Source
const DefaultFileEnding string = "pwd"

DefaultFileEnding is the default file ending for password files of a file storage backend.

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 and file suffix that identifies recovery key files.

Variables

View Source
var Managers map[string]*Manager = 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 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 DisableRecovery added in v0.3.2

func DisableRecovery()

DisableRecovery will stop recovery key file storage alongside passwords.

func EnableRecovery added in v0.3.2

func EnableRecovery(key string)

EnableRecovery will enforce recovery key file storage alongside passwords.

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 GetFileEnding

func GetFileEnding() (string, error)

GetFileEnding returns the current file ending of storage files.

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 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 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 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 SetFileEnding

func SetFileEnding(e string) error

SetFileEnding accepts a new file ending for storage files.

func SetStorePath

func SetStorePath(path string) error

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

func ToggleHashPassword added in v0.5.0

func ToggleHashPassword() bool

ToggleHashPassword will toggle the config variable HashPassword of the default password manager and return the current state.

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.

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

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) 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) GetFileEnding added in v0.5.0

func (f *FileStorage) GetFileEnding() string

GetFileEnding returns the current file ending of storage files.

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) 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) SetFileEnding added in v0.5.0

func (f *FileStorage) SetFileEnding(e string)

SetFileEnding accepts a new file ending for storage files.

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) 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(id string, data string) error
	Retrieve(id string) (string, error)
	Exists(id string) (bool, error)
	List() ([]string, error)
	Delete(id string) error
	Clean() error
}

Directories

Path Synopsis
cmd
exampleservice command
patchheader command
recovery command

Jump to

Keyboard shortcuts

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