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        eprintln!("encrypting message {} with padding {}", msg_len, pad_len);
223
224        let mut bytes = vec![0; key_len + msg_len + pad_len + mac_len];
225        bytes[key_len..(key_len + msg_len)].copy_from_slice(message);
226        // contains space for padding
227        let message_slice = &mut bytes[key_len..(key_len + msg_len + pad_len)];
228
229        let EncryptedMessage {
230            ephemeral_key, tag, ..
231        } = self.block_encrypt_in_place(message_slice, msg_len, rng)?;
232
233        bytes[..key_len].copy_from_slice(&ephemeral_key.to_bytes(true));
234        bytes[(key_len + msg_len + pad_len)..].copy_from_slice(&tag);
235        Ok(bytes)
236    }
237}
238
239impl<S: Suite> PrivateKey<S> {
240    /// Decrypt the message bytes in place. Variant for suites with stream
241    /// ciphers.
242    ///
243    /// When you have a buffer of bytes to decrypt, you first need to parse it
244    /// with `EncryptedMessage::from_bytes`, and then decrypt the structure
245    /// using this funciton. It will modify the bytes in the buffer and return a
246    /// slice to them.
247    pub fn stream_decrypt_in_place<'m>(
248        &self,
249        message: EncryptedMessage<'m, S>,
250    ) -> Result<&'m mut [u8], DecError>
251    where
252        S::Mac: digest::Mac + cipher::KeyInit,
253        S::Dec: cipher::KeyIvInit + cipher::StreamCipher,
254    {
255        stream_decrypt_in_place(message, &self.scalar)
256    }
257
258    /// Decrypt the message bytes into a new buffer. Variant for suites with
259    /// stream ciphers.
260    ///
261    /// When you have a buffer of bytes to decrypt, you first need to parse it
262    /// with `EncryptedMessage::from_bytes`, and then decrypt the structure
263    /// using this funciton. It will copy the message bytes into a new buffer
264    /// and return a [`Vec`] containing them.
265    pub fn stream_decrypt(&self, message: &EncryptedMessage<'_, S>) -> Result<Vec<u8>, DecError>
266    where
267        S::Mac: digest::Mac + cipher::KeyInit,
268        S::Dec: cipher::KeyIvInit + cipher::StreamCipher,
269    {
270        let mut msg_bytes = Vec::with_capacity(message.message.len());
271        msg_bytes.extend_from_slice(message.message);
272        let msg = EncryptedMessage {
273            ephemeral_key: message.ephemeral_key,
274            tag: message.tag.clone(),
275            message: &mut msg_bytes,
276        };
277        let _ = self.stream_decrypt_in_place(msg)?;
278        Ok(msg_bytes)
279    }
280
281    /// Decrypt the message bytes in place. Variant for suites with block
282    /// ciphers. Uses PKCS7 padding.
283    ///
284    /// When you have a buffer of bytes to decrypt, you first need to parse it
285    /// with `EncryptedMessage::from_bytes`, and then decrypt the structure
286    /// using this funciton. It will modify the bytes in the buffer and return a
287    /// slice to them.
288    pub fn block_decrypt_in_place<'m>(
289        &self,
290        message: EncryptedMessage<'m, S>,
291    ) -> Result<&'m mut [u8], DecError>
292    where
293        S::Mac: digest::Mac + cipher::KeyInit,
294        S::Dec: cipher::KeyIvInit + cipher::BlockDecryptMut,
295    {
296        block_decrypt_in_place(message, &self.scalar)
297    }
298
299    /// Decrypt the message bytes into a new buffer. Variant for suites with
300    /// block ciphers. Uses PKCS7 padding.
301    ///
302    /// When you have a buffer of bytes to decrypt, you first need to parse it
303    /// with `EncryptedMessage::from_bytes`, and then decrypt the structure
304    /// using this funciton. It will copy the message bytes into a new buffer
305    /// and return a [`Vec`] containing them.
306    pub fn block_decrypt(&self, message: &EncryptedMessage<'_, S>) -> Result<Vec<u8>, DecError>
307    where
308        S::Mac: digest::Mac + cipher::KeyInit,
309        S::Dec: cipher::KeyIvInit + cipher::BlockDecryptMut,
310    {
311        let mut msg_bytes = Vec::with_capacity(message.message.len());
312        msg_bytes.extend_from_slice(message.message);
313        let msg = EncryptedMessage {
314            ephemeral_key: message.ephemeral_key,
315            tag: message.tag.clone(),
316            message: &mut msg_bytes,
317        };
318        let s = self.block_decrypt_in_place(msg)?;
319        let len_without_pad = s.len();
320        msg_bytes.truncate(len_without_pad);
321        Ok(msg_bytes)
322    }
323}
324
325fn ecies_kem<E: Curve>(
326    q: generic_ec::NonZero<generic_ec::Point<E>>,
327    k: &generic_ec::NonZero<generic_ec::SecretScalar<E>>,
328    cipher_key: &mut [u8],
329    mac_key: &mut [u8],
330) -> Result<(), hkdf::InvalidLength> {
331    // Step 3 in encryption, step 4 in decruption: Use ECDH without small
332    // cofactor, as in generic-ec all scalars are guaranteed to be in the prime
333    // order subgroup
334    let z: generic_ec::NonZero<_> = k * q;
335    // No need to check the point for zero, it's guaranteed by construction
336
337    // 4 in enc, 5 in dec: convert z to octet string
338    let z_bs = z.to_bytes(true);
339
340    // 5-6 in enc, 6-7 in dec: use KDF to produce keys for encryption and mac
341    let kdf = hkdf::Hkdf::<sha2::Sha256>::new(None, &z_bs);
342    let mut all_bytes = vec![0u8; cipher_key.len() + mac_key.len()];
343
344    kdf.expand(b"generic-ecies cipher and mac", &mut all_bytes)?;
345    let mid = cipher_key.len();
346    cipher_key.copy_from_slice(&all_bytes[..mid]);
347    mac_key.copy_from_slice(&all_bytes[mid..]);
348    Ok(())
349}
350
351fn stream_encrypt_in_place<'m, S, R>(
352    m: &'m mut [u8],
353    q: &generic_ec::NonZero<generic_ec::Point<S::E>>,
354    rng: &mut R,
355) -> Result<EncryptedMessage<'m, S>, EncError>
356where
357    R: RngCore + CryptoRng,
358    S: Suite,
359    S::Mac: digest::Mac + cipher::KeyInit,
360    S::Enc: cipher::KeyIvInit + cipher::StreamCipher,
361{
362    // 1. Select ephemeral key pair
363    let k = generic_ec::NonZero::<generic_ec::SecretScalar<S::E>>::random(rng);
364    let r = generic_ec::Point::generator() * &k;
365
366    // 2: Use compression unconditionally
367
368    // Steps 3-6 encapsulated in KEM
369    let mut cipher_key = cipher::Key::<S::Enc>::default();
370    let mut mac_key = cipher::Key::<S::Mac>::default();
371    ecies_kem(*q, &k, &mut cipher_key, &mut mac_key).map_err(EncError::Kdf)?;
372
373    // Use zero IV since the key never repeats
374    let cipher_iv = cipher::Iv::<S::Enc>::default();
375    let mut cipher: S::Enc = cipher::KeyIvInit::new(&cipher_key, &cipher_iv);
376    let mac: S::Mac = digest::Mac::new(&mac_key);
377
378    // 7. Encrypt message
379    cipher::StreamCipher::try_apply_keystream(&mut cipher, m).map_err(EncError::StreamEnd)?;
380
381    // 8. MAC-tag the message
382    let d = mac.chain_update(&*m).finalize().into_bytes();
383
384    // 9. Output as structured message. Byte conversion is done separately
385    Ok(EncryptedMessage {
386        ephemeral_key: r,
387        message: m,
388        tag: d,
389    })
390}
391
392fn block_encrypt_in_place<'m, S: Suite, R>(
393    m: &'m mut [u8],
394    data_len: usize,
395    q: &generic_ec::NonZero<generic_ec::Point<S::E>>,
396    rng: &mut R,
397) -> Result<EncryptedMessage<'m, S>, EncError>
398where
399    R: RngCore + CryptoRng,
400    S::Mac: digest::Mac + cipher::KeyInit,
401    S::Enc: cipher::KeyIvInit + cipher::BlockEncryptMut,
402{
403    // 1. Select ephemeral key pair
404    let k = generic_ec::NonZero::<generic_ec::SecretScalar<S::E>>::random(rng);
405    let r = generic_ec::Point::generator() * &k;
406
407    // 2: Use compression unconditionally
408
409    // Steps 3-6 encapsulated in KEM
410    let mut cipher_key = cipher::Key::<S::Enc>::default();
411    let mut mac_key = cipher::Key::<S::Mac>::default();
412    ecies_kem(*q, &k, &mut cipher_key, &mut mac_key).map_err(EncError::Kdf)?;
413
414    // Use zero IV since the key never repeats
415    let cipher_iv = cipher::Iv::<S::Enc>::default();
416    let cipher: S::Enc = cipher::KeyIvInit::new(&cipher_key, &cipher_iv);
417    let mac: S::Mac = digest::Mac::new(&mac_key);
418
419    // 7. Encrypt message
420    cipher::BlockEncryptMut::encrypt_padded_mut::<cipher::block_padding::Pkcs7>(
421        cipher, m, data_len,
422    )
423    .map_err(EncError::PadError)?;
424
425    // 8. MAC-tag the message
426    let d = mac.chain_update(&*m).finalize().into_bytes();
427
428    // 9. Output as structured message. Byte conversion is done separately
429    Ok(EncryptedMessage {
430        ephemeral_key: r,
431        message: m,
432        tag: d,
433    })
434}
435
436fn stream_decrypt_in_place<'m, S: Suite>(
437    message: EncryptedMessage<'m, S>,
438    d: &generic_ec::NonZero<generic_ec::SecretScalar<S::E>>,
439) -> Result<&'m mut [u8], DecError>
440where
441    S::Mac: digest::Mac + cipher::KeyInit,
442    S::Dec: cipher::KeyIvInit + cipher::StreamCipher,
443{
444    // Byte conversion of step 1 and 2 is done separately
445
446    let r = message.ephemeral_key;
447    let m = message.message;
448    let tag = message.tag;
449
450    // 3. Verify the validity of the ephemeral key - unnecessary as all
451    // verification steps outlined in 3.2.2.1 of SECG SEC-1 (including non-zero
452    // point) are encoded in types and thus are achieved by construction
453
454    // Steps 4-7 encapsulated in KEM
455    let mut cipher_key = cipher::Key::<S::Dec>::default();
456    let mut mac_key = cipher::Key::<S::Mac>::default();
457    ecies_kem(r, d, &mut cipher_key, &mut mac_key).map_err(DecError::Kdf)?;
458
459    // Use zero IV since the key never repeats
460    let cipher_iv = cipher::Iv::<S::Dec>::default();
461    let mut cipher: S::Dec = cipher::KeyIvInit::new(&cipher_key, &cipher_iv);
462    let mac: S::Mac = digest::Mac::new(&mac_key);
463
464    // 8. Verify MAC
465    mac.chain_update(&*m)
466        .verify(&tag)
467        .map_err(DecError::MacInvalid)?;
468
469    // 9. Decrypt message
470    cipher::StreamCipher::try_apply_keystream(&mut cipher, m).map_err(DecError::StreamEnd)?;
471
472    // 10. Output message
473    Ok(m)
474}
475
476fn block_decrypt_in_place<'m, S: Suite>(
477    message: EncryptedMessage<'m, S>,
478    d: &generic_ec::NonZero<generic_ec::SecretScalar<S::E>>,
479) -> Result<&'m mut [u8], DecError>
480where
481    S::Mac: digest::Mac + cipher::KeyInit,
482    S::Dec: cipher::KeyIvInit + cipher::BlockDecryptMut,
483{
484    // Byte conversion of step 1 and 2 is done separately
485
486    let r = message.ephemeral_key;
487    let m = message.message;
488    let tag = message.tag;
489
490    // 3. Verify the validity of the ephemeral key - unnecessary as all
491    // verification steps outlined in 3.2.2.1 of SECG SEC-1 (including non-zero
492    // point) are encoded in types and thus are achieved by construction
493
494    // Steps 4-7 encapsulated in KEM
495    let mut cipher_key = cipher::Key::<S::Dec>::default();
496    let mut mac_key = cipher::Key::<S::Mac>::default();
497    ecies_kem(r, d, &mut cipher_key, &mut mac_key).map_err(DecError::Kdf)?;
498
499    // Use zero IV since the key never repeats
500    let cipher_iv = cipher::Iv::<S::Dec>::default();
501    let cipher: S::Dec = cipher::KeyIvInit::new(&cipher_key, &cipher_iv);
502    let mac: S::Mac = digest::Mac::new(&mac_key);
503
504    // 8. Verify MAC
505    mac.chain_update(&*m)
506        .verify(&tag)
507        .map_err(DecError::MacInvalid)?;
508
509    // 9. Decrypt message
510    eprintln!("decrypting length {}", m.len());
511    let s = cipher::BlockDecryptMut::decrypt_padded_mut::<cipher::block_padding::Pkcs7>(cipher, m)
512        .map_err(DecError::PadError)?;
513    let len_without_padding = s.len();
514
515    // 10. Output message
516    Ok(&mut m[..len_without_padding])
517}
518
519impl<'m, S: Suite> EncryptedMessage<'m, S> {
520    /// Convert the message triplet to bytes following the description in SECG
521    /// SEC-1: `ephemeral_key || message || MAC`. Ephemeral key is stored in
522    /// compressed form when supported.
523    pub fn to_bytes(&self) -> Vec<u8> {
524        // Followint SECG SEC-1 part 5.1.3, byte representation is a
525        // concatenation of component represenatations
526        let r = self.ephemeral_key.to_bytes(true);
527        let mut bytes = Vec::with_capacity(r.len() + self.message.len() + self.tag.len());
528        bytes.extend_from_slice(&r);
529        bytes.extend_from_slice(self.message);
530        bytes.extend_from_slice(&self.tag);
531        bytes
532    }
533
534    /// Read the message triplet from bytes
535    pub fn from_bytes(bytes: &'m mut [u8]) -> Result<Self, DeserializeError> {
536        // No only for convenience, but because borrow checker can't say that
537        // `len` doesn't borrow for lifetime of its return value?
538        let l = bytes.len();
539
540        // Followint SECG SEC-1 part 5.1.4, byte representation is a
541        // concatenation of component represenatations. Care must be taken
542        // to parse the point correctly if it's compressed or not.
543        let compressed_len = generic_ec::Point::<S::E>::serialized_len(true);
544        let (point_len, ephemeral_key) =
545            match generic_ec::Point::<S::E>::from_bytes(&bytes[..compressed_len]) {
546                Ok(point) => (compressed_len, point),
547                Err(e1) => {
548                    let len = generic_ec::Point::<S::E>::serialized_len(false);
549                    match generic_ec::Point::<S::E>::from_bytes(&bytes[..len]) {
550                        Ok(point) => (len, point),
551                        Err(e2) => return Err(DeserializeError::InvalidPoint(e1, e2)),
552                    }
553                }
554            };
555        let ephemeral_key =
556            generic_ec::NonZero::<generic_ec::Point<S::E>>::try_from(ephemeral_key)?;
557
558        let tag_len = GenericArray::<u8, MacSize<S>>::default().len();
559        let tag = &bytes[(l - tag_len)..];
560        let tag = GenericArray::<u8, MacSize<S>>::clone_from_slice(tag);
561
562        let message = &mut bytes[point_len..(l - tag_len)];
563
564        Ok(EncryptedMessage {
565            ephemeral_key,
566            message,
567            tag,
568        })
569    }
570}
571
572fn with_copy<S: Suite>(
573    message: &[u8],
574    run: impl FnOnce(&mut [u8]) -> Result<EncryptedMessage<'_, S>, EncError>,
575) -> Result<Vec<u8>, EncError> {
576    let key_len = generic_ec::Point::<S::E>::serialized_len(true);
577    let mac_len = <MacSize<S> as cipher::typenum::Unsigned>::USIZE;
578    let mut bytes = vec![0; key_len + message.len() + mac_len];
579    let message_slice = &mut bytes[key_len..(key_len + message.len())];
580    message_slice.copy_from_slice(message);
581    let EncryptedMessage {
582        ephemeral_key, tag, ..
583    } = run(message_slice)?;
584    bytes[..key_len].copy_from_slice(&ephemeral_key.to_bytes(true));
585    bytes[(key_len + message.len())..].copy_from_slice(&tag);
586    Ok(bytes)
587}
588
589/// Error when encrypting message
590///
591/// [`EncError::PadError`] may happen when an invalid size buffer is supplied for in-place
592/// encryption. Other errors should happen in very rare cases.
593#[derive(Debug, thiserror::Error)]
594pub enum EncError {
595    /// Rare error for KDF. May be caused by invalid EC instance
596    #[error("KDF failed: {0}")]
597    Kdf(hkdf::InvalidLength),
598    /// Rare error fo symmetric encryption. May be cause by trying to encrypt
599    /// too much data
600    #[error("Key stream end (too much data supplied): {0}")]
601    StreamEnd(cipher::StreamCipherError),
602    /// Error of symmetric encryption, caused by passing a too small buffer to
603    /// [`PublicKey::block_encrypt_in_place`]
604    #[error("Pad error {0}")]
605    PadError(cipher::inout::PadError),
606}
607
608/// Error when encrypting message
609///
610/// Most errors can happen when a message has been tampered with.
611#[derive(Debug, thiserror::Error)]
612pub enum DecError {
613    /// Invalid MAC, caused by tampering with the message or using the wrong key
614    #[error("MAC verification failed: {0}")]
615    MacInvalid(digest::MacError),
616    /// Rare error for KDF. May be caused by invalid EC instance
617    #[error("KDF failed: {0}")]
618    Kdf(hkdf::InvalidLength),
619    /// Rare error fo symmetric encryption. May be cause by trying to encrypt
620    /// too much data
621    #[error("Key stream end (too much data supplied): {0}")]
622    StreamEnd(cipher::StreamCipherError),
623    /// Error unpadding, might be caused by sender sending a corrupted message
624    #[error("Pad error {0}")]
625    PadError(cipher::block_padding::UnpadError),
626}
627
628/// Error when deserializing the byte representation of a message
629#[derive(Debug, thiserror::Error)]
630pub enum DeserializeError {
631    /// Failed to read [`EncryptedMessage::ephemeral_key`]
632    #[error("Ephemeral DH key is invalid: {0}; {1}")]
633    InvalidPoint(
634        generic_ec::errors::InvalidPoint,
635        generic_ec::errors::InvalidPoint,
636    ),
637    /// Failed to read [`EncryptedMessage::ephemeral_key`]
638    #[error("Ephemeral DH key is zero")]
639    ZeroPoint(#[from] generic_ec::errors::ZeroPoint),
640}