This is an automated email from the ASF dual-hosted git repository.
gstein pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/steve.git
The following commit(s) were added to refs/heads/trunk by this push:
new bd02a36 Use the built-in secrets module.
bd02a36 is described below
commit bd02a360a834dc75fbc3b96bf89b2d78714011bc
Author: Greg Stein <[email protected]>
AuthorDate: Sat Sep 20 03:51:01 2025 -0500
Use the built-in secrets module.
* crypto.shuffle() implements Fisher-Yates shuffling. Safe!
* election.new_eid() more easily uses secrets.token_hex()
---
v3/steve/crypto.py | 18 +++++++++++++++---
v3/steve/election.py | 8 +++-----
2 files changed, 18 insertions(+), 8 deletions(-)
diff --git a/v3/steve/crypto.py b/v3/steve/crypto.py
index ed8b13c..ce72123 100644
--- a/v3/steve/crypto.py
+++ b/v3/steve/crypto.py
@@ -19,7 +19,7 @@
#
import base64
-import random
+import secrets
import passlib.hash # note that .argon2 is proxy in this pkg
import passlib.utils # for the RNG, to create Salt values
@@ -78,5 +78,17 @@ def _hash(data: bytes, salt: bytes) -> bytes:
def shuffle(x):
"Ensure we use the strongest RNG available for shuffling."
- ### second param was removed in 3.11. need to revisit this.
- return random.shuffle(x) ###, passlib.utils.rng.random)
+
+ # Implements the Fisher-Yates shuffle, using secrets.randbelow() for
+ # cryptographically-safe (aka unpredictable) shuffling of elements.
+
+ # Count backwards, "fixing" a chosen element into place.
+ for i in range(len(x)-1, 0, -1):
+ # Choose element to fix from remaining pool.
+ j = secrets.randbelow(i + 1)
+
+ # Swap them in-place.
+ x[i], x[j] = x[j], x[i]
+
+ # We shuffled in-place, but also return for funsies.
+ return x
diff --git a/v3/steve/election.py b/v3/steve/election.py
index 5095586..b8f0eda 100644
--- a/v3/steve/election.py
+++ b/v3/steve/election.py
@@ -22,6 +22,7 @@
import sys
import json
+import secrets
from . import crypto
from . import db
@@ -386,8 +387,5 @@ class Election:
def new_eid():
"Create a new ElectionID."
- # Use 4 bytes of a salt, for 32 bits.
- b = crypto.gen_salt()
-
- # Format into 8 hex characters.
- return f'{b[0]:02x}{b[1]:02x}{b[2]:02x}{b[3]:02x}'
+ # Use 8 hex characters for an ElectionID.
+ return secrets.token_hex(4) # 4 bytes