1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164
//! # hpke //! **WARNING:** This code has not been audited. Use at your own discretion. //! //! This is a pure Rust implementation of the //! [HPKE](https://datatracker.ietf.org/doc/draft-irtf-cfrg-hpke/) hybrid encryption scheme. The //! purpose of hybrid encryption is to use allow someone to send secure messages to an entity whose //! public key they know. Here's an example of Alice and Bob, where Alice knows Bob's public key: //! //! ```ignore //! # use rand::{rngs::StdRng, SeedableRng}; //! # use hpke::{ //! # aead::ChaCha20Poly1305, //! # kdf::HkdfSha384, //! # kem::X25519HkdfSha256, //! # EncappedKey, Kem as KemTrait, OpModeR, OpModeS, setup_receiver, setup_sender, //! # }; //! // These types define the ciphersuite Alice and Bob will be using //! type Kem = X25519HkdfSha256; //! type Aead = ChaCha20Poly1305; //! type Kdf = HkdfSha384; //! //! let mut csprng = StdRng::from_entropy(); //! # let (bob_sk, bob_pk) = Kem::gen_keypair(&mut csprng); //! //! // This is a description string for the session. Both Alice and Bob need to know this value. //! // It's not secret. //! let info_str = b"Alice and Bob's weekly chat"; //! //! // Alice initiates a session with Bob. OpModeS::Base means that Alice is not authenticating //! // herself at all. If she had a public key herself, or a pre-shared secret that Bob also //! // knew, she'd be able to authenticate herself. See the OpModeS and OpModeR types for more //! // detail. //! let (encapsulated_key, mut encryption_context) = //! hpke::setup_sender::<Aead, Kdf, Kem, _>(&OpModeS::Base, &bob_pk, info_str, &mut csprng) //! .expect("invalid server pubkey!"); //! //! // Alice encrypts a message to Bob. msg gets encrypted in place, and aad is authenticated //! // associated data that is not encrypted. //! let mut msg = *b"fronthand or backhand?"; //! let aad = b"a gentleman's game"; //! let auth_tag = encryption_context //! .seal(&mut msg, aad) //! .expect("encryption failed!"); //! // The msg was encrypted in-place. So rename it for clarity //! let ciphertext = msg; //! # let mut ciphertext = ciphertext; // Make it mutable so Bob can decrypt in place //! //! // ~~~ //! // Alice sends the encapsulated key, message ciphertext, AAD, and auth tag to Bob over the //! // internet. Alice doesn't care if it's an insecure connection, because only Bob can read //! // her ciphertext. //! // ~~~ //! //! // Somewhere far away, Bob receives the data and makes a decryption session //! let mut decryption_context = //! hpke::setup_receiver::<Aead, Kdf, Kem>( //! &OpModeR::Base, //! &bob_sk, //! &encapsulated_key, //! info_str, //! ).expect("failed to set up receiver!"); //! decryption_context.open(&mut ciphertext, aad, &auth_tag).expect("invalid ciphertext!"); //! // The ciphertext was decrypted in-place. So rename it for clarity //! let plaintext = ciphertext; //! //! assert_eq!(&plaintext, b"fronthand or backhand?"); //! ``` //-------- no_std stuff --------// #![no_std] #[cfg(feature = "std")] #[allow(unused_imports)] #[macro_use] extern crate std; #[cfg(not(feature = "std"))] #[allow(unused_imports)] #[macro_use] extern crate alloc; //-------- Testing stuff --------// // kat_tests tests all the implemented ciphersuites, and thus needs all the dependencies. It also // needs std for file IO. #[cfg(all(test, feature = "std", feature = "x25519", feature = "p256"))] mod kat_tests; // kat_tests requires serde #[cfg(all(test, feature = "std", feature = "x25519", feature = "p256"))] #[macro_use] extern crate serde_derive; #[cfg(test)] mod test_util; //-------- Modules and exports--------// // Re-export this version of generic_array, since that's what's used everywhere in this crate pub use generic_array; #[macro_use] mod util; pub mod aead; pub mod kdf; pub mod kem; pub mod kex; pub mod op_mode; pub mod setup; pub mod single_shot; #[cfg(feature = "serde_impls")] mod serde_impls; #[doc(inline)] pub use crate::aead::{AeadCtxR, AeadCtxS}; #[doc(inline)] pub use kem::{EncappedKey, Kem}; #[doc(inline)] pub use kex::{Deserializable, Serializable}; #[doc(inline)] pub use op_mode::{OpModeR, OpModeS, PskBundle}; #[doc(inline)] pub use setup::{setup_receiver, setup_sender}; #[doc(inline)] pub use single_shot::{single_shot_open, single_shot_seal}; //-------- Top-level types --------// /// Describes things that can go wrong when trying to seal or open a ciphertext #[derive(Clone, Copy, Debug)] pub enum HpkeError { /// The nonce sequence counter has overflowed SeqOverflow, /// The authentication tag was invalid when opening InvalidTag, /// An unspecified error occured during encryption Encryption, /// A key exchange input or output was invalid InvalidKeyExchange, /// The KDF was asked to output too many bytes InvalidKdfLength, /// The deserializer was given a bad encoding InvalidEncoding, } impl core::fmt::Display for HpkeError { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { let kind = match self { HpkeError::SeqOverflow => "Sequence overflow", HpkeError::InvalidTag => "Invalid tag", HpkeError::Encryption => "Encryption error", HpkeError::InvalidKeyExchange => "Key exchange validation error", HpkeError::InvalidKdfLength => "Too many bytes requested from KDF", HpkeError::InvalidEncoding => "Cannot deserialize byte sequence: invalid encoding", }; f.write_str(kind) } } // An Error type is just something that's Debug and Display #[cfg(feature = "std")] impl std::error::Error for HpkeError {}