blob: ca969c066e783e2bd0aebfba478ed46628113ee9 [file] [log] [blame]
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# ### TBD docco
#
#
import base64
import random
import passlib.hash # note that .argon2 is proxy in this pkg
import passlib.utils # for the RNG, to create Salt values
import cryptography.fernet
# All salt values will be 16 bytes in length. After base64 encoding, they
# will be represented with 22 characters.
SALT_LEN = 16
def gen_salt() -> bytes:
"Generate bytes to be used as a salt, for hashing."
return passlib.utils.getrandbytes(passlib.utils.rng, SALT_LEN)
def gen_opened_key(edata: bytes, salt: bytes) -> bytes:
"Generate the OpenedKey for this election."
return _hash(edata, salt)
def gen_token(opened_key: bytes, value: str, salt: bytes) -> bytes:
"Generate a person or issue token."
return _hash(opened_key + value.encode(), salt)
### fix return type, to be a tuple
def create_vote(person_token: bytes,
issue_token: bytes,
votestring: str) -> bytes:
"Create a vote tuple, to record the VOTESTRING."
salt = gen_salt()
key = _hash(person_token + issue_token, salt)
b64key = base64.urlsafe_b64encode(key)
f = cryptography.fernet.Fernet(b64key)
return salt, f.encrypt(votestring.encode())
def decrypt_votestring(person_token: bytes,
issue_token: bytes,
salt: bytes,
token: bytes) -> str:
"Decrypt TOKEN into a VOTESTRING."
key = _hash(person_token + issue_token, salt)
b64key = base64.urlsafe_b64encode(key)
f = cryptography.fernet.Fernet(b64key)
return f.decrypt(token).decode()
def _hash(data: bytes, salt: bytes) -> bytes:
"Apply our desired hashing function."
ph = passlib.hash.argon2.using(type='d', salt=salt)
h = ph.hash(data)
return base64.standard_b64decode(h.split('$')[-1] + '==')
def shuffle(x):
"Ensure we use the strongest RNG available for shuffling."
return random.shuffle(x, passlib.utils.rng.random)