blob: a9959a665d7b0acbc3c08319bf218809950d53f2 [file] [log] [blame]
Fabio Utzig8101d1f2019-05-09 15:03:22 -03001"""
Fabio Utzig67c59fa2020-04-02 13:09:15 -03002ED25519 key management
Fabio Utzig8101d1f2019-05-09 15:03:22 -03003"""
4
David Brown79c4fcf2021-01-26 15:04:05 -07005# SPDX-License-Identifier: Apache-2.0
6
Fabio Utzig8101d1f2019-05-09 15:03:22 -03007from 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
Rustam Ismayilovef598b12024-07-11 11:50:13 +020036 def get_public_pem(self):
37 return self._get_public().public_bytes(
38 encoding=serialization.Encoding.PEM,
39 format=serialization.PublicFormat.SubjectPublicKeyInfo)
40
Fabio Utzig8f289ba2023-01-09 21:01:55 -030041 def get_private_bytes(self, minimal, format):
Ioannis Konstantelias78e57c72019-11-28 16:06:12 +020042 self._unsupported('get_private_bytes')
43
Fabio Utzig8101d1f2019-05-09 15:03:22 -030044 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
Ross Youngerae9d2562023-02-23 20:23:28 +130064 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
Fabio Utzig8101d1f2019-05-09 15:03:22 -030071
72class Ed25519(Ed25519Public):
73 """
Fabio Utzig67c59fa2020-04-02 13:09:15 -030074 Wrapper around an ED25519 private key.
Fabio Utzig8101d1f2019-05-09 15:03:22 -030075 """
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
Fabio Utzig8f289ba2023-01-09 21:01:55 -030089 def get_private_bytes(self, minimal, format):
Ioannis Konstantelias78e57c72019-11-28 16:06:12 +020090 raise Ed25519UsageError("Operation not supported with {} keys".format(
91 self.shortname()))
92
Fabio Utzig8101d1f2019-05-09 15:03:22 -030093 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)