commit 05d924a33e0d5643a4698015c73ad8b38d273230
parent 0a1344624667dfcf15f89655329109ec4280c55f
Author: lash <dev@holbrook.no>
Date: Sat, 28 Mar 2026 08:53:15 -0600
Make pwhash params settable
Diffstat:
5 files changed, 54 insertions(+), 18 deletions(-)
diff --git a/dummy/usawa/crypto.py b/dummy/usawa/crypto.py
@@ -50,16 +50,22 @@ class DID:
return "did:" + self.m + ":" + self.v
-def key_from_export(v, passphrase="", did=None):
+def key_from_export(v, passphrase="", did=None, opslimit=0, memlimit=0):
if passphrase is None:
passphrase = b""
if isinstance(passphrase, str):
passphrase = passphrase.encode("utf-8")
salt = v[: argon2i.SALTBYTES]
- ciphertext = v[argon2i.SALTBYTES :]
+ ciphertext = v[argon2i.SALTBYTES:]
+ if not opslimit:
+ opslimit = nacl.pwhash.OPSLIMIT_INTERACTIVE
+ if not memlimit:
+ memlimit = nacl.pwhash.MEMLIMIT_INTERACTIVE
+
+ logg.debug('pwhash ops {} mem {} salt {} pw {}'.format(opslimit, memlimit, salt, passphrase.hex()))
- key = argon2i.kdf(nacl.secret.SecretBox.KEY_SIZE, passphrase, salt)
+ key = argon2i.kdf(nacl.secret.SecretBox.KEY_SIZE, passphrase, salt, opslimit=opslimit, memlimit=memlimit)
box = nacl.secret.SecretBox(key)
try:
@@ -133,17 +139,16 @@ class Wallet:
:rtype: bytes
:todo: Raise local error if sign fail
"""
-
def sign(self, v):
raise NotImplementedError
+
"""Return the public key data in the wallet.
:returns: Public key data.
:rtype: bytes
:todo: Raise local error if sign fail
"""
-
def pubkey(self):
raise NotImplementedError
@@ -153,10 +158,10 @@ class Wallet:
:rtype: bytes
:todo: Raise local error if sign fail
"""
-
def privkey(self):
raise NotImplementedError
+
"""Verify signature data against the given message.
:param v: Data to verify
@@ -170,7 +175,8 @@ class Wallet:
def verify(self, v, sig):
raise NotImplementedError
- def export(self, passphrase=None):
+
+ def export(self, passphrase=None, opslimit=0, memlimit=0):
if passphrase is None:
passphrase = b""
if isinstance(passphrase, str):
@@ -179,16 +185,23 @@ class Wallet:
logg.warning("exporting key with no passphrase")
salt = os.urandom(argon2i.SALTBYTES)
- key = argon2i.kdf(nacl.secret.SecretBox.KEY_SIZE, passphrase, salt)
+ if not opslimit:
+ opslimit = nacl.pwhash.OPSLIMIT_INTERACTIVE
+ if not memlimit:
+ memlimit = nacl.pwhash.MEMLIMIT_INTERACTIVE
+ logg.debug('pwhash ops {} mem {} salt {} pw {}'.format(opslimit, memlimit, salt, passphrase.hex()))
+ key = argon2i.kdf(nacl.secret.SecretBox.KEY_SIZE, passphrase, salt, opslimit=opslimit, memlimit=memlimit)
box = nacl.secret.SecretBox(key)
k = self.privkey()
r = box.encrypt(k)
return salt + r # prepend salt
+
@staticmethod
- def from_export(v, passphrase=None):
+ def from_export(v, passphrase=None, **kwargs):
raise NotImplementedError()
+
"""Generate an identity XML tree entry from the wallet.
The element generated is valid to be inserted as an identity sub-element in the ledger element.
@@ -283,8 +296,8 @@ class DemoWallet(Wallet):
return r
@staticmethod
- def from_export(v, passphrase=None):
- k = key_from_export(v, passphrase=passphrase)
+ def from_export(v, passphrase=None, opslimit=0, memlimit=0):
+ k = key_from_export(v, passphrase=passphrase, opslimit=opslimit, memlimit=memlimit)
return DemoWallet(privatekey=k)
diff --git a/dummy/usawa/data/usawa.ini b/dummy/usawa/data/usawa.ini
@@ -16,6 +16,8 @@ socket_file_path=
[wallet]
key_passphrase =
+opslimit = 3
+memlimit = 33554432
[fs_resolver]
store_path=
diff --git a/dummy/usawa/runnable/create.py b/dummy/usawa/runnable/create.py
@@ -10,6 +10,8 @@ from usawa import Ledger, DemoWallet, UnitIndex, ACL
import usawa.config
from usawa.store import LedgerStore
from whee.valkey import ValkeyStore
+from whee.fs import FsStore
+from xdg_base_dirs import xdg_data_home
logging.basicConfig(level=logging.DEBUG)
logg = logging.getLogger()
@@ -117,6 +119,7 @@ argp.add_argument('-c', type=str, help='override config dir')
argp.add_argument('--unit-precision', type=int, default=UnitIndex.default_precision, help='Unit precision')
arg = argp.parse_args()
ctx = Context.from_args(arg)
+cfg = usawa.config.load_config(config_dir=arg.c)
def do_interactive(ctx):
@@ -137,7 +140,21 @@ ctx = ctx.open(ctx.output)
ctx.validate()
ledger = Ledger(ctx.uidx, topic=ctx.topic, src=ctx.uri)
-db = ValkeyStore('')
+store_type = cfg.get('STORE_TYPE')
+db = None
+if store_type == 'valkey':
+ db = ValkeyStore(
+ "",
+ host=cfg.get("VALKEY_HOST"),
+ port=cfg.get("VALKEY_PORT"),
+ )
+elif store_type == 'fs':
+ db = FsStore(
+ base=cfg.get('FSSTORE_BASE', xdg_data_home()),
+ dbname='usawa',
+ )
+else:
+ raise ValueError('invalid store type: ' + store_type)
store = LedgerStore(db, ledger)
pk = None
wallet = None
@@ -145,9 +162,11 @@ dt = datetime.datetime.now()
cfg = usawa.config.load_config(config_dir=arg.c)
+ops = int(cfg.get('WALLET_OPSLIMIT', 0))
+mem = int(cfg.get('WALLET_MEMLIMIT', 0))
try:
#pk = store.get_key()
- wallet = store.get_key(DemoWallet, passphrase=cfg.get('WALLET_KEY_PASSPHRASE'))
+ wallet = store.get_key(DemoWallet, passphrase=cfg.get('WALLET_KEY_PASSPHRASE'), opslimit=ops, memlimit=mem)
except FileNotFoundError:
logg.info('no default key found')
wallet = DemoWallet()
diff --git a/dummy/usawa/runnable/setup_wallet.py b/dummy/usawa/runnable/setup_wallet.py
@@ -85,9 +85,11 @@ def setup_wallet(cfg, wallet_dir=None):
with open(publickey_path, "wb") as f:
f.write(pk.encode())
logg.info("public key saved to: %s", publickey_path)
+ ops = int(cfg.get('WALLET_OPSLIMIT', 0))
+ mem = int(cfg.get('WALLET_MEMLIMIT', 0))
wallet = DemoWallet(privatekey=random_bytes)
- store.add_key(wallet, passphrase=passphrase_confirm)
+ store.add_key(wallet, passphrase=passphrase_confirm, opslimit=ops, memlimit=mem)
logg.info("key written to store")
logg.info("setup complete.")
diff --git a/dummy/usawa/store.py b/dummy/usawa/store.py
@@ -170,7 +170,7 @@ class KeyStore(BaseStore):
:type passphrase: bytes
:todo: Implement the ACL lookup
"""
- def add_key(self, wallet, acl=None, default=False, passphrase=None):
+ def add_key(self, wallet, acl=None, default=False, passphrase=None, opslimit=0, memlimit=0):
k = pfx_key()
try:
self.db.get(k)
@@ -180,7 +180,7 @@ class KeyStore(BaseStore):
if default:
self.db.put(k, pubkey, exist_ok=True)
k = pfx_key(pubkey=pubkey)
- v = wallet.export(passphrase=passphrase)
+ v = wallet.export(passphrase=passphrase, opslimit=opslimit, memlimit=memlimit)
self.db.put(k, v)
@@ -199,14 +199,14 @@ class KeyStore(BaseStore):
:return: Resulting wallet
:rtype: usawa.crypto.Wallet
"""
- def get_key(self, wallet_class, pubkey=None, passphrase=None):
+ def get_key(self, wallet_class, pubkey=None, passphrase=None, opslimit=0, memlimit=0):
if pubkey == None:
k = pfx_key()
pubkey = self.db.get(k)
k = pfx_key(pubkey=pubkey)
#return self.db.get(k)
r = self.db.get(k)
- return wallet_class.from_export(r, passphrase=passphrase)
+ return wallet_class.from_export(r, passphrase=passphrase, opslimit=opslimit, memlimit=memlimit)
class EntryStore(BaseStore):