crypto.py 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475
  1. """ Generic functions for the cryptographic primitives used in this project. """
  2. from binascii import hexlify, unhexlify
  3. from Crypto.Signature import PKCS1_PSS
  4. from Crypto.Hash import SHA512
  5. from Crypto.PublicKey import RSA
  6. __all__ = ['get_hasher', 'Signing', 'MAX_HASH']
  7. def get_hasher():
  8. """ Returns a object that you can use for hashing, compatible to the `hashlib` interface. """
  9. return SHA512.new()
  10. MAX_HASH = (1 << 512) - 1 # the largest possible hash value
  11. class Signing:
  12. """
  13. Functionality for creating and verifying signatures, and their public/private keys.
  14. :param byte_repr: The bytes serialization of a public key.
  15. """
  16. def __init__(self, byte_repr: bytes):
  17. self.rsa = RSA.importKey(byte_repr)
  18. def verify_sign(self, hashed_value: bytes, signature: bytes) -> bool:
  19. """ Verify a signature for an already hashed value and a public key. """
  20. ver = PKCS1_PSS.new(self.rsa)
  21. h = get_hasher()
  22. h.update(hashed_value)
  23. return ver.verify(h, signature)
  24. def sign(self, hashed_value: bytes) -> bytes:
  25. """ Sign a hashed value with this private key. """
  26. signer = PKCS1_PSS.new(self.rsa)
  27. h = get_hasher()
  28. h.update(hashed_value)
  29. return signer.sign(h)
  30. @classmethod
  31. def generate_private_key(cls):
  32. """ Generate a new private key. """
  33. return Signing(RSA.generate(3072).exportKey())
  34. @classmethod
  35. def from_file(cls, path):
  36. """ Reads a private or public key from the file at `path`. """
  37. with open(path, 'rb') as f:
  38. return cls(f.read())
  39. def as_bytes(self, include_priv: bool=False) -> bytes:
  40. """ Serialize this key to a `bytes` value. """
  41. if include_priv:
  42. return self.rsa.exportKey()
  43. else:
  44. return self.rsa.publickey().exportKey()
  45. def to_json_compatible(self):
  46. """ Returns a JSON-serializable representation of this object. """
  47. return hexlify(self.as_bytes()).decode()
  48. @classmethod
  49. def from_json_compatible(cls, obj):
  50. """ Creates a new object of this class, from a JSON-serializable representation. """
  51. return cls(unhexlify(obj))
  52. def __eq__(self, other: 'Signing'):
  53. return self.rsa.e == other.rsa.e and self.rsa.n == other.rsa.n
  54. def __hash__(self):
  55. return hash((self.rsa.e, self.rsa.n))