diff --git a/src/encipher_nkode.py b/src/encipher_nkode.py deleted file mode 100644 index f1b8fe1..0000000 --- a/src/encipher_nkode.py +++ /dev/null @@ -1,57 +0,0 @@ -from secrets import choice -import base64 -from src.models import ( - CustomerInterface, - UserEncipherKeys, - EncipheredNKode, - CustomerAttribute -) - - -def pad_user_mask(user_mask: list[int], customer_interface: CustomerInterface, max_nkode_len: int) -> list[int]: - assert (len(user_mask) <= max_nkode_len) - set_vals = customer_interface.get_set_values() - padded_user_mask = user_mask.copy() - for _ in range(max_nkode_len - len(user_mask)): - padded_user_mask.append(choice(set_vals)) - return padded_user_mask - - -def pad_user_code(user_code: list[int], max_nkode_len: int) -> list[int]: - assert (len(user_code) <= max_nkode_len) - return user_code + [0 for _ in range(max_nkode_len - len(user_code))] - - -def encode_base64_str(data: list[int]) -> str: - return base64.b64encode(data).decode("utf-8") - - -def decode_base64_str(data: str) -> list[int]: - return list(base64.b64decode(data)) - - -def hash_data(data: list[int]) -> bytes: - pass - - -def encipher_nkode( - user_nkode_attributes: list[CustomerAttribute], - user_keys: UserEncipherKeys, - customer_interface: CustomerInterface -) -> EncipheredNKode: - max_nkode_len = 10 - user_nkode_mask = [attr.set_val for attr in user_nkode_attributes] - user_nkode_attrs = [attr.attr_val for attr in user_nkode_attributes] - mask_cipher = pad_user_mask(user_nkode_mask, customer_interface, max_nkode_len) - passcode_cipher = pad_user_code(user_nkode_attrs, max_nkode_len) - - for idx in range(max_nkode_len): - set_idx = customer_interface.get_set_index(user_nkode_attributes[idx].set_val) - attr_idx = customer_interface.get_set_index(user_nkode_attributes[idx].attr_val) - passcode_cipher ^= user_keys.alpha_key[set_idx][attr_idx] ^ user_keys.pass_key[idx] - mask_cipher ^= user_keys.set_key[set_idx] ^ user_keys.mask_key[idx] - - return EncipheredNKode( - code="", - mask="" - ) diff --git a/src/models.py b/src/models.py index 4aaf8b0..e57f805 100644 --- a/src/models.py +++ b/src/models.py @@ -1,94 +1,11 @@ -import secrets from pydantic import BaseModel -from src.utils import ( - generate_random_list, generate_random_matrix, xor_lists, -) -class UserEncipherKeys(BaseModel): - alpha_key: list[list[int]] - set_key: list[int] - pass_key: list[int] - mask_key: list[int] - # TODO: add these - # height - # width - # max_nkode_len - - @staticmethod - def new_user_encipher_keys(height: int, width: int, set_values: list[int]): - assert len(set_values) == width - - set_key = generate_random_list(width) - set_key = xor_lists(set_key, set_values) - - return UserEncipherKeys( - alpha_key=generate_random_matrix(width, height), - pass_key=generate_random_list(height), - mask_key=generate_random_list(height), - set_key=set_key, - ) - - -class CustomerAttribute(BaseModel): +class NKodeAttribute(BaseModel): attr_val: int set_val: int -class CustomerInterface(BaseModel): - # base_interface: { set0: [(attr0, set0) ... (attrN, set0)], ... setM: [(attr0, setM) ... (attrN, setM)]} - base_interface: dict[int, CustomerAttribute] - height: int - width: int - - def __init__(self, **data): - super().__init__(**data) - self._set_index_lookup: dict[int, int] = {} - self._attr_index_lookup: dict[CustomerAttribute: (int, int)] = {} - self._map_base_interface() - - def _map_base_interface(self): - for set_idx, set_val in enumerate(self.base_interface.keys()): - attrs = self.base_interface[set_val] - self._set_index_lookup[set_val] = set_idx - for attr_idx, attr in enumerate(attrs): - self._attr_index_lookup[attr] = attr_idx - - @staticmethod - def new_interface(height: int, width: int): - assert (height <= 256) - assert (width <= 256) - - base_interface = {} - possible_set_vals = list(range(256)) - for w in range(width): - cur_set = secrets.choice(possible_set_vals) - possible_attr_values = list(range(256)) - base_interface[cur_set] = [] - for h in range(height): - cur_attr = secrets.choice(possible_attr_values) - base_interface[cur_set].append(CustomerAttribute(attr_val=cur_attr, set_val=cur_set)) - possible_attr_values.remove(cur_attr) - possible_set_vals.remove(cur_set) - - return CustomerInterface( - base_interface=base_interface, - height=height, - width=width, - ) - - def get_set_values(self) -> list[int]: - return list(self.base_interface.keys()) - - def get_attr_index(self, attr: CustomerAttribute) -> int: - assert(attr in self._attr_index_lookup.keys()) - return self._attr_index_lookup[attr] - - def get_set_index(self, set_val: int) -> int: - assert(set_val in self.get_set_values()) - return self._set_index_lookup[set_val] - - class EncipheredNKode(BaseModel): code: str mask: str diff --git a/src/nkode_interface.py b/src/nkode_interface.py new file mode 100644 index 0000000..d5de170 --- /dev/null +++ b/src/nkode_interface.py @@ -0,0 +1,31 @@ +from pydantic import BaseModel +from src.utils import generate_random_nonrepeating_list, generate_random_nonrepeating_matrix + + +class NKodeInterface(BaseModel): + interface: list[int] + set_vals: list[int] + numb_keys: int + numb_of_sets: int + + @staticmethod + def new_interface(numb_keys: int, numb_of_sets: int): + assert (numb_keys <= 256) + assert (numb_of_sets <= 256) + + return NKodeInterface( + interface=generate_random_nonrepeating_list(numb_of_sets*numb_keys), + sel_vals=generate_random_nonrepeating_list(numb_of_sets), + numb_keys=numb_keys, + numb_of_sets=numb_of_sets, + ) + + def get_attr_set_val(self, attr: int) -> int: + assert(attr in self.interface) + attr_idx = self.interface.index(attr) + set_idx = attr_idx % self.numb_of_sets + return self.set_vals[set_idx] + + def get_set_index(self, set_val: int) -> int: + assert(set_val in self.get_set_values()) + return self._set_index_lookup[set_val] diff --git a/src/user_cipher_keys.py b/src/user_cipher_keys.py new file mode 100644 index 0000000..8ad830f --- /dev/null +++ b/src/user_cipher_keys.py @@ -0,0 +1,82 @@ +import base64 +import hashlib + +import bcrypt +from secrets import choice +from pydantic import BaseModel + +from src.models import NKodeAttribute, EncipheredNKode +from src.nkode_interface import NKodeInterface +from src.utils import generate_random_nonrepeating_list, xor_lists, generate_random_nonrepeating_matrix + + +class UserCipherKeys(BaseModel): + alpha_key: list[list[int]] + set_key: list[int] + pass_key: list[int] + mask_key: list[int] + salt: bytes + + @staticmethod + def new_user_encipher_keys(numb_of_keys: int, attrs_per_key: int, set_values: list[int]): + assert len(set_values) == attrs_per_key + + set_key = generate_random_nonrepeating_list(attrs_per_key) + set_key = xor_lists(set_key, set_values) + + return UserCipherKeys( + alpha_key=generate_random_nonrepeating_matrix(attrs_per_key, numb_of_keys), + pass_key=generate_random_nonrepeating_list(numb_of_keys), + mask_key=generate_random_nonrepeating_list(numb_of_keys), + set_key=set_key, + salt=bcrypt.gensalt(), + ) + + @staticmethod + def pad_user_mask(user_mask: list[int], customer_interface: NKodeInterface, max_nkode_len: int) -> list[int]: + assert (len(user_mask) <= max_nkode_len) + set_vals = customer_interface.set_ + padded_user_mask = user_mask.copy() + for _ in range(max_nkode_len - len(user_mask)): + padded_user_mask.append(choice(set_vals)) + return padded_user_mask + + @staticmethod + def pad_user_code(user_code: list[int], max_nkode_len: int) -> list[int]: + assert (len(user_code) <= max_nkode_len) + return user_code + [0 for _ in range(max_nkode_len - len(user_code))] + + @staticmethod + def encode_base64_str(data: list[int]) -> str: + return base64.b64encode(data).decode("utf-8") + + @staticmethod + def decode_base64_str(data: str) -> list[int]: + return list(base64.b64decode(data)) + + def _hash_passcode(self, passcode: list[int]) -> str: + passcode_digest = base64.b64encode(hashlib.sha256(passcode).digest()) + hashed_data = bcrypt.hashpw(passcode_digest, self.salt) + return hashed_data.decode("utf-8") + + def encipher_nkode( + self, + nkode_attr_index: list[NKodeAttribute], + customer_interface: NKodeInterface + ) -> EncipheredNKode: + max_nkode_len = 10 + user_nkode_mask = [attr.set_val for attr in user_nkode_attributes] + user_nkode_attrs = [attr.attr_val for attr in user_nkode_attributes] + mask_cipher = self.pad_user_mask(user_nkode_mask, customer_interface, max_nkode_len) + passcode_cipher = self.pad_user_code(user_nkode_attrs, max_nkode_len) + + for idx in range(max_nkode_len): + set_idx = customer_interface.get_set_index(user_nkode_attributes[idx].set_val) + attr_idx = customer_interface.get_set_index(user_nkode_attributes[idx].attr_val) + passcode_cipher ^= self.alpha_key[set_idx][attr_idx] ^ self.pass_key[idx] + mask_cipher ^= self.set_key[set_idx] ^ self.mask_key[idx] + + return EncipheredNKode( + code=self._hash_passcode(passcode_cipher), + mask=self.base64.b64encode(mask_cipher).decode("utf-8") + ) diff --git a/test/test_encipher.py b/test/test_encipher.py index ec8f813..d19c352 100644 --- a/test/test_encipher.py +++ b/test/test_encipher.py @@ -1,5 +1,4 @@ import pytest -from src.encipher_nkode import encipher_nkode def test_encipher_nkode():