password

package module
v0.3.3 Latest Latest
Warning

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

Go to latest
Published: Oct 20, 2024 License: BSD-3-Clause Imports: 19 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: {}

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 RecoveryIdSuffix string = ".recovery"

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

Variables

View Source
var HashPassword bool = false

HashPassword signals if passwords will be stored as hashes.

View Source
var StorageDirMode os.FileMode = 0700

StorageDirMode controls the directory permission set by this package.

View Source
var StorageFileMode os.FileMode = 0600

StorageFileMode controls the file permission set by this package.

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 FilePath

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

GetFileEnding returns the current file ending of storage files.

func GetStorePath

func GetStorePath() string

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

func SetFileEnding(e string)

SetFileEnding accepts a new file ending for storage files.

func SetStorePath

func SetStorePath(path string)

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

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

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