automatic keygen for possible future usage
This commit is contained in:
parent
57f61b9675
commit
8bd20d815c
100
keygen.py
Normal file
100
keygen.py
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
import hmac
|
||||||
|
import hashlib
|
||||||
|
import base64
|
||||||
|
|
||||||
|
salt = "UqEEf08yMDE3qIQodAGAyNQ2EPFhb26f2o85MTIyMeAAkqlANiXcF"
|
||||||
|
|
||||||
|
def generate_secret_key(identifier: str, expiry: str) -> str:
|
||||||
|
"""
|
||||||
|
Generate a secret key with the following structure:
|
||||||
|
- encoded_data: Base64 encoding of (identifier + expiry)
|
||||||
|
- signature: 32 characters from the URL-safe base64 HMAC signature
|
||||||
|
- id_length_hex: 2-character hexadecimal number representing the length of the identifier
|
||||||
|
The HMAC is computed over (encoded_data + id_length_hex).
|
||||||
|
"""
|
||||||
|
global salt
|
||||||
|
if len(identifier) > 255:
|
||||||
|
raise ValueError("Identifier must be at most 255 characters long.")
|
||||||
|
if len(expiry) != 8:
|
||||||
|
raise ValueError("Expiry must be an 8-character string in DDMMYYYY format.")
|
||||||
|
|
||||||
|
# Concatenate identifier and expiry, then base64 encode the result.
|
||||||
|
plain_data = identifier + expiry
|
||||||
|
# Remove padding for compactness; we'll add it back during decoding.
|
||||||
|
encoded_data = base64.urlsafe_b64encode(plain_data.encode()).decode().rstrip("=")
|
||||||
|
|
||||||
|
# Format the length of the identifier as a 2-digit hexadecimal string.
|
||||||
|
id_length_hex = f"{len(identifier):02X}"
|
||||||
|
|
||||||
|
# Build the message for HMAC: encoded_data + id_length_hex.
|
||||||
|
message = encoded_data + id_length_hex
|
||||||
|
|
||||||
|
# Compute HMAC using SHA-256.
|
||||||
|
hmac_digest = hmac.new(salt.encode(), message.encode(), hashlib.sha256).digest()
|
||||||
|
|
||||||
|
# Get a URL-safe base64 representation and take the first 32 characters as the signature.
|
||||||
|
signature = base64.urlsafe_b64encode(hmac_digest).decode()[:32]
|
||||||
|
|
||||||
|
# Construct the final secret key.
|
||||||
|
secret_key = encoded_data + signature + id_length_hex
|
||||||
|
return secret_key
|
||||||
|
|
||||||
|
def decode_secret_key(secret_key: str):
|
||||||
|
"""
|
||||||
|
Decode the secret key and extract the identifier and expiry.
|
||||||
|
|
||||||
|
Token structure:
|
||||||
|
- encoded_data: secret_key[0 : (len(secret_key)-34)] (variable length)
|
||||||
|
- signature: secret_key[-34:-2] (32 characters)
|
||||||
|
- id_length_hex: secret_key[-2:] (2 characters)
|
||||||
|
|
||||||
|
The HMAC is verified over (encoded_data + id_length_hex). Then, encoded_data is base64-decoded
|
||||||
|
(with proper padding added) to yield (identifier + expiry), where the last 8 characters represent expiry.
|
||||||
|
The identifier length is determined from id_length_hex.
|
||||||
|
"""
|
||||||
|
global salt
|
||||||
|
|
||||||
|
if len(secret_key) < 34: # Must at least have signature (32) + id_length_hex (2)
|
||||||
|
raise ValueError("Invalid key length.")
|
||||||
|
|
||||||
|
# Extract the last 2 characters: id_length_hex.
|
||||||
|
id_length_hex = secret_key[-2:]
|
||||||
|
try:
|
||||||
|
id_length = int(id_length_hex, 16)
|
||||||
|
except ValueError:
|
||||||
|
raise ValueError("Invalid identifier length prefix in key.")
|
||||||
|
|
||||||
|
# The signature is the 32 characters preceding the last 2.
|
||||||
|
signature = secret_key[-34:-2]
|
||||||
|
# The remainder is the encoded_data.
|
||||||
|
encoded_data = secret_key[:-34]
|
||||||
|
|
||||||
|
# Verify the signature.
|
||||||
|
message = encoded_data + id_length_hex
|
||||||
|
expected_hmac = hmac.new(salt.encode(), message.encode(), hashlib.sha256).digest()
|
||||||
|
expected_signature = base64.urlsafe_b64encode(expected_hmac).decode()[:32]
|
||||||
|
|
||||||
|
if not hmac.compare_digest(signature, expected_signature):
|
||||||
|
raise ValueError("Invalid key signature.")
|
||||||
|
|
||||||
|
# Base64-decode the encoded_data.
|
||||||
|
# Add back any missing '=' padding.
|
||||||
|
padding = '=' * (-len(encoded_data) % 4)
|
||||||
|
plain_data = base64.urlsafe_b64decode(encoded_data + padding).decode()
|
||||||
|
|
||||||
|
# plain_data should be (identifier + expiry), where expiry is the last 8 characters.
|
||||||
|
if len(plain_data) != id_length + 8:
|
||||||
|
raise ValueError("Decoded data length does not match expected identifier length and expiry.")
|
||||||
|
|
||||||
|
identifier = plain_data[:id_length]
|
||||||
|
expiry = plain_data[id_length:]
|
||||||
|
|
||||||
|
return identifier, expiry
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
key = generate_secret_key("Besondere Gottesdienste", "30042025")
|
||||||
|
print(key)
|
||||||
|
identifier, expiry = decode_secret_key(key)
|
||||||
|
print("identifier:", identifier)
|
||||||
|
print("expiry:", expiry)
|
||||||
Loading…
x
Reference in New Issue
Block a user