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 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 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 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 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 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 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 let z: generic_ec::NonZero<_> = k * q;
335 let z_bs = z.to_bytes(true);
339
340 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 let k = generic_ec::NonZero::<generic_ec::SecretScalar<S::E>>::random(rng);
364 let r = generic_ec::Point::generator() * &k;
365
366 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 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 cipher::StreamCipher::try_apply_keystream(&mut cipher, m).map_err(EncError::StreamEnd)?;
380
381 let d = mac.chain_update(&*m).finalize().into_bytes();
383
384 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 let k = generic_ec::NonZero::<generic_ec::SecretScalar<S::E>>::random(rng);
405 let r = generic_ec::Point::generator() * &k;
406
407 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 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 cipher::BlockEncryptMut::encrypt_padded_mut::<cipher::block_padding::Pkcs7>(
421 cipher, m, data_len,
422 )
423 .map_err(EncError::PadError)?;
424
425 let d = mac.chain_update(&*m).finalize().into_bytes();
427
428 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 let r = message.ephemeral_key;
447 let m = message.message;
448 let tag = message.tag;
449
450 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 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 mac.chain_update(&*m)
466 .verify(&tag)
467 .map_err(DecError::MacInvalid)?;
468
469 cipher::StreamCipher::try_apply_keystream(&mut cipher, m).map_err(DecError::StreamEnd)?;
471
472 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 let r = message.ephemeral_key;
487 let m = message.message;
488 let tag = message.tag;
489
490 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 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 mac.chain_update(&*m)
506 .verify(&tag)
507 .map_err(DecError::MacInvalid)?;
508
509 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 Ok(&mut m[..len_without_padding])
517}
518
519impl<'m, S: Suite> EncryptedMessage<'m, S> {
520 pub fn to_bytes(&self) -> Vec<u8> {
524 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 pub fn from_bytes(bytes: &'m mut [u8]) -> Result<Self, DeserializeError> {
536 let l = bytes.len();
539
540 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#[derive(Debug, thiserror::Error)]
594pub enum EncError {
595 #[error("KDF failed: {0}")]
597 Kdf(hkdf::InvalidLength),
598 #[error("Key stream end (too much data supplied): {0}")]
601 StreamEnd(cipher::StreamCipherError),
602 #[error("Pad error {0}")]
605 PadError(cipher::inout::PadError),
606}
607
608#[derive(Debug, thiserror::Error)]
612pub enum DecError {
613 #[error("MAC verification failed: {0}")]
615 MacInvalid(digest::MacError),
616 #[error("KDF failed: {0}")]
618 Kdf(hkdf::InvalidLength),
619 #[error("Key stream end (too much data supplied): {0}")]
622 StreamEnd(cipher::StreamCipherError),
623 #[error("Pad error {0}")]
625 PadError(cipher::block_padding::UnpadError),
626}
627
628#[derive(Debug, thiserror::Error)]
630pub enum DeserializeError {
631 #[error("Ephemeral DH key is invalid: {0}; {1}")]
633 InvalidPoint(
634 generic_ec::errors::InvalidPoint,
635 generic_ec::errors::InvalidPoint,
636 ),
637 #[error("Ephemeral DH key is zero")]
639 ZeroPoint(#[from] generic_ec::errors::ZeroPoint),
640}