Remove signatures

pull/2115/head
Kieran R. Prasch 2020-06-25 19:52:04 -07:00
parent 455e8b1db7
commit 73f05ce061
No known key found for this signature in database
GPG Key ID: FDC3146ED25617D8
3 changed files with 93 additions and 37 deletions

View File

@ -0,0 +1,38 @@
"""
This file is part of nucypher.
nucypher is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
nucypher is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with nucypher. If not, see <https://www.gnu.org/licenses/>.
"""
from typing import List
from nucypher.policy.identity import Card
def paint_single_card(emitter, card: Card) -> None:
card_dict = card.to_json(as_string=False)
emitter.echo('*'*30)
emitter.message(f'{card}')
for field, value in card_dict.items():
emitter.echo(f'{field} ... {value}')
emitter.echo('*'*30)
def paint_cards(emitter, cards: List[Card]) -> None:
for card in cards:
paint_single_card(emitter=emitter, card=card)
# card_dict = card.to_dict()
# headers = [field for field in Card._specification]
# rows = [[n] for n in NetworksInventory.NETWORKS]
# emitter.echo(tabulate(rows, headers=headers, showindex='always'))

View File

@ -44,20 +44,21 @@ class Card:
character_flag=(bytes, 8),
verifying_key=(UmbralPublicKey, 33),
encrypting_key=(UmbralPublicKey, 33),
signature=(Signature, 64),
nickname=(bytes, VariableLengthBytestring)
nickname=(bytes, VariableLengthBytestring),
)
__FLAGS = {
__CARD_TYPES = {
bytes(ALICE): Alice,
bytes(BOB): Bob,
}
__ID_LENGTH = 20 # TODO: Review this size
__MAX_NICKNAME_SIZE = 10
__BASE_PAYLOAD_SIZE = sum(length[1] for length in _specification.values() if isinstance(length[1], int))
__MAX_CARD_LENGTH = __BASE_PAYLOAD_SIZE + __MAX_NICKNAME_SIZE
__FILE_EXTENSION = 'card'
CARD_DIR = Path(DEFAULT_CONFIG_ROOT) / 'cards'
NO_SIGNATURE.bool_value(False)
class InvalidCard(Exception):
"""Raised when an invalid, corrupted, or otherwise unsable card is encountered"""
@ -70,23 +71,31 @@ class Card:
def __init__(self,
character_flag: Union[ALICE, BOB],
verifying_key: UmbralPublicKey,
encrypting_key: Optional[UmbralPublicKey] = None,
signature=NO_SIGNATURE,
verifying_key: Union[UmbralPublicKey, bytes],
encrypting_key: Optional[Union[UmbralPublicKey, bytes]] = None,
card_dir: Path = CARD_DIR,
nickname: bytes = None):
nickname: Optional[Union[bytes, str]] = None):
self.card_dir = card_dir
try:
self.__character_class = self.__FLAGS[bytes(character_flag)]
self.__character_class = self.__CARD_TYPES[bytes(character_flag)]
except KeyError:
raise ValueError(f'Unsupported card type {str(character_flag)}')
self.__character_flag = character_flag
if isinstance(verifying_key, bytes):
verifying_key = UmbralPublicKey.from_bytes(verifying_key)
self.__verifying_key = verifying_key # signing public key
if isinstance(encrypting_key, bytes):
encrypting_key = UmbralPublicKey.from_bytes(encrypting_key)
self.__encrypting_key = encrypting_key # public key
self.__signature = signature
if isinstance(nickname, str):
nickname = nickname.encode()
self.__nickname = nickname
self.__validate()
self.card_dir = card_dir
def __repr__(self) -> str:
name = self.nickname or f'{self.__character_class.__name__}'
@ -102,26 +111,23 @@ class Card:
def __validate(self) -> bool:
if self.__nickname and (len(self.__nickname) > self.__MAX_NICKNAME_SIZE):
raise self.InvalidCard(f'Nickname exceeds maximum length')
if self.__signature is not NO_SIGNATURE:
self.__signature.verify(verifying_key=self.__verifying_key, message=self.__payload)
return True
@staticmethod
def __hash(payload: bytes) -> HexBytes:
@classmethod
def __hash(cls, payload: bytes) -> HexBytes:
blake = hashlib.blake2b()
blake.update(payload)
digest = blake.digest().hex()
return HexBytes(digest)
truncated_digest = digest[:cls.__ID_LENGTH]
return HexBytes(truncated_digest)
#
# Serializers
#
def __bytes__(self) -> bytes:
if self.__signature is NO_SIGNATURE:
raise self.UnsignedCard
self.__validate()
payload = self.__payload
payload += bytes(self.__signature)
if self.nickname:
payload += VariableLengthBytestring(self.__nickname)
return payload
@ -136,8 +142,8 @@ class Card:
self.__verifying_key,
self.__encrypting_key,
)
card_bytes = b''.join(bytes(e) for e in elements)
return card_bytes
payload = b''.join(bytes(e) for e in elements)
return payload
@classmethod
def from_bytes(cls, card_bytes: bytes) -> 'Card':
@ -173,32 +179,46 @@ class Card:
@classmethod
def from_dict(cls, card: Dict):
instance = cls(verifying_key=card['verifying_key'],
instance = cls(nickname=card.get('nickname'),
verifying_key=card['verifying_key'],
encrypting_key=card['encrypting_key'],
character_flag=card['character'])
return instance
def to_dict(self) -> Dict:
payload = dict(
nickname=self.__nickname,
verifying_key=self.verifying_key,
encrypting_key=self.encrypting_key,
character=self.__character_flag
)
return payload
def to_json(self, as_string: bool = True) -> Union[dict, str]:
payload = dict(
nickname=self.__nickname.decode(),
verifying_key=bytes(self.verifying_key).hex(),
encrypting_key=bytes(self.encrypting_key).hex(),
character=bytes(self.__character_flag).hex()
)
if as_string:
payload = json.dumps(payload)
return payload
@classmethod
def from_character(cls, character: Character) -> 'Card':
def from_character(cls, character: Character, nickname: Optional[str] = None) -> 'Card':
flag = getattr(constant_sorrow.constants, character.__class__.__name__.upper())
instance = cls(verifying_key=character.public_keys(power_up_class=SigningPower),
encrypting_key=character.public_keys(power_up_class=DecryptingPower),
character_flag=flag)
instance.sign(signing_power=character._crypto_power.power_ups(SigningPower))
character_flag=flag,
nickname=nickname)
return instance
#
# Card API
#
@property
def verifying_key(self) -> UmbralPublicKey:
return self.__verifying_key
@ -225,13 +245,6 @@ class Card:
def nickname(self, nickname: str) -> None:
self.set_nickname(nickname)
def sign(self, signing_power: SigningPower) -> None:
if signing_power.public_key() != self.__verifying_key:
raise ValueError(f'Cannot sign card for another verifying key')
if self.__signature is not NO_SIGNATURE:
raise RuntimeError(f'Card already signed')
self.__signature = signing_power.sign(self.__payload)
#
# Card Storage API
#
@ -248,7 +261,7 @@ class Card:
os.mkdir(str(self.card_dir))
filename = f'{self.id.hex()}.{self.__FILE_EXTENSION}'
filepath = self.card_dir / filename
with open(str(filepath), 'w') as file:
with open(str(filepath), 'wb') as file:
file.write(encoder(bytes(self)))
return Path(filepath)

View File

@ -18,6 +18,8 @@ GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with nucypher. If not, see <https://www.gnu.org/licenses/>.
"""
import os
import subprocess
import sys
@ -27,11 +29,11 @@ from setuptools.command.develop import develop
from setuptools.command.install import install
from typing import Dict
#
# Metadata
#
PACKAGE_NAME = 'nucypher'
BASE_DIR = Path(__file__).parent
PYPI_CLASSIFIERS = [
@ -89,11 +91,11 @@ class PostDevelopCommand(develop):
develop.run(self)
subprocess.call(f"scripts/installation/install_solc.py")
#
# Requirements
#
def read_requirements(path):
with open(os.path.join(BASE_DIR, path)) as f:
_pipenv_flags, *requirements = f.read().split('\n')
@ -115,18 +117,21 @@ DEPLOY_REQUIRES = [
]
URSULA_REQUIRES = ['prometheus_client', 'sentry-sdk'] # TODO: Consider renaming to 'monitor', etc.
ALICE_REQUIRES = ['qrcode']
BOB_REQUIRES = ['qrcode']
EXTRAS = {
# Admin
'docs': DOCS_REQUIRE,
'dev': DEV_REQUIRES + DOCS_REQUIRE + URSULA_REQUIRES,
'dev': DEV_REQUIRES + DOCS_REQUIRE + URSULA_REQUIRES + ALICE_REQUIRES,
'benchmark': DEV_REQUIRES + BENCHMARK_REQUIRES,
'deploy': DOCS_REQUIRE + DEPLOY_REQUIRES,
# User
'ursula': URSULA_REQUIRES
'ursula': URSULA_REQUIRES,
'alice': ALICE_REQUIRES,
'bob': BOB_REQUIRES
}