ecies_ed25519_silene/
lib.rs

1//! ECIES-ed25519: An Integrated Encryption Scheme on Twisted Edwards Curve25519.
2//!
3
4//! ECIES can be used to encrypt data using a public key such that it can only be decrypted
5//! by the holder of the corresponding private key. It is based on [curve25519-dalek](https://docs.rs/curve25519-dalek).
6//!
7//! There are two different backends for HKDF-SHA3_384 / AES-GCM operations:
8//!
9//!   - The `pure_rust` backend (default). It uses a collection of pure-rust implementations of SHA3, HKDF, AES, and AEAD.
10//!
11//!   - The `ring` backend uses [ring](https://briansmith.org/rustdoc/ring/). It uses rock solid primitives based on BoringSSL,
12//!     but cannot run on all platforms. For example it won't work in web assembly. To enable it add the following to your Cargo.toml:
13//!
14//!     `ecies-ed25519 = { version = "0.3", features = ["ring"] }`
15//!
16//! ## Example Usage
17//! ```rust
18//! let mut csprng = rand::thread_rng();
19//! let (secret, public) = ecies_ed25519::generate_keypair(&mut csprng);
20//!
21//! let message = "I 💖🔒";
22//!
23//! // Encrypt the message with the public key such that only the holder of the secret key can decrypt.
24//! let encrypted = ecies_ed25519::encrypt(&public, message.as_bytes(), &mut csprng).unwrap();
25//!
26//! // Decrypt the message with the secret key
27//! let decrypted = ecies_ed25519::decrypt(&secret, &encrypted);
28//!```
29//!
30//! ## `serde` support
31//!
32//! The `serde` feature is provided for serializing / deserializing private and public keys.
33//!
34
35use curve25519_dalek::scalar::Scalar;
36use rand::{CryptoRng, RngCore};
37
38mod keys;
39pub use keys::*;
40
41#[cfg(feature = "ring")]
42mod ring_backend;
43
44#[cfg(feature = "ring")]
45use ring_backend::*;
46
47#[cfg(feature = "pure_rust")]
48mod pure_rust_backend;
49
50#[cfg(feature = "pure_rust")]
51use pure_rust_backend::*;
52
53#[cfg(not(any(feature = "ring", feature = "pure_rust")))]
54compile_error!(
55    "ecies-rd25519: Either feature 'ring' or 'pure_rust' must be enabled for this crate."
56);
57
58#[cfg(all(feature = "ring", feature = "pure_rust"))]
59compile_error!(
60    "ecies-rd25519: Feature 'ring' and 'pure_rust' cannot both be enabled. Please choose one."
61);
62
63const HKDF_INFO: &[u8; 13] = b"ecies-ed25519";
64
65const AES_IV_LENGTH: usize = 12;
66
67type AesKey = [u8; 32];
68type SharedSecret = [u8; 32];
69
70/// Generate a keypair, ready for use in ECIES
71pub fn generate_keypair<R: CryptoRng + RngCore>(rng: &mut R) -> (SecretKey, PublicKey) {
72    let secret = SecretKey::generate(rng);
73    let public = PublicKey::from_secret(&secret);
74    (secret, public)
75}
76
77/// Encrypt a message using ECIES, it can only be decrypted by the receiver's SecretKey.
78pub fn encrypt<R: CryptoRng + RngCore>(
79    receiver_pub: &PublicKey,
80    msg: &[u8],
81    rng: &mut R,
82) -> Result<Vec<u8>, Error> {
83    let (ephemeral_sk, ephemeral_pk) = generate_keypair(rng);
84
85    let aes_key = encapsulate(&ephemeral_sk, receiver_pub);
86    let encrypted = aes_encrypt(&aes_key, msg, rng)?;
87
88    let mut cipher_text = Vec::with_capacity(PUBLIC_KEY_LENGTH + encrypted.len());
89    cipher_text.extend(ephemeral_pk.to_bytes().iter());
90    cipher_text.extend(encrypted);
91
92    Ok(cipher_text)
93}
94
95/// Decrypt a ECIES encrypted ciphertext using the receiver's SecretKey.
96pub fn decrypt(receiver_sec: &SecretKey, ciphertext: &[u8]) -> Result<Vec<u8>, Error> {
97    if ciphertext.len() <= PUBLIC_KEY_LENGTH {
98        return Err(Error::DecryptionFailedCiphertextShort);
99    }
100
101    let ephemeral_pk = PublicKey::from_bytes(&ciphertext[..PUBLIC_KEY_LENGTH])?;
102    let encrypted = &ciphertext[PUBLIC_KEY_LENGTH..];
103    let aes_key = decapsulate(receiver_sec, &ephemeral_pk);
104
105    let decrypted = aes_decrypt(&aes_key, encrypted).map_err(|_| Error::DecryptionFailed)?;
106
107    Ok(decrypted)
108}
109
110fn generate_shared(secret: &SecretKey, public: &PublicKey) -> SharedSecret {
111    let public = public.to_point();
112    #[allow(deprecated)]
113    let secret = Scalar::from_bits(secret.to_bytes());
114    let shared_point = public * secret;
115    let shared_point_compressed = shared_point.compress();
116
117    let output = shared_point_compressed.as_bytes().to_owned();
118
119    output
120}
121
122fn encapsulate(emphemeral_sk: &SecretKey, peer_pk: &PublicKey) -> AesKey {
123    let shared_point = generate_shared(emphemeral_sk, peer_pk);
124
125    let emphemeral_pk = PublicKey::from_secret(emphemeral_sk);
126
127    let mut master = [0u8; 32 * 2];
128    master[..32].clone_from_slice(emphemeral_pk.0.as_bytes());
129    master[32..].clone_from_slice(&shared_point);
130
131    hkdf_sha3(&master)
132}
133
134fn decapsulate(sk: &SecretKey, emphemeral_pk: &PublicKey) -> AesKey {
135    let shared_point = generate_shared(sk, emphemeral_pk);
136
137    let mut master = [0u8; 32 * 2];
138    master[..32].clone_from_slice(emphemeral_pk.0.as_bytes());
139    master[32..].clone_from_slice(&shared_point);
140
141    hkdf_sha3(&master)
142}
143
144/// Error types
145use thiserror::Error;
146
147#[derive(Debug, Error)]
148pub enum Error {
149    /// Encryption failed
150    #[error("ecies-rd25519: encryption failed")]
151    EncryptionFailed,
152
153    /// Encryption failed - RNG error
154    #[error("ecies-rd25519: encryption failed - RNG error")]
155    EncryptionFailedRng,
156
157    /// Decryption failed
158    #[error("ecies-rd25519: decryption failed")]
159    DecryptionFailed,
160
161    /// Decryption failed - ciphertext too short
162    #[error("ecies-rd25519: decryption failed - ciphertext too short")]
163    DecryptionFailedCiphertextShort,
164
165    /// Invalid public key bytes
166    #[error("ecies-rd25519: invalid public key bytes")]
167    InvalidPublicKeyBytes,
168
169    /// Invalid secret key bytes
170    #[error("ecies-rd25519: invalid secret key bytes")]
171    InvalidSecretKeyBytes,
172}
173
174#[cfg(test)]
175pub mod tests {
176    use super::*;
177
178    use rand::thread_rng;
179    use rand::SeedableRng;
180
181    #[test]
182    fn test_shared() {
183        let (emphemeral_sk, emphemeral_pk) = generate_keypair(&mut thread_rng());
184        let (peer_sk, peer_pk) = generate_keypair(&mut thread_rng());
185
186        assert_eq!(
187            generate_shared(&emphemeral_sk, &peer_pk),
188            generate_shared(&peer_sk, &emphemeral_pk)
189        );
190
191        // Make sure it fails when wrong keys used
192        assert_ne!(
193            generate_shared(&emphemeral_sk, &emphemeral_pk),
194            generate_shared(&peer_sk, &peer_pk)
195        )
196    }
197
198    #[test]
199    fn test_encapsulation() {
200        let (emphemeral_sk, emphemeral_pk) = generate_keypair(&mut thread_rng());
201        let (peer_sk, peer_pk) = generate_keypair(&mut thread_rng());
202
203        assert_eq!(
204            encapsulate(&emphemeral_sk, &peer_pk),
205            decapsulate(&peer_sk, &emphemeral_pk)
206        )
207    }
208
209    #[test]
210    fn test_aes() {
211        let mut test_rng = rand::rngs::StdRng::from_seed([0u8; 32]);
212        let mut key = [0u8; 32];
213        test_rng.fill_bytes(&mut key);
214
215        let plaintext = b"ABC";
216        let encrypted = aes_encrypt(&key, plaintext, &mut test_rng).unwrap();
217        let decrypted = aes_decrypt(&key, &encrypted).unwrap();
218
219        assert_eq!(plaintext, decrypted.as_slice());
220
221        // Test bad ciphertext
222        assert!(aes_decrypt(&key, &[0u8; 16]).is_err());
223
224        // Test bad secret key
225        let bad_secret = SecretKey::generate(&mut thread_rng());
226        assert!(aes_decrypt(bad_secret.as_bytes(), &encrypted).is_err());
227    }
228
229    #[test]
230    fn test_ecies_ed25519() {
231        let (peer_sk, peer_pk) = generate_keypair(&mut thread_rng());
232
233        let plaintext = b"ABOLISH ICE";
234
235        let encrypted = encrypt(&peer_pk, plaintext, &mut thread_rng()).unwrap();
236        let decrypted = decrypt(&peer_sk, &encrypted).unwrap();
237
238        assert_eq!(plaintext, decrypted.as_slice());
239
240        // Test bad ciphertext
241        assert!(decrypt(&peer_sk, &[0u8; 16]).is_err());
242
243        // Test that it fails when using a bad secret key
244        let bad_secret = SecretKey::generate(&mut thread_rng());
245        assert!(decrypt(&bad_secret, &encrypted).is_err());
246    }
247
248    #[test]
249    fn test_hkdf_sha256_interop() {
250        let known_key: Vec<u8> = vec![
251            204, 68, 78, 7, 8, 70, 53, 136, 56, 115, 129, 183, 226, 82, 147, 253, 62, 59, 170, 188,
252            131, 119, 31, 21, 249, 255, 19, 103, 230, 24, 213, 204,
253        ];
254        let key = hkdf_sha3(b"ABC123");
255
256        assert_eq!(key.to_vec(), known_key);
257    }
258
259    #[test]
260    fn test_aes_interop() {
261        let key = [
262            118, 184, 224, 173, 160, 241, 61, 144, 64, 93, 106, 229, 83, 134, 189, 40, 189, 210,
263            25, 184, 160, 141, 237, 26, 168, 54, 239, 204, 139, 119, 13, 199,
264        ];
265
266        let plaintext = b"ABC";
267
268        let known_encrypted: Vec<u8> = vec![
269            218, 65, 89, 124, 81, 87, 72, 141, 119, 36, 224, 63, 149, 218, 64, 106, 159, 178, 238,
270            212, 36, 223, 93, 107, 19, 211, 62, 75, 195, 46, 177,
271        ];
272
273        let decrypted = aes_decrypt(&key, &known_encrypted).unwrap();
274        assert_eq!(plaintext, decrypted.as_slice());
275    }
276
277    #[test]
278    fn test_ecies_ed25519_interop() {
279        let peer_sk = SecretKey([
280            118, 184, 224, 173, 160, 241, 61, 144, 64, 93, 106, 229, 83, 134, 189, 40, 189, 210,
281            25, 184, 160, 141, 237, 26, 168, 54, 239, 204, 139, 119, 13, 199,
282        ]);
283
284        let plaintext = b"ABC";
285        let known_encrypted: Vec<u8> = vec![
286            235, 249, 207, 231, 91, 38, 106, 202, 22, 34, 114, 191, 107, 122, 99, 157, 43, 210, 46,
287            229, 219, 208, 111, 176, 98, 154, 42, 250, 114, 233, 68, 8, 159, 7, 231, 190, 85, 81,
288            56, 122, 152, 186, 151, 124, 246, 147, 163, 153, 29, 85, 248, 238, 194, 15, 180, 98,
289            163, 36, 49, 191, 133, 242, 186,
290        ];
291
292        let decrypted = decrypt(&peer_sk, &known_encrypted).unwrap();
293
294        assert_eq!(plaintext, decrypted.as_slice());
295    }
296
297    #[test]
298    fn test_public_key_extract() {
299        let mut test_rng = rand::rngs::StdRng::from_seed([0u8; 32]);
300
301        let secret = SecretKey::generate(&mut test_rng);
302        let public = PublicKey::from_secret(&secret);
303
304        PublicKey::from_bytes(public.as_bytes()).unwrap();
305
306        // Test bad bytes
307        assert!(PublicKey::from_bytes(&[0u8; 16]).is_err());
308        assert!(SecretKey::from_bytes(&[0u8; 16]).is_err());
309    }
310
311    #[cfg(feature = "serde")]
312    #[test]
313    fn test_hex() {
314        use hex::{FromHex, ToHex};
315
316        let mut test_rng = rand::rngs::StdRng::from_seed([0u8; 32]);
317        let (secret, public) = generate_keypair(&mut test_rng);
318
319        // lower
320        let serialized_secret: String = secret.encode_hex();
321        let serialized_public: String = public.encode_hex();
322
323        let deserialized_secret = SecretKey::from_hex(serialized_secret).unwrap();
324        let deserialized_public = PublicKey::from_hex(&serialized_public).unwrap();
325
326        assert_eq!(secret.to_bytes(), deserialized_secret.to_bytes());
327        assert_eq!(public.as_bytes(), deserialized_public.as_bytes());
328
329        // UPPER
330        let serialized_secret: String = secret.encode_hex_upper();
331        let serialized_public: String = public.encode_hex_upper();
332
333        let deserialized_secret = SecretKey::from_hex(serialized_secret).unwrap();
334        let deserialized_public = PublicKey::from_hex(serialized_public).unwrap();
335
336        assert_eq!(secret.to_bytes(), deserialized_secret.to_bytes());
337        assert_eq!(public.as_bytes(), deserialized_public.as_bytes());
338    }
339
340    #[cfg(feature = "serde")]
341    #[test]
342    fn test_serde_json() {
343        let mut test_rng = rand::rngs::StdRng::from_seed([0u8; 32]);
344        let (secret, public) = generate_keypair(&mut test_rng);
345
346        // String
347        let serialized_secret = serde_json::to_string(&secret).unwrap();
348        let serialized_public = serde_json::to_string(&public).unwrap();
349
350        let deserialized_secret: SecretKey = serde_json::from_str(&serialized_secret).unwrap();
351        let deserialized_public: PublicKey = serde_json::from_str(&serialized_public).unwrap();
352
353        assert_eq!(secret.to_bytes(), deserialized_secret.to_bytes());
354        assert_eq!(public.as_bytes(), deserialized_public.as_bytes());
355
356        // Stringy bytes
357        let deserialized_secret: SecretKey =
358            serde_json::from_slice(serialized_secret.as_bytes()).unwrap();
359        let deserialized_public: PublicKey =
360            serde_json::from_slice(serialized_public.as_bytes()).unwrap();
361
362        assert_eq!(secret.as_bytes(), deserialized_secret.as_bytes());
363        assert_eq!(public.as_bytes(), deserialized_public.as_bytes());
364
365        // Bytes
366        let serialized_secret = serde_json::to_vec(&secret).unwrap();
367        let serialized_public = serde_json::to_vec(&public).unwrap();
368
369        let deserialized_secret: SecretKey = serde_json::from_slice(&serialized_secret).unwrap();
370        let deserialized_public: PublicKey = serde_json::from_slice(&serialized_public).unwrap();
371
372        assert_eq!(secret.as_bytes(), deserialized_secret.as_bytes());
373        assert_eq!(public.as_bytes(), deserialized_public.as_bytes());
374
375        // Test errors - mangle some bits and confirm it doesn't work:
376        let mut serialized_public = serde_json::to_vec(&public).unwrap();
377        serialized_public[0] = 50;
378        assert!(serde_json::from_slice::<PublicKey>(&serialized_public).is_err());
379
380        let mut serialized_public = serde_json::to_vec(&public).unwrap();
381        serialized_public.push(48);
382        serialized_public.push(49);
383        assert!(serde_json::from_slice::<PublicKey>(&serialized_public).is_err());
384    }
385
386    #[cfg(feature = "serde")]
387    #[test]
388    fn test_serde_cbor() {
389        let mut test_rng = rand::rngs::StdRng::from_seed([0u8; 32]);
390        let (secret, public) = generate_keypair(&mut test_rng);
391
392        let serialized_secret = serde_cbor::to_vec(&secret).unwrap();
393        let serialized_public = serde_cbor::to_vec(&public).unwrap();
394
395        let deserialized_secret: SecretKey = serde_cbor::from_slice(&serialized_secret).unwrap();
396        let deserialized_public: PublicKey = serde_cbor::from_slice(&serialized_public).unwrap();
397
398        assert_eq!(secret.as_bytes(), deserialized_secret.as_bytes());
399        assert_eq!(public.as_bytes(), deserialized_public.as_bytes());
400
401        // Test errors - mangle some bits and confirm it doesn't work:
402        let mut serialized_public = serialized_public;
403        serialized_public[6] ^= 0xFF;
404        assert!(serde_cbor::from_slice::<PublicKey>(&serialized_public).is_err());
405    }
406}