Skip to content

crypt.keysafe #

Keysafe

A safe implementation to help you sign, encrypt, decrypt and store your keys locally.

Internals

When loading a keysafe object, you can specify a directory and a secret. In that directory, a file called .keys will be created and encrypted using the secret provided (AES-CBC).

Content of that file is a JSON dictionnary of key-name and it's mnemonic, a single mnemonic is enough to derivate ed25519 and x25519 keys.

When loaded, private/public signing key and public/private encryption keys are loaded and ready to be used.

  • key_generate_add() generate a new key and store is as specified name
  • key_import_add() import an existing key based on it's seed and specified name

Example

module main

import freeflowuniverse.crystallib.crypt.keysafe

fn main() {
    mut ks := keysafe.keysafe_get('/tmp/', 'helloworld')!
    println(ks)

    ks.key_generate_add('demo') or { println(err) }
    println(ks)

    if ks.exists('demo') {
        println('key demo exists')
    }
}

Keys

Note about keys: when generating a new key, the "master key" is a SigningKey Ed25519 key. From that key, we can derivate a PrivateKey (encrypting key) X25519.

We can convert public-key only as well. On public key exchange, please always exchange the public SigningKey (aka the master key for us). Based on that SignigKey, we can derivate the Encyption PublicKey and KeysSafe does it for you.

fn key_encode #

fn key_encode(key []u8) string

fn keysafe_get #

fn keysafe_get(path0 string, secret string) !KeysSafe

Note: root key needs to be 'SigningKey' from libsodiumfrom that SigningKey we can derivate PrivateKey needed to encrypt

fn pubkey_new #

fn pubkey_new(name string, myself PrivKey, remote string) !PubKey

fn verifykey_new #

fn verifykey_new(name string, remote string) !VerifyKey

remote is the public master key which needs to verify

struct KeysSafe #

struct KeysSafe {
pub mut:
	path   pathlib.Path       // file path of keys
	loaded bool               // flag to know if keysafe is loaded or loading
	secret string             // secret to encrypt local file
	keys   map[string]PrivKey // list of keys
}

fn (KeysSafe) generate_multiple #

fn (mut ks KeysSafe) generate_multiple(count int) !

for testing purposes you can generate multiple keys

fn (KeysSafe) key_generate_add #

fn (mut ks KeysSafe) key_generate_add(name string) !PrivKey

generate a new key is just importing a key with a random seed

fn (KeysSafe) key_import_add #

fn (mut ks KeysSafe) key_import_add(name string, seed []u8) !PrivKey

import based on an existing seed

fn (KeysSafe) get #

fn (mut ks KeysSafe) get(name string) !PrivKey

fn (KeysSafe) exists #

fn (mut ks KeysSafe) exists(name string) bool

fn (KeysSafe) key_add #

fn (mut ks KeysSafe) key_add(pk PrivKey) !

fn (KeysSafe) persist #

fn (mut ks KeysSafe) persist()

fn (KeysSafe) serialize #

fn (mut ks KeysSafe) serialize() string

fn (KeysSafe) load #

fn (mut ks KeysSafe) load()

fn (KeysSafe) deserialize #

fn (mut ks KeysSafe) deserialize(input string)

struct PersistantKeysSafe #

struct PersistantKeysSafe {
pub mut:
	keys map[string]string // store name/mnemonics only
}

struct PrivKey #

struct PrivKey {
pub:
	name     string
	mnemonic string
	signkey  libsodium.SigningKey // master key
	privkey  libsodium.PrivateKey // derivated from master key
}

fn (PrivKey) master_public #

fn (key PrivKey) master_public() string

retrieve the master public key from PrivKey object this is the public key as need to be shared to a remote user to verify that we signed with our private key is shared as hex key in string format (66 chars)

fn (PrivKey) sign #

fn (key PrivKey) sign(data []u8) []u8

sign data with our signing key data is bytestr output is []u8 bytestring to get bytes from string do: mystring.bytes().

fn (PrivKey) sign_hex #

fn (key PrivKey) sign_hex(data []u8) string

sign data with our signing key. data is bytestr. output is hex string. to get bytes from string do: mystring.bytes(). size of output is ?

struct PubKey #

struct PubKey {
pub:
	name   string
	source PrivKey // ourself (private key, to sign message)
	remote []u8    // target public key (to encrypt)
}

fn (PubKey) encrypt #

fn (key PubKey) encrypt(data []u8) ![]u8

this will encrypt bytes so that only the owner of this pubkey can decrypt it

fn (PubKey) decrypt #

fn (key PubKey) decrypt(data []u8) []u8

verify a signed data

struct VerifyKey #

struct VerifyKey {
pub:
	name   string
	remote libsodium.VerifyKey // target public master key
}

fn (VerifyKey) verify #

fn (key VerifyKey) verify(data []u8) bool

verify a signed data, returns true if signature is correct