Add SecretKeyFactory

pull/263/head
Bogdan Opanchuk 2021-03-19 21:34:44 -07:00
parent d532ef1383
commit c419705245
2 changed files with 47 additions and 2 deletions

View File

@ -5,7 +5,7 @@ from .__about__ import (
from .capsule import Capsule
from .capsule_frag import CapsuleFrag
from .key_frag import KeyFrag, generate_kfrags
from .keys import SecretKey, PublicKey
from .keys import SecretKey, PublicKey, SecretKeyFactory
from .pre import encrypt, decrypt_original, decrypt_reencrypted, reencrypt
__all__ = [
@ -19,6 +19,7 @@ __all__ = [
"__url__",
"SecretKey",
"PublicKey",
"SecretKeyFactory",
"Capsule",
"KeyFrag",
"CapsuleFrag",

View File

@ -1,3 +1,4 @@
import os
from typing import TYPE_CHECKING, Tuple
from cryptography.exceptions import InvalidSignature
@ -8,7 +9,7 @@ from . import openssl
from .curve import CURVE
from .curve_scalar import CurveScalar
from .curve_point import CurvePoint
from .dem import DEM
from .dem import kdf
from .serializable import Serializable
if TYPE_CHECKING: # pragma: no cover
@ -136,3 +137,46 @@ class PublicKey(Serializable):
def __hash__(self) -> int:
return hash((self.__class__, bytes(self)))
class SecretKeyFactory(Serializable):
"""
This class handles keying material for Umbral, by allowing deterministic
derivation of SecretKeys based on labels.
Don't use this key material directly as a key.
"""
_KEY_SEED_SIZE = 64
_DERIVED_KEY_SIZE = 64
def __init__(self, key_seed: bytes):
self.__key_seed = key_seed
@classmethod
def random(cls) -> 'SecretKeyFactory':
return cls(os.urandom(cls._KEY_SEED_SIZE))
def secret_key_by_label(self, label: bytes) -> SecretKey:
tag = b"KEY_DERIVATION/" + label
key = kdf(self.__key_seed, self._DERIVED_KEY_SIZE, info=tag)
from .hashing import Hash
digest = Hash(tag)
digest.update(key)
scalar_key = CurveScalar.from_digest(digest)
return SecretKey(scalar_key)
@classmethod
def __take__(cls, data: bytes) -> Tuple['SecretKeyFactory', bytes]:
key_seed, data = cls.__take_bytes__(data, cls._KEY_SEED_SIZE)
return cls(key_seed), data
def __bytes__(self) -> bytes:
return bytes(self.__key_seed)
def __str__(self):
return f"{self.__class__.__name__}:..."
def __hash__(self):
raise NotImplementedError("Hashing secret objects is insecure")