Matrix protocol in OCaml, Eio specialised
at main 327 lines 9.6 kB view raw
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