Matrix protocol in OCaml, Eio specialised
1(** Olm/Megolm cryptographic session management.
2
3 This module implements the Olm double-ratchet algorithm for encrypted
4 to-device messages, and Megolm for encrypted room messages.
5
6 @see <https://spec.matrix.org/v1.11/client-server-api/#end-to-end-encryption> E2EE *)
7
8(** {1 Olm Account} *)
9
10(** Olm account - manages identity keys and one-time keys.
11
12 An Olm account contains:
13 - Ed25519 identity key (for signing)
14 - Curve25519 identity key (for key exchange)
15 - One-time keys (for session establishment) *)
16module Account : sig
17 (** Account type. *)
18 type t = {
19 ed25519_priv : Mirage_crypto_ec.Ed25519.priv;
20 ed25519_pub : Mirage_crypto_ec.Ed25519.pub;
21 curve25519_secret : Mirage_crypto_ec.X25519.secret;
22 curve25519_public : string;
23 mutable one_time_keys : (string * (Mirage_crypto_ec.X25519.secret * string)) list;
24 mutable fallback_key : (string * (Mirage_crypto_ec.X25519.secret * string)) option;
25 mutable next_key_id : int;
26 max_one_time_keys : int;
27 }
28
29 val create : unit -> t
30 (** Generate a new Olm account with fresh identity keys. *)
31
32 val ed25519_key : t -> string
33 (** Get the Ed25519 identity key as base64. *)
34
35 val curve25519_key : t -> string
36 (** Get the Curve25519 identity key as base64. *)
37
38 val identity_keys : t -> string * string
39 (** Get the identity keys as a pair (ed25519, curve25519). *)
40
41 val sign : t -> string -> string
42 (** Sign a message with the account's Ed25519 key. *)
43
44 val generate_one_time_keys : t -> int -> unit
45 (** Generate new one-time keys. *)
46
47 val one_time_keys : t -> (string * string) list
48 (** Get one-time keys for upload (key_id -> public_key). *)
49
50 val signed_one_time_keys : t -> (string * string * string) list
51 (** Get signed one-time keys for upload. Returns [(key_id, public_key, signature)]. *)
52
53 val mark_keys_as_published : t -> unit
54 (** Mark one-time keys as published. *)
55
56 val generate_fallback_key : t -> unit
57 (** Generate a fallback key. *)
58
59 val fallback_key : t -> (string * string) option
60 (** Get the fallback key if one exists. *)
61
62 val remove_one_time_key : t -> string -> unit
63 (** Remove a one-time key by ID (after session creation). *)
64
65 val one_time_keys_count : t -> int
66 (** Number of unpublished one-time keys. *)
67
68 val max_one_time_keys : t -> int
69 (** Maximum number of one-time keys this account can hold. *)
70end
71
72(** {1 Olm Session} *)
73
74(** Olm session state for the double ratchet algorithm. *)
75module Session : sig
76 type chain_key = { key : string; index : int }
77 type root_key = string
78 type message_key = string
79
80 (** Session type. *)
81 type t = {
82 session_id : string;
83 their_identity_key : string;
84 mutable their_ratchet_key : string option;
85 mutable our_ratchet_secret : Mirage_crypto_ec.X25519.secret;
86 mutable our_ratchet_public : string;
87 mutable root_key : root_key;
88 mutable sending_chain : chain_key option;
89 mutable receiving_chains : (string * chain_key) list;
90 mutable skipped_keys : ((string * int) * message_key) list;
91 creation_time : Ptime.t;
92 }
93
94 val create_outbound :
95 Account.t ->
96 their_identity_key:string ->
97 their_one_time_key:string ->
98 t
99 (** Create a new outbound session (when sending first message). *)
100
101 val create_inbound :
102 Account.t ->
103 their_identity_key:string ->
104 their_ephemeral_key:string ->
105 one_time_key_id:string ->
106 t
107 (** Create a new inbound session (when receiving first message). *)
108
109 val session_id : t -> string
110 (** Get session ID. *)
111
112 val their_identity_key : t -> string
113 (** Get their identity key. *)
114
115 val encrypt : t -> string -> int * string
116 (** Encrypt a plaintext message. Returns (message_type, ciphertext). *)
117
118 val decrypt : t -> message_type:int -> ciphertext:string -> (string, string) result
119 (** Decrypt a message. *)
120
121 val is_pre_key_message : int -> bool
122 (** Check if this is a pre-key message (first message in session). *)
123end
124
125(** {1 Megolm Sessions} *)
126
127(** Megolm session for room message encryption.
128
129 Megolm uses a ratchet that only moves forward, making it efficient
130 for encrypting many messages to many recipients. *)
131module Megolm : sig
132
133 (** Inbound session for decrypting received room messages. *)
134 module Inbound : sig
135 (** Inbound session type. *)
136 type t = {
137 session_id : string;
138 sender_key : string;
139 room_id : string;
140 mutable ratchet : string array;
141 mutable message_index : int;
142 mutable received_indices : int list;
143 signing_key : string;
144 creation_time : Ptime.t;
145 }
146
147 val of_export :
148 session_id:string ->
149 sender_key:string ->
150 room_id:string ->
151 ratchet:string array ->
152 message_index:int ->
153 signing_key:string ->
154 t
155 (** Create from exported session data. *)
156
157 val from_room_key :
158 sender_key:string ->
159 room_id:string ->
160 session_id:string ->
161 session_key:string ->
162 signing_key:string ->
163 t
164 (** Create from room key event (m.room_key). *)
165
166 val session_id : t -> string
167 (** Get session ID. *)
168
169 val sender_key : t -> string
170 (** Get sender key. *)
171
172 val room_id : t -> string
173 (** Get room ID. *)
174
175 val first_known_index : t -> int
176 (** Get first known message index. *)
177
178 val decrypt : t -> ciphertext:string -> message_index:int -> (string, string) result
179 (** Decrypt a message. *)
180 end
181
182 (** Outbound session for encrypting messages to send to a room. *)
183 module Outbound : sig
184 (** Outbound session type. *)
185 type t = {
186 session_id : string;
187 room_id : string;
188 mutable ratchet : string array;
189 mutable message_index : int;
190 signing_priv : Mirage_crypto_ec.Ed25519.priv;
191 signing_pub : Mirage_crypto_ec.Ed25519.pub;
192 creation_time : Ptime.t;
193 mutable message_count : int;
194 max_messages : int;
195 max_age : Ptime.Span.t;
196 mutable shared_with : (string * string) list;
197 }
198
199 val create : room_id:string -> t
200 (** Create a new outbound session for a room. *)
201
202 val session_id : t -> string
203 (** Get session ID. *)
204
205 val room_id : t -> string
206 (** Get room ID. *)
207
208 val message_index : t -> int
209 (** Get current message index. *)
210
211 val needs_rotation : t -> bool
212 (** Check if session should be rotated. *)
213
214 val export_session_key : t -> string
215 (** Export the session key for sharing via m.room_key. *)
216
217 val signing_key : t -> string
218 (** Get the signing key. *)
219
220 val encrypt : t -> string -> int * string
221 (** Encrypt a message. Returns (message_index, ciphertext). *)
222
223 val mark_shared_with : t -> user_id:string -> device_id:string -> unit
224 (** Mark session as shared with a user/device. *)
225
226 val is_shared_with : t -> user_id:string -> device_id:string -> bool
227 (** Check if already shared with a user/device. *)
228
229 val shared_with : t -> (string * string) list
230 (** Get list of users this session is shared with. *)
231 end
232end
233
234(** {1 Olm Machine} *)
235
236(** Olm Machine - high-level state machine for E2EE operations. *)
237module Machine : sig
238 type t
239 (** Machine type. *)
240
241 val create : user_id:string -> device_id:string -> t
242 (** Create a new OlmMachine. *)
243
244 val identity_keys : t -> string * string
245 (** Get identity keys. *)
246
247 val device_keys_for_upload : t -> string * string * string list * (string * string) list
248 (** Get device keys for upload. Returns (user_id, device_id, algorithms, keys). *)
249
250 val generate_one_time_keys : t -> int -> unit
251 (** Generate one-time keys if needed. *)
252
253 val one_time_keys_for_upload : t -> (string * string * string) list
254 (** Get one-time keys for upload. *)
255
256 val mark_keys_as_published : t -> unit
257 (** Mark keys as uploaded. *)
258
259 val receive_device_keys : t -> user_id:string -> devices:(string * Keys.queried_device_keys) list -> unit
260 (** Store device keys from key query response. *)
261
262 val get_outbound_group_session : t -> room_id:string -> Megolm.Outbound.t
263 (** Get or create outbound Megolm session for a room. *)
264
265 val receive_room_key :
266 t ->
267 sender_key:string ->
268 room_id:string ->
269 session_id:string ->
270 session_key:string ->
271 signing_key:string ->
272 unit
273 (** Store inbound Megolm session from room key event. *)
274
275 val encrypt_room_message : t -> room_id:string -> content:string -> string
276 (** Encrypt a room message using Megolm. *)
277
278 val decrypt_room_message :
279 t ->
280 room_id:string ->
281 sender_key:string ->
282 session_id:string ->
283 ciphertext:string ->
284 message_index:int ->
285 (string, string) result
286 (** Decrypt a room message. *)
287
288 val get_olm_session : t -> their_identity_key:string -> Session.t option
289 (** Get or create Olm session for a device. *)
290
291 val create_olm_session :
292 t ->
293 their_identity_key:string ->
294 their_one_time_key:string ->
295 Session.t
296 (** Create outbound Olm session. *)
297
298 val create_inbound_session :
299 t ->
300 their_identity_key:string ->
301 their_ephemeral_key:string ->
302 one_time_key_id:string ->
303 Session.t
304 (** Process inbound Olm message to create session. *)
305
306 val encrypt_to_device :
307 t ->
308 their_identity_key:string ->
309 their_one_time_key:string ->
310 plaintext:string ->
311 int * string
312 (** Encrypt a to-device message. *)
313
314 val decrypt_to_device :
315 t ->
316 their_identity_key:string ->
317 message_type:int ->
318 ciphertext:string ->
319 (string, string) result
320 (** Decrypt a to-device message. *)
321
322 val one_time_keys_count : t -> int
323 (** Number of one-time keys remaining. *)
324
325 val should_upload_keys : t -> bool
326 (** Should upload more one-time keys? *)
327end