Skip to main content

generic_ecies/
lib.rs

1//! ECIES is a scheme for efficient ciphers with asymmetric key using elliptic
2//! curves and symmetric ciphers. This implementation is generic in its
3//! components, thanks to using [`generic_ec`] and `RustCrypto` traits. You can
4//! use the ciphersuites defined by us in advance, like
5//! [`curve25519xsalsa20hmac`] and [`curve25519aes128_cbchmac`], or you can
6//! define your own [`Suite`].
7//!
8//! This implementation is based on [SECG
9//! SEC-1](http://www.secg.org/sec1-v2.pdf)
10//!
11//! You can find examples of usage in the predefined ciphersuites:
12//! [`curve25519xsalsa20hmac`] and [`curve25519aes128_cbchmac`]
13
14#![forbid(clippy::disallowed_methods, missing_docs, unsafe_code)]
15#![cfg_attr(not(test), forbid(unused_crate_dependencies))]
16
17#[macro_use]
18mod common;
19
20#[cfg(feature = "curve25519aes128-cbchmac")]
21pub mod curve25519aes128_cbchmac;
22#[cfg(feature = "curve25519xsalsa20hmac")]
23pub mod curve25519xsalsa20hmac;
24
25use cipher::generic_array::GenericArray;
26use digest::Mac as _;
27use generic_ec::Curve;
28use rand_core::{CryptoRng, RngCore};
29
30/// A suite of cryptographic protocols to use for ECIES
31///
32/// Thanks for UC-security, any secure protocols can work together.
33///
34/// This crate has several suites ready-made, such as
35/// [`curve25519xsalsa20hmac`] and [`curve25519aes128_cbchmac`].
36pub trait Suite {
37    /// Elliptic curve provided by [`generic_ec`], for use in ECDH
38    type E: Curve;
39    /// MAC provided by [`digest`]
40    type Mac: digest::OutputSizeUser;
41    /// Encryption provided by [`cipher`], for use for symmetric encryption
42    type Enc;
43    /// Decryption corresponding to `Enc`. For stream cipher will usually be
44    /// the same as `Enc`
45    type Dec;
46}
47
48pub(crate) type MacSize<S> = <<S as Suite>::Mac as digest::OutputSizeUser>::OutputSize;
49
50/// Amount of bytes padding of this message will take. When using
51/// [`PublicKey::block_encrypt_in_place`], you will find this function useful to
52/// find out how many bytes to append to the buffer so that the padding will fit
53pub const fn pad_size<S: Suite>(message_len: usize) -> usize
54where
55    S::Enc: cipher::BlockSizeUser,
56{
57    let block_size = <<S::Enc as cipher::BlockSizeUser>::BlockSize as cipher::Unsigned>::USIZE;
58    block_size - (message_len % block_size)
59}
60
61/// Private key is a scalar of the elliptic curve in the chosen suite.
62///
63/// You can obtain a private key by generating it with [`PrivateKey::generate`],
64/// or by reading it from bytes with [`PrivateKey::from_bytes`].
65///
66/// The scalars are stored as bytes in big-endian format, which might not always
67/// be compatible with other software working with this elliptic curve. For
68/// example, for EdDSA compatability we provide a method
69/// [`PrivateKey::from_eddsa_pkey_bytes`]
70#[derive(Clone, Debug)]
71pub struct PrivateKey<S: Suite> {
72    /// `d` in the standard
73    pub scalar: generic_ec::NonZero<generic_ec::SecretScalar<S::E>>,
74}
75
76/// Public key is a point on the elliptic curve of the chosen suite.
77///
78/// You can obtain a public key from a newly generated private key by
79/// [`PrivateKey::public_key`], or by reading it from bytes with
80/// [`PublicKey::from_bytes`]
81#[derive(Clone, Debug, PartialEq, Eq)]
82pub struct PublicKey<S: Suite> {
83    /// `Q` in the standard
84    pub point: generic_ec::NonZero<generic_ec::Point<S::E>>,
85}
86
87/// Represents a parsed message. To convert to and from platform independent
88/// wire bytes use [`EncryptedMessage::from_bytes`] and
89/// [`EncryptedMessage::to_bytes`]
90///
91/// The borrows the bytes to be encrypted instead of owning them, which allows
92/// for efficient in-place encryption and decryption.
93#[derive(Debug, PartialEq)]
94pub struct EncryptedMessage<'m, S: Suite> {
95    /// Ephemeral key in DH in the protocol
96    pub ephemeral_key: generic_ec::NonZero<generic_ec::Point<S::E>>,
97    /// Encrypted bytes of the message, stored elsewhere
98    pub message: &'m mut [u8],
99    /// MAC tag of encrypted bytes
100    pub tag: GenericArray<u8, MacSize<S>>,
101}
102
103impl<S: Suite> PrivateKey<S> {
104    /// Generate random key using the provided [`CryptoRng`]
105    pub fn generate(rng: &mut (impl RngCore + CryptoRng)) -> Self {
106        let scalar = generic_ec::NonZero::<generic_ec::SecretScalar<S::E>>::random(rng);
107        Self { scalar }
108    }
109    /// Read the bytes as a big-endian number. This might not necessarily be
110    /// compatible with other software for working with elliptic curves.
111    pub fn from_bytes(bytes: impl AsRef<[u8]>) -> Option<Self> {
112        let scalar = generic_ec::SecretScalar::from_be_bytes(bytes.as_ref()).ok()?;
113        let scalar = generic_ec::NonZero::try_from(scalar).ok()?;
114        Some(Self { scalar })
115    }
116    /// Stores the scalar as a big-endian number. This might not necessarily be
117    /// compatible with other software for working with elliptic curves.
118    pub fn to_bytes(&self) -> Vec<u8> {
119        let scalar: &generic_ec::Scalar<S::E> = self.scalar.as_ref();
120        scalar.to_be_bytes().to_vec()
121    }
122
123    /// Compute the associated public key `Q = g * d`
124    pub fn public_key(&self) -> PublicKey<S> {
125        let point = generic_ec::Point::generator() * &self.scalar;
126        PublicKey { point }
127    }
128}
129
130impl<S: Suite> PublicKey<S> {
131    /// Read the encoded scalar. Should be compatible with most other software
132    /// for working with elliptic curves.
133    pub fn from_bytes(bytes: impl AsRef<[u8]>) -> Option<Self> {
134        let point = generic_ec::Point::<S::E>::from_bytes(bytes).ok()?;
135        let point = generic_ec::NonZero::<generic_ec::Point<S::E>>::try_from(point).ok()?;
136        Some(Self { point })
137    }
138    /// Write the encoded scalar. Should be compatible with most other software
139    /// for working with elliptic curves.
140    pub fn to_bytes(&self) -> Vec<u8> {
141        self.point.to_bytes(true).to_vec()
142    }
143
144    /// Encrypt the message bytes in place. Variant for suites with stream
145    /// ciphers.
146    ///
147    /// You can interact with the encrypted bytes through the returned
148    /// [`EncryptedMessage`], but be careful that changing them will invalidate
149    /// the mac.
150    pub fn stream_encrypt_in_place<'m>(
151        &self,
152        message: &'m mut [u8],
153        rng: &mut (impl RngCore + CryptoRng),
154    ) -> Result<EncryptedMessage<'m, S>, EncError>
155    where
156        S::Mac: digest::Mac + cipher::KeyInit,
157        S::Enc: cipher::KeyIvInit + cipher::StreamCipher,
158    {
159        stream_encrypt_in_place::<S, _>(message, &self.point, rng)
160    }
161
162    /// Encrypt the message bytes in place. Variant for suites with block
163    /// ciphers. Uses PKCS7 padding.
164    ///
165    /// - `message` - the buffer containing the message to encrypt, plus enough
166    ///   space for padding
167    /// - `data_len` - length of the message in the buffer
168    ///
169    /// Given a message `m`, the size of the buffer should be at least `m.len() +
170    /// pad_size(m.len())`. If the buffer size is too small, the function will
171    /// return [`EncError::PadError`]
172    ///
173    /// You can interact with the encrypted bytes through the returned
174    /// [`EncryptedMessage`], but be careful that changing them will invalidate
175    /// the mac.
176    pub fn block_encrypt_in_place<'m>(
177        &self,
178        message: &'m mut [u8],
179        data_len: usize,
180        rng: &mut (impl RngCore + CryptoRng),
181    ) -> Result<EncryptedMessage<'m, S>, EncError>
182    where
183        S::Mac: digest::Mac + cipher::KeyInit,
184        S::Enc: cipher::KeyIvInit + cipher::BlockEncryptMut,
185    {
186        block_encrypt_in_place::<S, _>(message, data_len, &self.point, rng)
187    }
188
189    /// Encrypt the message bytes into a new buffer. Variant for suites with
190    /// stream ciphers.
191    ///
192    /// Returnes the encoded bytes of [`EncryptedMessage`]
193    pub fn stream_encrypt(
194        &self,
195        message: &[u8],
196        rng: &mut (impl RngCore + CryptoRng),
197    ) -> Result<Vec<u8>, EncError>
198    where
199        S::Mac: digest::Mac + cipher::KeyInit,
200        S::Enc: cipher::KeyIvInit + cipher::StreamCipher,
201    {
202        with_copy(message, |msg| self.stream_encrypt_in_place(msg, rng))
203    }
204
205    /// Encrypt the message bytes into a new buffer. Variant for suites with
206    /// block ciphers. Uses PKCS7 padding.
207    ///
208    /// Returnes the encoded bytes of [`EncryptedMessage`]
209    pub fn block_encrypt(
210        &self,
211        message: &[u8],
212        rng: &mut (impl RngCore + CryptoRng),
213    ) -> Result<Vec<u8>, EncError>
214    where
215        S::Mac: digest::Mac + cipher::KeyInit,
216        S::Enc: cipher::KeyIvInit + cipher::BlockEncryptMut,
217    {
218        let key_len = generic_ec::Point::<S::E>::serialized_len(true);
219        let mac_len = <MacSize<S> as cipher::typenum::Unsigned>::USIZE;
220        let msg_len = message.len();
221        let pad_len = pad_size::<S>(msg_len);
222
223        let mut bytes = vec![0; key_len + msg_len + pad_len + mac_len];
224        bytes[key_len..(key_len + msg_len)].copy_from_slice(message);
225        // contains space for padding
226        let message_slice = &mut bytes[key_len..(key_len + msg_len + pad_len)];
227
228        let EncryptedMessage {
229            ephemeral_key, tag, ..
230        } = self.block_encrypt_in_place(message_slice, msg_len, rng)?;
231
232        bytes[..key_len].copy_from_slice(&ephemeral_key.to_bytes(true));
233        bytes[(key_len + msg_len + pad_len)..].copy_from_slice(&tag);
234        Ok(bytes)
235    }
236}
237
238impl<S: Suite> PrivateKey<S> {
239    /// Decrypt the message bytes in place. Variant for suites with stream
240    /// ciphers.
241    ///
242    /// When you have a buffer of bytes to decrypt, you first need to parse it
243    /// with `EncryptedMessage::from_bytes`, and then decrypt the structure
244    /// using this funciton. It will modify the bytes in the buffer and return a
245    /// slice to them.
246    pub fn stream_decrypt_in_place<'m>(
247        &self,
248        message: EncryptedMessage<'m, S>,
249    ) -> Result<&'m mut [u8], DecError>
250    where
251        S::Mac: digest::Mac + cipher::KeyInit,
252        S::Dec: cipher::KeyIvInit + cipher::StreamCipher,
253    {
254        stream_decrypt_in_place(message, &self.scalar)
255    }
256
257    /// Decrypt the message bytes into a new buffer. Variant for suites with
258    /// stream ciphers.
259    ///
260    /// When you have a buffer of bytes to decrypt, you first need to parse it
261    /// with `EncryptedMessage::from_bytes`, and then decrypt the structure
262    /// using this funciton. It will copy the message bytes into a new buffer
263    /// and return a [`Vec`] containing them.
264    pub fn stream_decrypt(&self, message: &EncryptedMessage<'_, S>) -> Result<Vec<u8>, DecError>
265    where
266        S::Mac: digest::Mac + cipher::KeyInit,
267        S::Dec: cipher::KeyIvInit + cipher::StreamCipher,
268    {
269        let mut msg_bytes = Vec::with_capacity(message.message.len());
270        msg_bytes.extend_from_slice(message.message);
271        let msg = EncryptedMessage {
272            ephemeral_key: message.ephemeral_key,
273            tag: message.tag.clone(),
274            message: &mut msg_bytes,
275        };
276        let _ = self.stream_decrypt_in_place(msg)?;
277        Ok(msg_bytes)
278    }
279
280    /// Decrypt the message bytes in place. Variant for suites with block
281    /// ciphers. Uses PKCS7 padding.
282    ///
283    /// When you have a buffer of bytes to decrypt, you first need to parse it
284    /// with `EncryptedMessage::from_bytes`, and then decrypt the structure
285    /// using this funciton. It will modify the bytes in the buffer and return a
286    /// slice to them.
287    pub fn block_decrypt_in_place<'m>(
288        &self,
289        message: EncryptedMessage<'m, S>,
290    ) -> Result<&'m mut [u8], DecError>
291    where
292        S::Mac: digest::Mac + cipher::KeyInit,
293        S::Dec: cipher::KeyIvInit + cipher::BlockDecryptMut,
294    {
295        block_decrypt_in_place(message, &self.scalar)
296    }
297
298    /// Decrypt the message bytes into a new buffer. Variant for suites with
299    /// block ciphers. Uses PKCS7 padding.
300    ///
301    /// When you have a buffer of bytes to decrypt, you first need to parse it
302    /// with `EncryptedMessage::from_bytes`, and then decrypt the structure
303    /// using this funciton. It will copy the message bytes into a new buffer
304    /// and return a [`Vec`] containing them.
305    pub fn block_decrypt(&self, message: &EncryptedMessage<'_, S>) -> Result<Vec<u8>, DecError>
306    where
307        S::Mac: digest::Mac + cipher::KeyInit,
308        S::Dec: cipher::KeyIvInit + cipher::BlockDecryptMut,
309    {
310        let mut msg_bytes = Vec::with_capacity(message.message.len());
311        msg_bytes.extend_from_slice(message.message);
312        let msg = EncryptedMessage {
313            ephemeral_key: message.ephemeral_key,
314            tag: message.tag.clone(),
315            message: &mut msg_bytes,
316        };
317        let s = self.block_decrypt_in_place(msg)?;
318        let len_without_pad = s.len();
319        msg_bytes.truncate(len_without_pad);
320        Ok(msg_bytes)
321    }
322}
323
324fn ecies_kem<E: Curve>(
325    q: generic_ec::NonZero<generic_ec::Point<E>>,
326    k: &generic_ec::NonZero<generic_ec::SecretScalar<E>>,
327    cipher_key: &mut [u8],
328    mac_key: &mut [u8],
329) -> Result<(), hkdf::InvalidLength> {
330    // Step 3 in encryption, step 4 in decruption: Use ECDH without small
331    // cofactor, as in generic-ec all scalars are guaranteed to be in the prime
332    // order subgroup
333    let z: generic_ec::NonZero<_> = (k * q).into_secret();
334    // No need to check the point for zero, it's guaranteed by construction
335
336    // 4 in enc, 5 in dec: convert z to octet string
337    let z_bs = z.to_bytes(true);
338
339    // 5-6 in enc, 6-7 in dec: use KDF to produce keys for encryption and mac
340    let kdf = hkdf::Hkdf::<sha2::Sha256>::new(None, z_bs.as_nonsecret_bytes());
341    let mut all_bytes = vec![0u8; cipher_key.len() + mac_key.len()];
342
343    kdf.expand(b"generic-ecies cipher and mac", &mut all_bytes)?;
344    let mid = cipher_key.len();
345    cipher_key.copy_from_slice(&all_bytes[..mid]);
346    mac_key.copy_from_slice(&all_bytes[mid..]);
347    Ok(())
348}
349
350fn stream_encrypt_in_place<'m, S, R>(
351    m: &'m mut [u8],
352    q: &generic_ec::NonZero<generic_ec::Point<S::E>>,
353    rng: &mut R,
354) -> Result<EncryptedMessage<'m, S>, EncError>
355where
356    R: RngCore + CryptoRng,
357    S: Suite,
358    S::Mac: digest::Mac + cipher::KeyInit,
359    S::Enc: cipher::KeyIvInit + cipher::StreamCipher,
360{
361    // 1. Select ephemeral key pair
362    let k = generic_ec::NonZero::<generic_ec::SecretScalar<S::E>>::random(rng);
363    let r = generic_ec::Point::generator() * &k;
364
365    // 2: Use compression unconditionally
366
367    // Steps 3-6 encapsulated in KEM
368    let mut cipher_key = cipher::Key::<S::Enc>::default();
369    let mut mac_key = cipher::Key::<S::Mac>::default();
370    ecies_kem(*q, &k, &mut cipher_key, &mut mac_key).map_err(EncError::Kdf)?;
371
372    // Use zero IV since the key never repeats
373    let cipher_iv = cipher::Iv::<S::Enc>::default();
374    let mut cipher: S::Enc = cipher::KeyIvInit::new(&cipher_key, &cipher_iv);
375    let mac: S::Mac = digest::Mac::new(&mac_key);
376
377    // 7. Encrypt message
378    cipher::StreamCipher::try_apply_keystream(&mut cipher, m).map_err(EncError::StreamEnd)?;
379
380    // 8. MAC-tag the message
381    let d = mac.chain_update(&*m).finalize().into_bytes();
382
383    // 9. Output as structured message. Byte conversion is done separately
384    Ok(EncryptedMessage {
385        ephemeral_key: r,
386        message: m,
387        tag: d,
388    })
389}
390
391fn block_encrypt_in_place<'m, S: Suite, R>(
392    m: &'m mut [u8],
393    data_len: usize,
394    q: &generic_ec::NonZero<generic_ec::Point<S::E>>,
395    rng: &mut R,
396) -> Result<EncryptedMessage<'m, S>, EncError>
397where
398    R: RngCore + CryptoRng,
399    S::Mac: digest::Mac + cipher::KeyInit,
400    S::Enc: cipher::KeyIvInit + cipher::BlockEncryptMut,
401{
402    // 1. Select ephemeral key pair
403    let k = generic_ec::NonZero::<generic_ec::SecretScalar<S::E>>::random(rng);
404    let r = generic_ec::Point::generator() * &k;
405
406    // 2: Use compression unconditionally
407
408    // Steps 3-6 encapsulated in KEM
409    let mut cipher_key = cipher::Key::<S::Enc>::default();
410    let mut mac_key = cipher::Key::<S::Mac>::default();
411    ecies_kem(*q, &k, &mut cipher_key, &mut mac_key).map_err(EncError::Kdf)?;
412
413    // Use zero IV since the key never repeats
414    let cipher_iv = cipher::Iv::<S::Enc>::default();
415    let cipher: S::Enc = cipher::KeyIvInit::new(&cipher_key, &cipher_iv);
416    let mac: S::Mac = digest::Mac::new(&mac_key);
417
418    // 7. Encrypt message
419    cipher::BlockEncryptMut::encrypt_padded_mut::<cipher::block_padding::Pkcs7>(
420        cipher, m, data_len,
421    )
422    .map_err(EncError::PadError)?;
423
424    // 8. MAC-tag the message
425    let d = mac.chain_update(&*m).finalize().into_bytes();
426
427    // 9. Output as structured message. Byte conversion is done separately
428    Ok(EncryptedMessage {
429        ephemeral_key: r,
430        message: m,
431        tag: d,
432    })
433}
434
435fn stream_decrypt_in_place<'m, S: Suite>(
436    message: EncryptedMessage<'m, S>,
437    d: &generic_ec::NonZero<generic_ec::SecretScalar<S::E>>,
438) -> Result<&'m mut [u8], DecError>
439where
440    S::Mac: digest::Mac + cipher::KeyInit,
441    S::Dec: cipher::KeyIvInit + cipher::StreamCipher,
442{
443    // Byte conversion of step 1 and 2 is done separately
444
445    let r = message.ephemeral_key;
446    let m = message.message;
447    let tag = message.tag;
448
449    // 3. Verify the validity of the ephemeral key - unnecessary as all
450    // verification steps outlined in 3.2.2.1 of SECG SEC-1 (including non-zero
451    // point) are encoded in types and thus are achieved by construction
452
453    // Steps 4-7 encapsulated in KEM
454    let mut cipher_key = cipher::Key::<S::Dec>::default();
455    let mut mac_key = cipher::Key::<S::Mac>::default();
456    ecies_kem(r, d, &mut cipher_key, &mut mac_key).map_err(DecError::Kdf)?;
457
458    // Use zero IV since the key never repeats
459    let cipher_iv = cipher::Iv::<S::Dec>::default();
460    let mut cipher: S::Dec = cipher::KeyIvInit::new(&cipher_key, &cipher_iv);
461    let mac: S::Mac = digest::Mac::new(&mac_key);
462
463    // 8. Verify MAC
464    mac.chain_update(&*m)
465        .verify(&tag)
466        .map_err(DecError::MacInvalid)?;
467
468    // 9. Decrypt message
469    cipher::StreamCipher::try_apply_keystream(&mut cipher, m).map_err(DecError::StreamEnd)?;
470
471    // 10. Output message
472    Ok(m)
473}
474
475fn block_decrypt_in_place<'m, S: Suite>(
476    message: EncryptedMessage<'m, S>,
477    d: &generic_ec::NonZero<generic_ec::SecretScalar<S::E>>,
478) -> Result<&'m mut [u8], DecError>
479where
480    S::Mac: digest::Mac + cipher::KeyInit,
481    S::Dec: cipher::KeyIvInit + cipher::BlockDecryptMut,
482{
483    // Byte conversion of step 1 and 2 is done separately
484
485    let r = message.ephemeral_key;
486    let m = message.message;
487    let tag = message.tag;
488
489    // 3. Verify the validity of the ephemeral key - unnecessary as all
490    // verification steps outlined in 3.2.2.1 of SECG SEC-1 (including non-zero
491    // point) are encoded in types and thus are achieved by construction
492
493    // Steps 4-7 encapsulated in KEM
494    let mut cipher_key = cipher::Key::<S::Dec>::default();
495    let mut mac_key = cipher::Key::<S::Mac>::default();
496    ecies_kem(r, d, &mut cipher_key, &mut mac_key).map_err(DecError::Kdf)?;
497
498    // Use zero IV since the key never repeats
499    let cipher_iv = cipher::Iv::<S::Dec>::default();
500    let cipher: S::Dec = cipher::KeyIvInit::new(&cipher_key, &cipher_iv);
501    let mac: S::Mac = digest::Mac::new(&mac_key);
502
503    // 8. Verify MAC
504    mac.chain_update(&*m)
505        .verify(&tag)
506        .map_err(DecError::MacInvalid)?;
507
508    // 9. Decrypt message
509    let s = cipher::BlockDecryptMut::decrypt_padded_mut::<cipher::block_padding::Pkcs7>(cipher, m)
510        .map_err(DecError::PadError)?;
511    let len_without_padding = s.len();
512
513    // 10. Output message
514    Ok(&mut m[..len_without_padding])
515}
516
517impl<'m, S: Suite> EncryptedMessage<'m, S> {
518    /// Convert the message triplet to bytes following the description in SECG
519    /// SEC-1: `ephemeral_key || message || MAC`. Ephemeral key is stored in
520    /// compressed form when supported.
521    pub fn to_bytes(&self) -> Vec<u8> {
522        // Followint SECG SEC-1 part 5.1.3, byte representation is a
523        // concatenation of component represenatations
524        let r = self.ephemeral_key.to_bytes(true);
525        let mut bytes = Vec::with_capacity(r.len() + self.message.len() + self.tag.len());
526        bytes.extend_from_slice(&r);
527        bytes.extend_from_slice(self.message);
528        bytes.extend_from_slice(&self.tag);
529        bytes
530    }
531
532    /// Read the message triplet from bytes
533    pub fn from_bytes(bytes: &'m mut [u8]) -> Result<Self, DeserializeError> {
534        // No only for convenience, but because borrow checker can't say that
535        // `len` doesn't borrow for lifetime of its return value?
536        let l = bytes.len();
537
538        // Followint SECG SEC-1 part 5.1.4, byte representation is a
539        // concatenation of component represenatations. Care must be taken
540        // to parse the point correctly if it's compressed or not.
541        // Try to parse the ephemeral key, first as compressed, then as uncompressed
542        let compressed_len = generic_ec::Point::<S::E>::serialized_len(true);
543        let compressed_slice = bytes
544            .get(..compressed_len)
545            .ok_or(DeserializeError::TooShort)?;
546        let (point_len, ephemeral_key) =
547            match generic_ec::Point::<S::E>::from_bytes(compressed_slice) {
548                Ok(point) => (compressed_len, point),
549                Err(e1) => {
550                    // Compressed parsing failed, try uncompressed
551                    let uncompressed_len = generic_ec::Point::<S::E>::serialized_len(false);
552                    let uncompressed_slice = bytes
553                        .get(..uncompressed_len)
554                        .ok_or(DeserializeError::TooShort)?;
555                    match generic_ec::Point::<S::E>::from_bytes(uncompressed_slice) {
556                        Ok(point) => (uncompressed_len, point),
557                        Err(e2) => return Err(DeserializeError::InvalidPoint(e1, e2)),
558                    }
559                }
560            };
561        let ephemeral_key =
562            generic_ec::NonZero::<generic_ec::Point<S::E>>::try_from(ephemeral_key)?;
563
564        // Ensure the buffer is large enough to contain the point, tag, and message
565        let tag_len = GenericArray::<u8, MacSize<S>>::default().len();
566        let tag_start = l.checked_sub(tag_len).ok_or(DeserializeError::TooShort)?;
567        if tag_start < point_len {
568            return Err(DeserializeError::TooShort);
569        }
570        let tag = &bytes[tag_start..];
571        let tag = GenericArray::<u8, MacSize<S>>::clone_from_slice(tag);
572
573        let message = &mut bytes[point_len..tag_start];
574
575        Ok(EncryptedMessage {
576            ephemeral_key,
577            message,
578            tag,
579        })
580    }
581}
582
583fn with_copy<S: Suite>(
584    message: &[u8],
585    run: impl FnOnce(&mut [u8]) -> Result<EncryptedMessage<'_, S>, EncError>,
586) -> Result<Vec<u8>, EncError> {
587    let key_len = generic_ec::Point::<S::E>::serialized_len(true);
588    let mac_len = <MacSize<S> as cipher::typenum::Unsigned>::USIZE;
589    let mut bytes = vec![0; key_len + message.len() + mac_len];
590    let message_slice = &mut bytes[key_len..(key_len + message.len())];
591    message_slice.copy_from_slice(message);
592    let EncryptedMessage {
593        ephemeral_key, tag, ..
594    } = run(message_slice)?;
595    bytes[..key_len].copy_from_slice(&ephemeral_key.to_bytes(true));
596    bytes[(key_len + message.len())..].copy_from_slice(&tag);
597    Ok(bytes)
598}
599
600/// Error when encrypting message
601///
602/// [`EncError::PadError`] may happen when an invalid size buffer is supplied for in-place
603/// encryption. Other errors should happen in very rare cases.
604#[non_exhaustive]
605#[derive(Debug, thiserror::Error)]
606pub enum EncError {
607    /// Rare error for KDF. May be caused by invalid EC instance
608    #[error("KDF failed: {0}")]
609    Kdf(hkdf::InvalidLength),
610    /// Rare error fo symmetric encryption. May be cause by trying to encrypt
611    /// too much data
612    #[error("Key stream end (too much data supplied): {0}")]
613    StreamEnd(cipher::StreamCipherError),
614    /// Error of symmetric encryption, caused by passing a too small buffer to
615    /// [`PublicKey::block_encrypt_in_place`]
616    #[error("Pad error {0}")]
617    PadError(cipher::inout::PadError),
618}
619
620/// Error when encrypting message
621///
622/// Most errors can happen when a message has been tampered with.
623#[non_exhaustive]
624#[derive(Debug, thiserror::Error)]
625pub enum DecError {
626    /// Invalid MAC, caused by tampering with the message or using the wrong key
627    #[error("MAC verification failed: {0}")]
628    MacInvalid(digest::MacError),
629    /// Rare error for KDF. May be caused by invalid EC instance
630    #[error("KDF failed: {0}")]
631    Kdf(hkdf::InvalidLength),
632    /// Rare error fo symmetric encryption. May be cause by trying to encrypt
633    /// too much data
634    #[error("Key stream end (too much data supplied): {0}")]
635    StreamEnd(cipher::StreamCipherError),
636    /// Error unpadding, might be caused by sender sending a corrupted message
637    #[error("Pad error {0}")]
638    PadError(cipher::block_padding::UnpadError),
639}
640
641/// Error when deserializing the byte representation of a message
642#[non_exhaustive]
643#[derive(Debug, thiserror::Error)]
644pub enum DeserializeError {
645    /// Failed to read [`EncryptedMessage::ephemeral_key`]
646    #[error("Ephemeral DH key is invalid: {0}; {1}")]
647    InvalidPoint(
648        generic_ec::errors::InvalidPoint,
649        generic_ec::errors::InvalidPoint,
650    ),
651    /// Failed to read [`EncryptedMessage::ephemeral_key`]
652    #[error("Ephemeral DH key is zero")]
653    ZeroPoint(#[from] generic_ec::errors::ZeroPoint),
654    /// Input buffer is too short to contain a valid message
655    #[error("Input buffer is too short")]
656    TooShort,
657}