1# This file is dual licensed under the terms of the Apache License, Version
2# 2.0, and the BSD License. See the LICENSE file in the root of this repository
3# for complete details.
4
5from __future__ import annotations
6
7import abc
8
9from cryptography.exceptions import UnsupportedAlgorithm, _Reasons
10from cryptography.hazmat.bindings._rust import openssl as rust_openssl
11from cryptography.hazmat.primitives import _serialization
12from cryptography.utils import Buffer
13
14
15class MLKEM768PublicKey(metaclass=abc.ABCMeta):
16 @classmethod
17 def from_public_bytes(cls, data: Buffer) -> MLKEM768PublicKey:
18 from cryptography.hazmat.backends.openssl.backend import backend
19
20 if not backend.mlkem_supported():
21 raise UnsupportedAlgorithm(
22 "ML-KEM-768 is not supported by this backend.",
23 _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM,
24 )
25
26 return rust_openssl.mlkem.from_mlkem768_public_bytes(data)
27
28 @abc.abstractmethod
29 def encapsulate(self) -> tuple[bytes, bytes]:
30 """
31 Encapsulate: returns (shared_secret, ciphertext).
32 """
33
34 @abc.abstractmethod
35 def public_bytes(
36 self,
37 encoding: _serialization.Encoding,
38 format: _serialization.PublicFormat,
39 ) -> bytes:
40 """
41 The serialized bytes of the public key.
42 """
43
44 @abc.abstractmethod
45 def public_bytes_raw(self) -> bytes:
46 """
47 The raw bytes of the public key.
48 Equivalent to public_bytes(Raw, Raw).
49
50 The public key is 1,184 bytes for ML-KEM-768.
51 """
52
53 @abc.abstractmethod
54 def __eq__(self, other: object) -> bool:
55 """
56 Checks equality.
57 """
58
59 @abc.abstractmethod
60 def __copy__(self) -> MLKEM768PublicKey:
61 """
62 Returns a copy.
63 """
64
65 @abc.abstractmethod
66 def __deepcopy__(self, memo: dict) -> MLKEM768PublicKey:
67 """
68 Returns a deep copy.
69 """
70
71
72if hasattr(rust_openssl, "mlkem"):
73 MLKEM768PublicKey.register(rust_openssl.mlkem.MLKEM768PublicKey)
74
75
76class MLKEM768PrivateKey(metaclass=abc.ABCMeta):
77 @classmethod
78 def generate(cls) -> MLKEM768PrivateKey:
79 from cryptography.hazmat.backends.openssl.backend import backend
80
81 if not backend.mlkem_supported():
82 raise UnsupportedAlgorithm(
83 "ML-KEM-768 is not supported by this backend.",
84 _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM,
85 )
86
87 return rust_openssl.mlkem.generate_mlkem768_key()
88
89 @classmethod
90 def from_seed_bytes(cls, data: Buffer) -> MLKEM768PrivateKey:
91 from cryptography.hazmat.backends.openssl.backend import backend
92
93 if not backend.mlkem_supported():
94 raise UnsupportedAlgorithm(
95 "ML-KEM-768 is not supported by this backend.",
96 _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM,
97 )
98
99 return rust_openssl.mlkem.from_mlkem768_seed_bytes(data)
100
101 @abc.abstractmethod
102 def decapsulate(self, ciphertext: Buffer) -> bytes:
103 """
104 Decapsulate: returns shared_secret.
105 """
106
107 @abc.abstractmethod
108 def public_key(self) -> MLKEM768PublicKey:
109 """
110 The MLKEM768PublicKey derived from this private key.
111 """
112
113 @abc.abstractmethod
114 def private_bytes(
115 self,
116 encoding: _serialization.Encoding,
117 format: _serialization.PrivateFormat,
118 encryption_algorithm: _serialization.KeySerializationEncryption,
119 ) -> bytes:
120 """
121 The serialized bytes of the private key.
122 """
123
124 @abc.abstractmethod
125 def private_bytes_raw(self) -> bytes:
126 """
127 The raw bytes of the private key (64-byte seed).
128 Equivalent to private_bytes(Raw, Raw, NoEncryption()).
129 """
130
131 @abc.abstractmethod
132 def __copy__(self) -> MLKEM768PrivateKey:
133 """
134 Returns a copy.
135 """
136
137 @abc.abstractmethod
138 def __deepcopy__(self, memo: dict) -> MLKEM768PrivateKey:
139 """
140 Returns a deep copy.
141 """
142
143
144if hasattr(rust_openssl, "mlkem"):
145 MLKEM768PrivateKey.register(rust_openssl.mlkem.MLKEM768PrivateKey)
146
147
148class MLKEM1024PublicKey(metaclass=abc.ABCMeta):
149 @classmethod
150 def from_public_bytes(cls, data: Buffer) -> MLKEM1024PublicKey:
151 from cryptography.hazmat.backends.openssl.backend import backend
152
153 if not backend.mlkem_supported():
154 raise UnsupportedAlgorithm(
155 "ML-KEM-1024 is not supported by this backend.",
156 _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM,
157 )
158
159 return rust_openssl.mlkem.from_mlkem1024_public_bytes(data)
160
161 @abc.abstractmethod
162 def encapsulate(self) -> tuple[bytes, bytes]:
163 """
164 Encapsulate: returns (shared_secret, ciphertext).
165 """
166
167 @abc.abstractmethod
168 def public_bytes(
169 self,
170 encoding: _serialization.Encoding,
171 format: _serialization.PublicFormat,
172 ) -> bytes:
173 """
174 The serialized bytes of the public key.
175 """
176
177 @abc.abstractmethod
178 def public_bytes_raw(self) -> bytes:
179 """
180 The raw bytes of the public key.
181 Equivalent to public_bytes(Raw, Raw).
182
183 The public key is 1,568 bytes for ML-KEM-1024.
184 """
185
186 @abc.abstractmethod
187 def __eq__(self, other: object) -> bool:
188 """
189 Checks equality.
190 """
191
192 @abc.abstractmethod
193 def __copy__(self) -> MLKEM1024PublicKey:
194 """
195 Returns a copy.
196 """
197
198 @abc.abstractmethod
199 def __deepcopy__(self, memo: dict) -> MLKEM1024PublicKey:
200 """
201 Returns a deep copy.
202 """
203
204
205if hasattr(rust_openssl, "mlkem"):
206 MLKEM1024PublicKey.register(rust_openssl.mlkem.MLKEM1024PublicKey)
207
208
209class MLKEM1024PrivateKey(metaclass=abc.ABCMeta):
210 @classmethod
211 def generate(cls) -> MLKEM1024PrivateKey:
212 from cryptography.hazmat.backends.openssl.backend import backend
213
214 if not backend.mlkem_supported():
215 raise UnsupportedAlgorithm(
216 "ML-KEM-1024 is not supported by this backend.",
217 _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM,
218 )
219
220 return rust_openssl.mlkem.generate_mlkem1024_key()
221
222 @classmethod
223 def from_seed_bytes(cls, data: Buffer) -> MLKEM1024PrivateKey:
224 from cryptography.hazmat.backends.openssl.backend import backend
225
226 if not backend.mlkem_supported():
227 raise UnsupportedAlgorithm(
228 "ML-KEM-1024 is not supported by this backend.",
229 _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM,
230 )
231
232 return rust_openssl.mlkem.from_mlkem1024_seed_bytes(data)
233
234 @abc.abstractmethod
235 def decapsulate(self, ciphertext: Buffer) -> bytes:
236 """
237 Decapsulate: returns shared_secret.
238 """
239
240 @abc.abstractmethod
241 def public_key(self) -> MLKEM1024PublicKey:
242 """
243 The MLKEM1024PublicKey derived from this private key.
244 """
245
246 @abc.abstractmethod
247 def private_bytes(
248 self,
249 encoding: _serialization.Encoding,
250 format: _serialization.PrivateFormat,
251 encryption_algorithm: _serialization.KeySerializationEncryption,
252 ) -> bytes:
253 """
254 The serialized bytes of the private key.
255 """
256
257 @abc.abstractmethod
258 def private_bytes_raw(self) -> bytes:
259 """
260 The raw bytes of the private key (64-byte seed).
261 Equivalent to private_bytes(Raw, Raw, NoEncryption()).
262 """
263
264 @abc.abstractmethod
265 def __copy__(self) -> MLKEM1024PrivateKey:
266 """
267 Returns a copy.
268 """
269
270 @abc.abstractmethod
271 def __deepcopy__(self, memo: dict) -> MLKEM1024PrivateKey:
272 """
273 Returns a deep copy.
274 """
275
276
277if hasattr(rust_openssl, "mlkem"):
278 MLKEM1024PrivateKey.register(rust_openssl.mlkem.MLKEM1024PrivateKey)