1""" 2ED25519 key management 3""" 4 5# SPDX-License-Identifier: Apache-2.0 6 7from cryptography.hazmat.primitives import serialization 8from cryptography.hazmat.primitives.asymmetric import ed25519 9 10from .general import KeyClass 11 12 13class Ed25519UsageError(Exception): 14 pass 15 16 17class Ed25519Public(KeyClass): 18 def __init__(self, key): 19 self.key = key 20 21 def shortname(self): 22 return "ed25519" 23 24 def _unsupported(self, name): 25 raise Ed25519UsageError("Operation {} requires private key".format(name)) 26 27 def _get_public(self): 28 return self.key 29 30 def get_public_bytes(self): 31 # The key is embedded into MBUboot in "SubjectPublicKeyInfo" format 32 return self._get_public().public_bytes( 33 encoding=serialization.Encoding.DER, 34 format=serialization.PublicFormat.SubjectPublicKeyInfo) 35 36 def get_public_pem(self): 37 return self._get_public().public_bytes( 38 encoding=serialization.Encoding.PEM, 39 format=serialization.PublicFormat.SubjectPublicKeyInfo) 40 41 def get_private_bytes(self, minimal, format): 42 self._unsupported('get_private_bytes') 43 44 def export_private(self, path, passwd=None): 45 self._unsupported('export_private') 46 47 def export_public(self, path): 48 """Write the public key to the given file.""" 49 pem = self._get_public().public_bytes( 50 encoding=serialization.Encoding.PEM, 51 format=serialization.PublicFormat.SubjectPublicKeyInfo) 52 with open(path, 'wb') as f: 53 f.write(pem) 54 55 def sig_type(self): 56 return "ED25519" 57 58 def sig_tlv(self): 59 return "ED25519" 60 61 def sig_len(self): 62 return 64 63 64 def verify_digest(self, signature, digest): 65 """Verify that signature is valid for given digest""" 66 k = self.key 67 if isinstance(self.key, ed25519.Ed25519PrivateKey): 68 k = self.key.public_key() 69 return k.verify(signature=signature, data=digest) 70 71 72class Ed25519(Ed25519Public): 73 """ 74 Wrapper around an ED25519 private key. 75 """ 76 77 def __init__(self, key): 78 """key should be an instance of EllipticCurvePrivateKey""" 79 self.key = key 80 81 @staticmethod 82 def generate(): 83 pk = ed25519.Ed25519PrivateKey.generate() 84 return Ed25519(pk) 85 86 def _get_public(self): 87 return self.key.public_key() 88 89 def get_private_bytes(self, minimal, format): 90 raise Ed25519UsageError("Operation not supported with {} keys".format( 91 self.shortname())) 92 93 def export_private(self, path, passwd=None): 94 """ 95 Write the private key to the given file, protecting it with the 96 optional password. 97 """ 98 if passwd is None: 99 enc = serialization.NoEncryption() 100 else: 101 enc = serialization.BestAvailableEncryption(passwd) 102 pem = self.key.private_bytes( 103 encoding=serialization.Encoding.PEM, 104 format=serialization.PrivateFormat.PKCS8, 105 encryption_algorithm=enc) 106 with open(path, 'wb') as f: 107 f.write(pem) 108 109 def sign_digest(self, digest): 110 """Return the actual signature""" 111 return self.key.sign(data=digest) 112