Registry / auth-security / spake2

spake2

JSON →
library0.9pypypi✓ verified 85d ago

The `spake2` library is a pure-Python implementation of the SPAKE2 password-authenticated key exchange (PAKE) algorithm. It enables two parties sharing a weak password to securely derive a strong shared secret over an insecure channel, preventing passive eavesdropping and limiting active attackers to a single password guess per protocol execution. The current stable version is 0.9, released in September 2024, with an infrequent release cadence.

pip install spake2
INSTALL
IMPORT
SIG · SPAKE2
S
spake2
auth-securitypythonv0.9
Install
2.3s avg
Import
122ms
Disk
33MB
Pass rate
10/ 10
Env Coverage10 / 10
glibc
3.93.13
musl
3.93.13
Install & Compatibility
Where this runs
tested against v0.9 · pip install
no network on importno background threads
Install × environment matrix
Each cell = how many times install + import succeeded across repeated harness runs. Partial = flaky.
glibc = Debian/Ubuntu slim · musl = Alpine Linux
musl
py 3.103.910 runs
installs and imports cleanly · install 0.0s · import 0.123s · 34.6MB
glibc
py 3.103.910 runs
installs and imports cleanly · install 2.3s · import 0.121s · 35MB
33MB installed
● package 33MB
Code
Verified usage

Verified import paths — ran on the pinned version, not inferred.

SPAKE2_A
from spake2 import SPAKE2_A
SPAKE2_B
from spake2 import SPAKE2_B
SPAKE2_Symmetric
from spake2 import SPAKE2_Symmetric
Use this class if roles (A/B) cannot be pre-determined, providing a symmetric interface.
ParamsEd25519
from spake2.parameters.all import ParamsEd25519
from spake2.params import ParamsEd25519
Specific parameter sets are located in `spake2.parameters` submodules, typically imported from `spake2.parameters.all` for convenience or directly from e.g., `spake2.parameters.i3072`.

This quickstart demonstrates a basic SPAKE2 key exchange between two parties, Alice (role A) and Bob (role B), who share a weak password. Both parties initialize their respective SPAKE2 instances with the shared password and unique identity strings. They then exchange initial messages, process the received message, and derive a strong, shared secret key. The `idA` and `idB` strings are crucial for binding the key to specific parties and preventing replay/substitution attacks. The example uses `ParamsEd25519` for elliptic curve security.

import os from spake2 import SPAKE2_A, SPAKE2_B from spake2.parameters.all import ParamsEd25519 # Or other parameter sets like Params3072 def run_spake2_exchange(password: bytes, idA: bytes, idB: bytes): # Alice (Side A) alice = SPAKE2_A(password, idA=idA, idB=idB, params=ParamsEd25519) alice_msg = alice.start() # Bob (Side B) bob = SPAKE2_B(password, idA=idA, idB=idB, params=ParamsEd25519) bob_msg = bob.start() # Exchange messages # In a real application, alice_msg would be sent to Bob, and bob_msg to Alice. # For this example, we directly pass them. # Alice processes Bob's message alice_key = alice.finish(bob_msg) # Bob processes Alice's message bob_key = bob.finish(alice_msg) print(f"Alice's derived key: {alice_key.hex()}") print(f"Bob's derived key: {bob_key.hex()}") if alice_key == bob_key: print("\nShared secret derived successfully!") return alice_key else: print("\nFailed to derive shared secret. Keys do not match.") return None if __name__ == "__main__": # Example usage shared_password = os.environ.get('SPAKE2_PASSWORD', 'test-password').encode('utf-8') alice_id = b"Alice" bob_id = b"BobServer" print(f"Using password: {shared_password.decode('utf-8')}") print(f"Alice ID: {alice_id.decode('utf-8')}, Bob ID: {bob_id.decode('utf-8')}") derived_key = run_spake2_exchange(shared_password, alice_id, bob_id) if derived_key: # The derived key can then be used for symmetric encryption, HMAC, or fed into HKDF. print(f"Using derived key for subsequent secure communication.")
Debug
Known issues
gotchaThe `spake2` library is not constant-time and does not inherently protect against timing attacks. Applications must ensure that attackers cannot measure the duration of key exchange operations, particularly in sensitive environments.
fix
Implement countermeasures at the application level to obscure timing differences, such as adding random delays or ensuring consistent execution paths regardless of input.
affects: All versions
gotchaThe security of the derived key relies on a strong source of random numbers provided by `os.urandom()`. Do not use this library on systems where `os.urandom()` is known to be weak or compromised.
fix
Ensure the operating system's cryptographic randomness facilities are robust and properly seeded. Consult system documentation or security guides for verifying `os.urandom()` strength.
affects: All versions
gotchaParticipants must correctly agree on their roles (A and B) or use `SPAKE2_Symmetric`. Using the same role (e.g., `SPAKE2_A` on both sides) will result in non-matching keys, indistinguishable from a password mismatch, making debugging difficult.
fix
Clearly define and enforce the roles (A and B) for the communicating parties. Alternatively, use the `SPAKE2_Symmetric` class if both sides need to operate identically without pre-assigned roles.
affects: All versions
gotchaThe `spake2` library expects passwords to be byte strings (e.g., `b"my_password"`). Passing a `str` will lead to a `TypeError`.
fix
Always encode string passwords to bytes before passing them to `SPAKE2_A`, `SPAKE2_B`, or `SPAKE2_Symmetric`. For example, `password.encode('utf-8')`.
affects: All versions
gotchaEach `SPAKE2` instance and the messages it generates are single-use. Reusing an instance for multiple key exchanges or replaying messages will result in protocol failure and potential security vulnerabilities.
fix
Create new `SPAKE2_A`, `SPAKE2_B`, or `SPAKE2_Symmetric` instances for every new key exchange session. Do not reuse old messages or state objects.
affects: All versions
Errors
Common errors & fixes
Failed to derive shared secret. Keys do not match.
This typically occurs when the shared password does not match, the `idA`/`idB` identifiers are inconsistent, or the roles (A/B) were incorrectly assigned (e.g., both sides initialized as `SPAKE2_A`).
fix
Verify that both parties use the exact same password and identity strings. Confirm that one party is `SPAKE2_A` and the other is `SPAKE2_B`, or both are `SPAKE2_Symmetric`.
TypeError: password must be bytes, not str
The `spake2` library's constructors for `SPAKE2_A`, `SPAKE2_B`, and `SPAKE2_Symmetric` require the password argument to be a byte string.
fix
Convert the password string to bytes using `.encode()` before passing it to the SPAKE2 constructor, e.g., `SPAKE2_A(b'my_password', ...)` or `SPAKE2_A('my_password'.encode('utf-8'), ...)`.
ModuleNotFoundError: No module named 'spake2.parameters'
Attempting to import parameter sets from an incorrect or non-existent path. Specific parameter sets (e.g., `ParamsEd25519`, `Params3072`) are located within the `spake2.parameters` package.
fix
Ensure the import path is correct. Common parameter sets can be imported from `from spake2.parameters.all import ...` or directly from their specific submodules like `from spake2.parameters.i3072 import Params3072`.
Upgrade
Version history
0.9latest on PyPI · released Sep 25, 2024
Audit
Dependencies
cryptographyrequiredUsed internally for HKDF (HMAC-based Key Derivation Function).
Agent activity
14 hits · last 30 days
node
12
OpenAI (training)
1
Resources
spake2 — pip install spake2 · libregistry