1#![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
30pub trait Suite {
37 type E: Curve;
39 type Mac: digest::OutputSizeUser;
41 type Enc;
43 type Dec;
46}
47
48pub(crate) type MacSize<S> = <<S as Suite>::Mac as digest::OutputSizeUser>::OutputSize;
49
50pub 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#[derive(Clone, Debug)]
71pub struct PrivateKey<S: Suite> {
72 pub scalar: generic_ec::NonZero<generic_ec::SecretScalar<S::E>>,
74}
75
76#[derive(Clone, Debug, PartialEq, Eq)]
82pub struct PublicKey<S: Suite> {
83 pub point: generic_ec::NonZero<generic_ec::Point<S::E>>,
85}
86
87#[derive(Debug, PartialEq)]
94pub struct EncryptedMessage<'m, S: Suite> {
95 pub ephemeral_key: generic_ec::NonZero<generic_ec::Point<S::E>>,
97 pub message: &'m mut [u8],
99 pub tag: GenericArray<u8, MacSize<S>>,
101}
102
103impl<S: Suite> PrivateKey<S> {
104 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 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 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 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 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 pub fn to_bytes(&self) -> Vec<u8> {
141 self.point.to_bytes(true).to_vec()
142 }
143
144 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 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 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 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 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 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 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 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 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 let z: generic_ec::NonZero<_> = (k * q).into_secret();
334 let z_bs = z.to_bytes(true);
338
339 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 let k = generic_ec::NonZero::<generic_ec::SecretScalar<S::E>>::random(rng);
363 let r = generic_ec::Point::generator() * &k;
364
365 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 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 cipher::StreamCipher::try_apply_keystream(&mut cipher, m).map_err(EncError::StreamEnd)?;
379
380 let d = mac.chain_update(&*m).finalize().into_bytes();
382
383 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 let k = generic_ec::NonZero::<generic_ec::SecretScalar<S::E>>::random(rng);
404 let r = generic_ec::Point::generator() * &k;
405
406 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 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 cipher::BlockEncryptMut::encrypt_padded_mut::<cipher::block_padding::Pkcs7>(
420 cipher, m, data_len,
421 )
422 .map_err(EncError::PadError)?;
423
424 let d = mac.chain_update(&*m).finalize().into_bytes();
426
427 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 let r = message.ephemeral_key;
446 let m = message.message;
447 let tag = message.tag;
448
449 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 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 mac.chain_update(&*m)
465 .verify(&tag)
466 .map_err(DecError::MacInvalid)?;
467
468 cipher::StreamCipher::try_apply_keystream(&mut cipher, m).map_err(DecError::StreamEnd)?;
470
471 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 let r = message.ephemeral_key;
486 let m = message.message;
487 let tag = message.tag;
488
489 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 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 mac.chain_update(&*m)
505 .verify(&tag)
506 .map_err(DecError::MacInvalid)?;
507
508 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 Ok(&mut m[..len_without_padding])
515}
516
517impl<'m, S: Suite> EncryptedMessage<'m, S> {
518 pub fn to_bytes(&self) -> Vec<u8> {
522 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 pub fn from_bytes(bytes: &'m mut [u8]) -> Result<Self, DeserializeError> {
534 let l = bytes.len();
537
538 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 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 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#[non_exhaustive]
605#[derive(Debug, thiserror::Error)]
606pub enum EncError {
607 #[error("KDF failed: {0}")]
609 Kdf(hkdf::InvalidLength),
610 #[error("Key stream end (too much data supplied): {0}")]
613 StreamEnd(cipher::StreamCipherError),
614 #[error("Pad error {0}")]
617 PadError(cipher::inout::PadError),
618}
619
620#[non_exhaustive]
624#[derive(Debug, thiserror::Error)]
625pub enum DecError {
626 #[error("MAC verification failed: {0}")]
628 MacInvalid(digest::MacError),
629 #[error("KDF failed: {0}")]
631 Kdf(hkdf::InvalidLength),
632 #[error("Key stream end (too much data supplied): {0}")]
635 StreamEnd(cipher::StreamCipherError),
636 #[error("Pad error {0}")]
638 PadError(cipher::block_padding::UnpadError),
639}
640
641#[non_exhaustive]
643#[derive(Debug, thiserror::Error)]
644pub enum DeserializeError {
645 #[error("Ephemeral DH key is invalid: {0}; {1}")]
647 InvalidPoint(
648 generic_ec::errors::InvalidPoint,
649 generic_ec::errors::InvalidPoint,
650 ),
651 #[error("Ephemeral DH key is zero")]
653 ZeroPoint(#[from] generic_ec::errors::ZeroPoint),
654 #[error("Input buffer is too short")]
656 TooShort,
657}