Implement Keystore with new models

pull/161/head
tuxxy 2018-02-10 17:01:11 -07:00
parent b894ca6d18
commit 893ae8d24c
3 changed files with 91 additions and 114 deletions

View File

@ -18,9 +18,9 @@ class Key(Base):
is_signing = Column(Boolean, unique=False)
created_at = Column(DateTime, default=datetime.utcnow)
def __init__(self, key_data, is_signing):
def __init__(self, fingerprint, key_data, is_signing):
self.fingerprint = fingerprint
self.key_data = key_data
self.fingerprint = self.get_fingerprint()
self.is_signing = is_signing
@ -57,9 +57,11 @@ class Workorder(Base):
id = Column(Integer, primary_key=True)
bob_pubkey_sig_id = Column(Integer, ForeignKey('keys.id'))
bob_signature = Column(LargeBinary, unique=True)
hrac = Column(LargeBinary, unique=False)
created_at = Column(DateTime, default=datetime.utcnow)
def __init__(self, bob_pubkey_sig_id, hrac):
def __init__(self, bob_pubkey_sig_id, bob_signature, hrac):
self.bob_pubkey_sig_id = bob_pubkey_sig_id
self.bob_signature = bob_signature
self.hrac = hrac

View File

@ -34,7 +34,7 @@ class Keypair(object):
else:
raise ValueError("Either pass a valid key as umbral_key or, if you want to generate keys, set generate_keys_if_needed to True.")
def serialize_pubkey(self, as_bytes=True) -> Union[bytes, str]:
def serialize_pubkey(self, as_b64=False) -> bytes:
"""
Serializes the pubkey for storage/transport in either urlsafe base64
or as a bytestring.
@ -43,9 +43,9 @@ class Keypair(object):
:return: The serialized pubkey in bytes
"""
if as_bytes:
return bytes(self.pubkey)
return self.pubkey.save_key()
if as_b64:
return self.pubkey.save_key()
return bytes(self.pubkey)
def get_fingerprint(self):
"""

View File

@ -1,19 +1,18 @@
import sha3
from nkms.crypto.constants import KFRAG_LENGTH
from nkms.keystore.db.models import Key, KeyFrag
from nkms.keystore.db.models import Key, PolicyContract, Workorder
from nkms.crypto.utils import BytestringSplitter
from nkms.crypto.signature import Signature
from sqlalchemy.orm import sessionmaker
from typing import Union
from umbral.fragments import KFrag
from umbral.keys import UmbralPublicKey
from . import keypairs
class KeyNotFound(KeyError):
class NotFound(Exception):
"""
Exception class for KeyStore get_key calls for keys that don't exist.
Exception class for KeyStore calls for objects that don't exist.
"""
pass
@ -32,45 +31,23 @@ class KeyStore(object):
"""
self.session = sessionmaker(bind=sqlalchemy_engine)()
def _get_fingerprint(self, key: bytes) -> bytes:
def add_key(self,
keypair: Union[keypairs.EncryptingKeypair
keypairs.SigningKeypair]) -> Key:
"""
Hashes the key using keccak_256 and returns the hexdigest in bytes.
:param keypair: Keypair object to store in the keystore.
:param key: Key to hash
:return: Hexdigest fingerprint of key (keccak 256) in bytes
:return: The newly added key object.
"""
return sha3.keccak_256(key).hexdigest().encode()
fingerprint = keypair.get_fingerprint()
key_data = keypair.serialize_pubkey(as_b64=True)
is_signing = isinstance(keypair, keypairs.SigningKeypair)
def generate_encrypting_keypair(self, gen_priv=True) -> keypairs.EncryptingKeypair:
"""
Generates an ECIES keypair.
new_key = Key(fingerprint, key_data, is_signing)
TODO: Initalize keypair with provided data.
:param gen_priv: Generate private key or not?
:return: ECIES encrypting keypair
"""
ecies_keypair = keypairs.EncryptingKeypair()
if gen_priv:
ecies_keypair.gen_privkey()
return ecies_keypair
def generate_signing_keypair(self, gen_priv=True) -> keypairs.SigningKeypair:
"""
Generates an ECDSA keypair.
TODO: Initalize keypair with provided data.
:param gen_priv: Generate private key or not?
:return ECDSA signing keypair
"""
ecdsa_keypair = keypairs.SigningKeypair()
if gen_priv:
ecdsa_keypair.gen_privkey()
return ecdsa_keypair
self.session.add(new_key)
self.session.commit()
return new_key
def get_key(self, fingerprint: bytes) -> Union[keypairs.EncryptingKeypair,
keypairs.SigningKeypair]:
@ -80,74 +57,14 @@ class KeyStore(object):
:param fingerprint: Fingerprint, in bytes, of key to return
:return: Keypair of the returned key.
"""
key = self.session.query(Key).filter_by(fingerprint=fingerprint).first()
if not key:
raise KeyNotFound(
raise NotFound(
"No key with fingerprint {} found.".format(fingerprint))
return keypairs.Keypair.deserialize_key(key.key_data)
def get_kfrag(self, hrac: bytes, get_sig: bool=False):
"""
Returns a RekeyFrag from the KeyStore.
:param hrac: HRAC in bytes
:return: Deserialized RekeyFrag from KeyStore
"""
kfrag = self.session.query(KeyFrag).filter_by(hrac=hrac).first()
if not kfrag:
raise KeyNotFound(
"No KeyFrag with HRAC {} found."
.format(hrac)
)
# TODO: Make this use a class
sig, kfrag = self.kfrag_splitter(kfrag.key_frag)
if get_sig:
return (kfrag, sig)
return kfrag
def add_key(self,
keypair: Union[keypairs.EncryptingKeypair,
keypairs.SigningKeypair],
store_pub: bool = True) -> bytes:
"""
Gets a fingerprint of the key and adds it to the keystore.
:param key: Key, in bytes, to add to lmdb
:return: Fingerprint, in bytes, of the added key
"""
if store_pub:
fingerprint = self._get_fingerprint(keypair.pubkey)
key = keypair.serialize_pubkey()
else:
fingerprint = self._get_fingerprint(keypair.privkey)
key = keypair.serialize_privkey()
# Create new Key object and commit to db
self.session.add(Key(key))
self.session.commit()
return fingerprint
def add_kfrag(self, hrac: bytes, kfrag, sig: bytes=None):
"""
Adds a RekeyFrag to sqlite.
:param hrac: Hashed Resource Authenticate Code
:param kfrag: RekeyFrag instance to add to sqlite
:param sig: Signature of kfrag (if exists)
"""
kfrag_data = b''
if sig:
kfrag_data += sig
kfrag_data += bytes(kfrag)
kfrag = KeyFrag(hrac, kfrag_data)
self.session.add(kfrag)
self.session.commit()
if key.is_signing:
pubkey = UmbralPublicKey(key.key_data, as_b64=True)
return keypairs.SigningKeypair(pubkey)
def del_key(self, fingerprint: bytes):
"""
@ -158,11 +75,69 @@ class KeyStore(object):
self.session.query(Key).filter_by(fingerprint=fingerprint).delete()
self.session.commit()
def del_kfrag(self, hrac: bytes):
def add_policy_contract(self, expiration, deposit, hrac,
alice_pubkey_sig, alice_pubkey_enc,
bob_pubkey_sig, alice_signature) -> PolicyContract:
"""
Deletes a RekeyFrag from sqlite.
Creates a PolicyContract to the Keystore.
:return: The newly added PolicyContract object
"""
# TODO: This can be optimized to one commit/write.
alice_pubkey_sig = self.add_key(alice_pubkey_sig)
alice_pubkey_enc = self.add_key(alice_pubkey_enc)
bob_pubkey_sig = self.add_key(bob_pubkey_sig)
:param hrac: Hashed Resource Authentication Code
new_policy_contract = PolicyContract(
expiration, deposit, hrac, alice_pubkey_sig.id,
alice_pubkey_enc.id, bob_pubkey_sig.id, alice_signature
)
self.session.add(new_policy_contract)
return new_policy_contract
def get_policy_contract(self, hrac: bytes) -> PolicyContract:
"""
self.session.query(KeyFrag).filter_by(hrac=hrac).delete()
Returns the PolicyContract by its HRAC.
:return: The PolicyContract object
"""
policy_contract = self.session.query(PolicyContract).filter_by(hrac=hrac).first()
if not policy_contract:
raise NotFound("No PolicyContract with {} HRAC found.".format(hrac))
return policy_contract
def del_policy_contract(self, hrac: bytes):
"""
Deletes a PolicyContract from the Keystore.
"""
self.session.query(PolicyContract).filter_by(hrac=hrac).delete()
self.session.commit()
def add_workorder(self, bob_pubkey_sig, bob_signature, hrac) -> Workorder:
"""
Adds a Workorder to the keystore.
"""
bob_pubkey_sig = self.add_key(bob_pubkey_sig)
new_workorder = Workorder(bob_pubkey_sig.id, bob_signature, hrac)
self.session.add(new_workorder)
self.session.commit()
return new_workorder
def get_workorder(self, hrac: bytes) -> Workorder:
"""
Returns a list of Workorders by HRAC.
"""
workorders = self.session.query(Workorder).filter_by(hrac)
if not workorders:
raise NotFound("No Workorders with {} HRAC found.".format(hrac))
return workorders
def del_workorder(self, hrac: bytes):
"""
Deletes a Workorder from the Keystore.
"""
self.session.query(Workorder).filter_by(hrac=hrac).delete()
self.session.commit()