upstream: https://github.com/mirage/mirage-crypto
1(** Simpler crypto
2
3 Mirage-crypto is a cryptographic library.
4
5 The overarching API principle is simply mapping inputs to outputs, wherever
6 feasible.
7
8 Similar algorithms in the same class (like {{!Hash}hashes} or
9 {{!Cipher_block}block ciphers}) are presented as distinct modules sharing
10 the same signature.
11
12 The opam package mirage-crypto-rng provides a cryptographically secure
13 pseudo-random number generator, the package mirage-crypto-pk provides public
14 key cryptography. *)
15
16(**/**)
17
18(** A treasure-trove of random utilities.
19
20 This is largely an internal API used in related sub-libraries or tests. As
21 such, it is prone to breakage. *)
22module Uncommon : sig
23 val ( // ) : int -> int -> int
24 (** [x // y] is the ceiling division [ceil (x / y)].
25
26 [x // y] is [0] for any non-positive [x].
27
28 @raise Division_by_zero when [y < 1]. *)
29
30 val imin : int -> int -> int
31
32 val imax : int -> int -> int
33 (** [imax a b] returns the larger of [a] and [b]. *)
34
35 val iter2 : 'a -> 'a -> ('a -> unit) -> unit
36 (** [iter2 a b f] applies [f] to [a] then [b]. *)
37
38 val iter3 : 'a -> 'a -> 'a -> ('a -> unit) -> unit
39 (** [iter3 a b c f] applies [f] to [a], [b], then [c]. *)
40
41 val xor : string -> string -> string
42 (** [xor a b] computes the bitwise XOR of [a] and [b]. *)
43
44 val unsafe_xor_into :
45 string -> src_off:int -> bytes -> dst_off:int -> int -> unit
46 (** [unsafe_xor_into src ~src_off dst ~dst_off len] XORs [len] bytes from
47 [src] at [src_off] into [dst] at [dst_off] without bounds checks. *)
48
49 val invalid_arg : ('a, Format.formatter, unit, unit, unit, 'b) format6 -> 'a
50 (** [invalid_arg fmt] raises [Invalid_argument] with a formatted message. *)
51end
52
53(**/**)
54
55(** The poly1305 message authentication code *)
56module Poly1305 : sig
57 type 'a iter = ('a -> unit) -> unit
58
59 type t
60 (** Represents a running mac computation, suitable for appending inputs. *)
61
62 val mac_size : int
63 (** [mac_size] is the size of the output. *)
64
65 val empty : key:string -> t
66 (** [empty] is the empty context with the given [key].
67
68 @raise Invalid_argument if key is not 32 bytes. *)
69
70 val feed : t -> string -> t
71 (** [feed t msg] adds the information in [msg] to [t]. *)
72
73 val feedi : t -> string iter -> t
74 (** [feedi t iter] feeds iter into [t]. *)
75
76 val get : t -> string
77 (** [get t] is the mac corresponding to [t]. *)
78
79 val mac : key:string -> string -> string
80 (** [mac ~key msg] is the all-in-one mac computation:
81 [get (feed (empty ~key) msg)]. *)
82
83 val maci : key:string -> string iter -> string
84 (** [maci ~key iter] is the all-in-one mac computation:
85 [get (feedi (empty ~key) iter)]. *)
86
87 val mac_into :
88 key:string -> (string * int * int) list -> bytes -> dst_off:int -> unit
89 (** [mac_into ~key datas dst dst_off] computes the [mac] of [datas]. *)
90
91 (**/**)
92
93 val unsafe_mac_into :
94 key:string -> (string * int * int) list -> bytes -> dst_off:int -> unit
95 (** [unsafe_mac_into ~key datas dst dst_off] is {!mac_into} without bounds
96 checks. *)
97
98 (**/**)
99end
100
101(** {1 Symmetric-key cryptography} *)
102
103(** Authenticated encryption with associated data.
104
105 This defines a uniform interface of symmetrics cryptographic algorithms
106 which encrypt, and also protect the integrity of the data. Additional data,
107 only used for integrity protection, not encrypted and not part of the
108 ciphertext, can be passed in optionally. This prevents the same ciphertext
109 being used at a different location. See
110 {{:https://tools.ietf.org/html/rfc5116}RFC 5116} for further description. *)
111module type AEAD = sig
112 val tag_size : int
113 (** The size of the authentication tag. *)
114
115 type key
116 (** The abstract type for the key. *)
117
118 val of_secret : string -> key
119 (** [of_secret secret] constructs the encryption key corresponding to
120 [secret].
121
122 @raise Invalid_argument if the length of [secret] is not a valid key size.
123 *)
124
125 (** {1 Authenticated encryption and decryption with inline tag} *)
126
127 val authenticate_encrypt :
128 key:key -> nonce:string -> ?adata:string -> string -> string
129 (** [authenticate_encrypt ~key ~nonce ~adata msg] encrypts [msg] with [key]
130 and [nonce], and appends an authentication tag computed over the encrypted
131 [msg], using [key], [nonce], and [adata].
132
133 @raise Invalid_argument if [nonce] is not of the right size. *)
134
135 val authenticate_decrypt :
136 key:key -> nonce:string -> ?adata:string -> string -> string option
137 (** [authenticate_decrypt ~key ~nonce ~adata msg] splits [msg] into encrypted
138 data and authentication tag, computes the authentication tag using [key],
139 [nonce], and [adata], and decrypts the encrypted data. If the
140 authentication tags match, the decrypted data is returned.
141
142 @raise Invalid_argument if [nonce] is not of the right size. *)
143
144 (** {1 Authenticated encryption and decryption with tag provided separately}
145 *)
146
147 val authenticate_encrypt_tag :
148 key:key -> nonce:string -> ?adata:string -> string -> string * string
149 (** [authenticate_encrypt_tag ~key ~nonce ~adata msg] encrypts [msg] with
150 [key] and [nonce]. The computed authentication tag is returned separately
151 as second part of the tuple.
152
153 @raise Invalid_argument if [nonce] is not of the right size. *)
154
155 val authenticate_decrypt_tag :
156 key:key ->
157 nonce:string ->
158 ?adata:string ->
159 tag:string ->
160 string ->
161 string option
162 (** [authenticate_decrypt ~key ~nonce ~adata ~tag msg] computes the
163 authentication tag using [key], [nonce], and [adata], and decrypts the
164 encrypted data. If the authentication tags match, the decrypted data is
165 returned.
166
167 @raise Invalid_argument if [nonce] is not of the right size. *)
168
169 (** {1 Authenticated encryption and decryption into existing buffers} *)
170
171 val authenticate_encrypt_into :
172 key:key ->
173 nonce:string ->
174 ?adata:string ->
175 string ->
176 src_off:int ->
177 bytes ->
178 dst_off:int ->
179 tag_off:int ->
180 int ->
181 unit
182 (** [authenticate_encrypt_into ~key ~nonce ~adata msg ~src_off dst ~dst_off
183 ~tag_off len] encrypts [len] bytes of [msg] starting at [src_off] with
184 [key] and [nonce]. The output is put into [dst] at [dst_off], the tag into
185 [dst] at [tag_off].
186
187 @raise Invalid_argument if [nonce] is not of the right size.
188 @raise Invalid_argument if [String.length msg - src_off < len].
189 @raise Invalid_argument if [Bytes.length dst - dst_off < len].
190 @raise Invalid_argument if [Bytes.length dst - tag_off < tag_size]. *)
191
192 val authenticate_decrypt_into :
193 key:key ->
194 nonce:string ->
195 ?adata:string ->
196 string ->
197 src_off:int ->
198 tag_off:int ->
199 bytes ->
200 dst_off:int ->
201 int ->
202 bool
203 (** [authenticate_decrypt_into ~key ~nonce ~adata msg ~src_off ~tag_off dst
204 ~dst_off len] computes the authentication tag using [key], [nonce], and
205 [adata], and decrypts the [len] bytes encrypted data from [msg] starting
206 at [src_off] into [dst] starting at [dst_off]. If the authentication tags
207 match, [true] is returned, and the decrypted data is in [dst].
208
209 @raise Invalid_argument if [nonce] is not of the right size.
210 @raise Invalid_argument if [String.length msg - src_off < len].
211 @raise Invalid_argument if [Bytes.length dst - dst_off < len].
212 @raise Invalid_argument if [String.length msg - tag_off < tag_size]. *)
213
214 (**/**)
215
216 val unsafe_authenticate_encrypt_into :
217 key:key ->
218 nonce:string ->
219 ?adata:string ->
220 string ->
221 src_off:int ->
222 bytes ->
223 dst_off:int ->
224 tag_off:int ->
225 int ->
226 unit
227 (** [unsafe_authenticate_encrypt_into] is {!authenticate_encrypt_into}, but
228 without bounds checks.
229
230 @raise Invalid_argument if [nonce] is not of the right size.
231
232 This may cause memory issues if an invariant is violated:
233 - [String.length msg - src_off >= len].
234 - [Bytes.length dst - dst_off >= len].
235 - [Bytes.length dst - tag_off >= tag_size]. *)
236
237 val unsafe_authenticate_decrypt_into :
238 key:key ->
239 nonce:string ->
240 ?adata:string ->
241 string ->
242 src_off:int ->
243 tag_off:int ->
244 bytes ->
245 dst_off:int ->
246 int ->
247 bool
248 (** [unsafe_authenticate_decrypt_into] is {!authenticate_decrypt_into}, but
249 without bounds checks.
250
251 @raise Invalid_argument if [nonce] is not of the right size.
252
253 This may cause memory issues if an invariant is violated:
254 - [String.length msg - src_off >= len].
255 - [Bytes.length dst - dst_off >= len].
256 - [String.length msg - tag_off >= tag_size]. *)
257
258 (**/**)
259end
260
261(** Block ciphers.
262
263 Each algorithm, and each mode of operation, is contained in its own separate
264 module. *)
265
266(** Module types for various block cipher modes of operation. *)
267module Block : sig
268 (** Modes of operation: *)
269
270 (** {e Electronic Codebook} "mode". *)
271 module type ECB = sig
272 type key
273
274 val of_secret : string -> key
275 (** Construct the encryption key corresponding to [secret].
276
277 @raise Invalid_argument
278 if the length of [secret] is not in {{!key_sizes}[key_sizes]}. *)
279
280 val key_sizes : int array
281 (** Key sizes allowed with this cipher. *)
282
283 val block_size : int
284 (** The size of a single block. *)
285
286 val encrypt : key:key -> string -> string
287 (** [encrypt ~key src] encrypts [src] into a freshly allocated buffer of the
288 same size using [key].
289
290 @raise Invalid_argument
291 if the length of [src] is not a multiple of {!block_size}. *)
292
293 val decrypt : key:key -> string -> string
294 (** [decrypt ~key src] decrypts [src] into a freshly allocated buffer of the
295 same size using [key].
296
297 @raise Invalid_argument
298 if the length of [src] is not a multiple of {!block_size}. *)
299
300 val encrypt_into :
301 key:key -> string -> src_off:int -> bytes -> dst_off:int -> int -> unit
302 (** [encrypt_into ~key src ~src_off dst dst_off len] encrypts [len] octets
303 from [src] starting at [src_off] into [dst] starting at [dst_off].
304
305 @raise Invalid_argument if [len] is not a multiple of {!block_size}.
306 @raise Invalid_argument
307 if [src_off < 0 || String.length src - src_off < len].
308 @raise Invalid_argument
309 if [dst_off < 0 || Bytes.length dst - dst_off < len]. *)
310
311 val decrypt_into :
312 key:key -> string -> src_off:int -> bytes -> dst_off:int -> int -> unit
313 (** [decrypt_into ~key src ~src_off dst dst_off len] decrypts [len] octets
314 from [src] starting at [src_off] into [dst] starting at [dst_off].
315
316 @raise Invalid_argument if [len] is not a multiple of {!block_size}.
317 @raise Invalid_argument
318 if [src_off < 0 || String.length src - src_off < len].
319 @raise Invalid_argument
320 if [dst_off < 0 || Bytes.length dst - dst_off < len]. *)
321
322 (**/**)
323
324 val unsafe_encrypt_into :
325 key:key -> string -> src_off:int -> bytes -> dst_off:int -> int -> unit
326 (** [unsafe_encrypt_into] is {!encrypt_into}, but without bounds checks.
327
328 This may cause memory issues if an invariant is violated:
329 - [len] must be a multiple of {!block_size},
330 - [src_off >= 0 && String.length src - src_off >= len],
331 - [dst_off >= 0 && Bytes.length dst - dst_off >= len]. *)
332
333 val unsafe_decrypt_into :
334 key:key -> string -> src_off:int -> bytes -> dst_off:int -> int -> unit
335 (** [unsafe_decrypt_into] is {!decrypt_into}, but without bounds checks.
336
337 This may cause memory issues if an invariant is violated:
338 - [len] must be a multiple of {!block_size},
339 - [src_off >= 0 && String.length src - src_off >= len],
340 - [dst_off >= 0 && Bytes.length dst - dst_off >= len]. *)
341
342 (**/**)
343 end
344
345 (** {e Cipher-block chaining} mode. *)
346 module type CBC = sig
347 type key
348
349 val of_secret : string -> key
350 (** Construct the encryption key corresponding to [secret].
351
352 @raise Invalid_argument
353 if the length of [secret] is not in {{!key_sizes}[key_sizes]}. *)
354
355 val key_sizes : int array
356 (** Key sizes allowed with this cipher. *)
357
358 val block_size : int
359 (** The size of a single block. *)
360
361 val encrypt : key:key -> iv:string -> string -> string
362 (** [encrypt ~key ~iv msg] is [msg] encrypted under [key], using [iv] as the
363 CBC initialization vector.
364
365 @raise Invalid_argument
366 if [iv] is not [block_size], or [msg] is not [k * block_size] long. *)
367
368 val decrypt : key:key -> iv:string -> string -> string
369 (** [decrypt ~key ~iv msg] is the inverse of [encrypt].
370
371 @raise Invalid_argument
372 if [iv] is not [block_size], or [msg] is not [k * block_size] long. *)
373
374 val next_iv : ?off:int -> string -> iv:string -> string
375 (** [next_iv ~iv ciphertext ~off] is the first [iv] {e following} the
376 encryption that used [iv] to produce [ciphertext].
377
378 For protocols which perform inter-message chaining, this is the [iv] for
379 the next message.
380
381 It is either [iv], when [String.length ciphertext - off = 0], or the
382 last block of [ciphertext]. Note that
383
384 {[
385 encrypt ~iv msg1
386 || encrypt ~iv:(next_iv ~iv (encrypt ~iv msg1)) msg2
387 == encrypt ~iv (msg1 || msg2)
388 ]}
389
390 @raise Invalid_argument if the length of [iv] is not [block_size].
391 @raise Invalid_argument
392 if the length of [ciphertext] is not a multiple of [block_size]. *)
393
394 val encrypt_into :
395 key:key ->
396 iv:string ->
397 string ->
398 src_off:int ->
399 bytes ->
400 dst_off:int ->
401 int ->
402 unit
403 (** [encrypt_into ~key ~iv src ~src_off dst dst_off len] encrypts [len]
404 octets from [src] starting at [src_off] into [dst] starting at
405 [dst_off].
406
407 @raise Invalid_argument if the length of [iv] is not {!block_size}.
408 @raise Invalid_argument if [len] is not a multiple of {!block_size}.
409 @raise Invalid_argument
410 if [src_off < 0 || String.length src - src_off < len].
411 @raise Invalid_argument
412 if [dst_off < 0 || Bytes.length dst - dst_off < len]. *)
413
414 val decrypt_into :
415 key:key ->
416 iv:string ->
417 string ->
418 src_off:int ->
419 bytes ->
420 dst_off:int ->
421 int ->
422 unit
423 (** [decrypt_into ~key ~iv src ~src_off dst dst_off len] decrypts [len]
424 octets from [src] starting at [src_off] into [dst] starting at
425 [dst_off].
426
427 @raise Invalid_argument if the length of [iv] is not {!block_size}.
428 @raise Invalid_argument if [len] is not a multiple of {!block_size}.
429 @raise Invalid_argument
430 if [src_off < 0 || String.length src - src_off < len].
431 @raise Invalid_argument
432 if [dst_off < 0 || Bytes.length dst - dst_off < len]. *)
433
434 (**/**)
435
436 val unsafe_encrypt_into :
437 key:key ->
438 iv:string ->
439 string ->
440 src_off:int ->
441 bytes ->
442 dst_off:int ->
443 int ->
444 unit
445 (** [unsafe_encrypt_into] is {!encrypt_into}, but without bounds checks.
446
447 This may casue memory issues if an invariant is violated:
448 - the length of [iv] must be {!block_size},
449 - [len] must be a multiple of {!block_size},
450 - [src_off >= 0 && String.length src - src_off >= len],
451 - [dst_off >= 0 && Bytes.length dst - dst_off >= len]. *)
452
453 val unsafe_decrypt_into :
454 key:key ->
455 iv:string ->
456 string ->
457 src_off:int ->
458 bytes ->
459 dst_off:int ->
460 int ->
461 unit
462 (** [unsafe_decrypt_into] is {!decrypt_into}, but without bounds checks.
463
464 This may casue memory issues if an invariant is violated:
465 - the length of [iv] must be {!block_size},
466 - [len] must be a multiple of {!block_size},
467 - [src_off >= 0 && String.length src - src_off >= len],
468 - [dst_off >= 0 && Bytes.length dst - dst_off >= len]. *)
469
470 val unsafe_encrypt_into_inplace :
471 key:key -> iv:string -> bytes -> dst_off:int -> int -> unit
472 (** [unsafe_encrypt_into_inplace] is {!unsafe_encrypt_into}, but assumes
473 that [dst] already contains the mesage to be encrypted.
474
475 This may casue memory issues if an invariant is violated:
476 - the length of [iv] must be {!block_size},
477 - [len] must be a multiple of {!block_size},
478 - [src_off >= 0 && String.length src - src_off >= len],
479 - [dst_off >= 0 && Bytes.length dst - dst_off >= len]. *)
480
481 (**/**)
482 end
483
484 (** {e Counter} mode. *)
485 module type CTR = sig
486 type key
487
488 val of_secret : string -> key
489 (** Construct the encryption key corresponding to [secret].
490
491 @raise Invalid_argument
492 if the length of [secret] is not in {{!key_sizes}[key_sizes]}. *)
493
494 val key_sizes : int array
495 (** Key sizes allowed with this cipher. *)
496
497 val block_size : int
498 (** The size of a single block. *)
499
500 type ctr
501
502 val add_ctr : ctr -> int64 -> ctr
503 (** [add_ctr ctr n] adds [n] to [ctr]. *)
504
505 val next_ctr : ?off:int -> string -> ctr:ctr -> ctr
506 (** [next_ctr ~off msg ~ctr] is the state of the counter after encrypting or
507 decrypting [msg] at offset [off] with the counter [ctr].
508
509 For protocols which perform inter-message chaining, this is the counter
510 for the next message.
511
512 It is computed as [C.add ctr (ceil (len msg / block_size))]. Note that
513 if [len msg1 = k * block_size],
514
515 {[
516 encrypt ~ctr msg1
517 || encrypt ~ctr:(next_ctr ~ctr msg1) msg2
518 == encrypt ~ctr (msg1 || msg2)
519 ]} *)
520
521 val ctr_of_octets : string -> ctr
522 (** [ctr_of_octets buf] converts the value of [buf] into a counter. *)
523
524 val stream : key:key -> ctr:ctr -> int -> string
525 (** [stream ~key ~ctr n] is the raw keystream.
526
527 Keystream is the concatenation of successive encrypted counter states.
528 If [E(x)] is the single block [x] encrypted under [key], then keystream
529 is the first [n] bytes of
530 [E(ctr) || E(add ctr 1) || E(add ctr 2) || ...].
531
532 Note that
533
534 {[
535 stream ~key ~ctr (k * block_size)
536 || stream ~key ~ctr:(add ctr k) x
537 == stream ~key ~ctr ((k * block_size) + x)
538 ]}
539
540 In other words, it is possible to restart a keystream at [block_size]
541 boundaries by manipulating the counter. *)
542
543 val encrypt : key:key -> ctr:ctr -> string -> string
544 (** [encrypt ~key ~ctr msg] is [stream ~key ~ctr (len msg) lxor msg]. *)
545
546 val decrypt : key:key -> ctr:ctr -> string -> string
547 (** [decrypt] is [encrypt]. *)
548
549 val stream_into : key:key -> ctr:ctr -> bytes -> off:int -> int -> unit
550 (** [stream_into ~key ~ctr dst ~off len] is the raw key stream put into
551 [dst] starting at [off].
552
553 @raise Invalid_argument if [Bytes.length dst - off < len]. *)
554
555 val encrypt_into :
556 key:key ->
557 ctr:ctr ->
558 string ->
559 src_off:int ->
560 bytes ->
561 dst_off:int ->
562 int ->
563 unit
564 (** [encrypt_into ~key ~ctr src ~src_off dst ~dst_off len] produces the key
565 stream into [dst] at [dst_off], and then xors it with [src] at
566 [src_off].
567
568 @raise Invalid_argument
569 if [dst_off < 0 || Bytes.length dst - dst_off < len].
570 @raise Invalid_argument
571 if [src_off < 0 || String.length src - src_off < len]. *)
572
573 val decrypt_into :
574 key:key ->
575 ctr:ctr ->
576 string ->
577 src_off:int ->
578 bytes ->
579 dst_off:int ->
580 int ->
581 unit
582 (** [decrypt_into] is {!encrypt_into}. *)
583
584 (**/**)
585
586 val unsafe_stream_into :
587 key:key -> ctr:ctr -> bytes -> off:int -> int -> unit
588 (** [unsafe_stream_into] is {!stream_into}, but without bounds checks.
589
590 This may cause memory issues if the invariant is violated:
591 - [off >= 0 && Bytes.length buf - off >= len]. *)
592
593 val unsafe_encrypt_into :
594 key:key ->
595 ctr:ctr ->
596 string ->
597 src_off:int ->
598 bytes ->
599 dst_off:int ->
600 int ->
601 unit
602 (** [unsafe_encrypt_into] is {!encrypt_into}, but without bounds checks.
603
604 This may cause memory issues if an invariant is violated:
605 - [dst_off >= 0 && Bytes.length dst - dst_off >= len],
606 - [src_off >= 0 && String.length src - src_off >= len]. *)
607
608 val unsafe_decrypt_into :
609 key:key ->
610 ctr:ctr ->
611 string ->
612 src_off:int ->
613 bytes ->
614 dst_off:int ->
615 int ->
616 unit
617 (** [unsafe_decrypt_into] is {!unsafe_encrypt_into}. *)
618
619 (**/**)
620 end
621
622 (** {e Galois/Counter Mode}. *)
623 module type GCM = sig
624 include AEAD
625
626 val key_sizes : int array
627 (** Key sizes allowed with this cipher. *)
628
629 val block_size : int
630 (** The size of a single block. *)
631 end
632
633 (** {e Counter with CBC-MAC} mode. *)
634 module type CCM16 = sig
635 include AEAD
636
637 val key_sizes : int array
638 (** Key sizes allowed with this cipher. *)
639
640 val block_size : int
641 (** The size of a single block. *)
642 end
643end
644
645module AES : sig
646 module ECB : Block.ECB
647 module CBC : Block.CBC
648 module CTR : Block.CTR with type ctr = int64 * int64
649 module GCM : Block.GCM
650 module CCM16 : Block.CCM16
651end
652
653module DES : sig
654 module ECB : Block.ECB
655 module CBC : Block.CBC
656 module CTR : Block.CTR with type ctr = int64
657end
658
659val accelerated : [ `XOR | `AES | `GHASH ] list
660(** Operations using non-portable, hardware-dependent implementation in this
661 build of the library. *)
662
663(** The ChaCha20 cipher proposed by D.J. Bernstein. *)
664module Chacha20 : sig
665 include AEAD
666
667 val crypt : key:key -> nonce:string -> ?ctr:int64 -> string -> string
668 (** [crypt ~key ~nonce ~ctr data] generates a ChaCha20 key stream using the
669 [key], and [nonce]. The [ctr] defaults to 0. The generated key stream is
670 of the same length as [data], and the output is the XOR of the key stream
671 and [data]. This implements, depending on the size of the [nonce] (8 or 12
672 bytes) both the original specification (where the counter is 8 byte, same
673 as the nonce) and the IETF RFC 8439 specification (where nonce is 12
674 bytes, and counter 4 bytes).
675
676 @raise Invalid_argument
677 if invalid parameters are provided. Valid parameters are: [key] must be
678 32 bytes and [nonce] 12 bytes for the IETF mode (and counter fit into 32
679 bits), or [key] must be either 16 bytes or 32 bytes and [nonce] 8 bytes.
680 *)
681end
682
683(** General stream cipher type. *)
684module type Stream = sig
685 type key
686 type result = { message : string; key : key }
687
688 val of_secret : string -> key
689 (** [of_secret s] creates a key from the secret string [s]. *)
690
691 val encrypt : key:key -> string -> result
692 (** [encrypt ~key msg] encrypts [msg] with [key]. *)
693
694 val decrypt : key:key -> string -> result
695 (** [decrypt ~key msg] decrypts [msg] with [key]. *)
696end
697
698module ARC4 : Stream
699(** {e Alleged Rivest Cipher 4}. *)