diff --git a/core/CHANGELOG.md b/core/CHANGELOG.md index f35f0e3..f4db5af 100644 --- a/core/CHANGELOG.md +++ b/core/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Changed + +- Compute AES key using HKDF [#261] + ## [0.32.1] - 2024-12-17 ### Added @@ -402,6 +406,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Canonical implementation shielded by feature. +[#261]: https://github.com/dusk-network/phoenix/issues/261 [#258]: https://github.com/dusk-network/phoenix/issues/258 [#255]: https://github.com/dusk-network/phoenix/issues/255 [#240]: https://github.com/dusk-network/phoenix/issues/240 diff --git a/core/Cargo.toml b/core/Cargo.toml index 402b753..a6006c1 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -27,6 +27,8 @@ bs58 = { version = "0.4" , optional = true } base64 = { version = "0.22", optional = true } serde_json = { version = "1.0", optional = true } hex = { version = "0.4" , optional = true } +hkdf = "0.12" +sha2 = "0.10" [dev-dependencies] assert_matches = "1.3" diff --git a/core/src/encryption/aes.rs b/core/src/encryption/aes.rs index 9a3a8bb..d2f0687 100644 --- a/core/src/encryption/aes.rs +++ b/core/src/encryption/aes.rs @@ -12,6 +12,9 @@ use aes_gcm::{ Aes256Gcm, Key, }; +use hkdf::Hkdf; +use sha2::Sha256; + use crate::Error; const NONCE_SIZE: usize = 12; @@ -24,13 +27,22 @@ pub const ENCRYPTION_EXTRA_SIZE: usize = NONCE_SIZE + 16; /// containing a nonce and the ciphertext (which includes the tag) pub fn encrypt( shared_secret_key: &JubJubAffine, + salt: &[u8], plaintext: &[u8], rng: &mut R, ) -> Result<[u8; ENCRYPTION_SIZE], Error> { // To encrypt using AES256 we need 32-bytes keys. Thus, we use - // the 32-bytes serialization of the 64-bytes DH key. - let key = shared_secret_key.to_bytes(); - let key = Key::::from_slice(&key); + // a 32-bytes key computed out of the 32-bytes serialization of the 64-bytes + // DH key, using the HKDF algorithm. + let ikm = shared_secret_key.to_bytes(); + let info = b"Phoenix-Dusk".to_vec(); + + let hk = Hkdf::::new(Some(salt), &ikm); + let mut okm = [0u8; 32]; + hk.expand(&info, &mut okm) + .expect("32 is a valid length for Sha256 to output"); + + let key = Key::::from_slice(&okm); let cipher = Aes256Gcm::new(key); let nonce = Aes256Gcm::generate_nonce(rng); @@ -48,12 +60,21 @@ pub fn encrypt( /// returning the plaintext pub fn decrypt( shared_secret_key: &JubJubAffine, + salt: &[u8], encryption: &[u8], ) -> Result<[u8; PLAINTEXT_SIZE], Error> { // To decrypt using AES256 we need 32-bytes keys. Thus, we use - // the 32-bytes serialization of the 64-bytes DH key. - let key = shared_secret_key.to_bytes(); - let key = Key::::from_slice(&key); + // a 32-bytes key computed out of the 32-bytes serialization of the 64-bytes + // DH key, using the HKDF algorithm. + let ikm = shared_secret_key.to_bytes(); + let info = b"Phoenix-Dusk".to_vec(); + + let hk = Hkdf::::new(Some(salt), &ikm); + let mut okm = [0u8; 32]; + hk.expand(&info, &mut okm) + .expect("32 is a valid length for Sha256 to output"); + + let key = Key::::from_slice(&okm); let nonce = &encryption[..NONCE_SIZE]; let ciphertext = &encryption[NONCE_SIZE..]; diff --git a/core/src/note.rs b/core/src/note.rs index 437da7b..33d88da 100644 --- a/core/src/note.rs +++ b/core/src/note.rs @@ -123,7 +123,9 @@ impl Note { let mut plaintext = value.to_bytes().to_vec(); plaintext.append(&mut value_blinder.to_bytes().to_vec()); - aes::encrypt(&shared_secret, &plaintext, rng) + let salt = stealth_address.to_bytes(); + + aes::encrypt(&shared_secret, &salt, &plaintext, rng) .expect("Encrypted correctly.") } }; @@ -238,8 +240,10 @@ impl Note { let R = self.stealth_address.R(); let shared_secret = dhke(vk.a(), R); + let salt = self.stealth_address.to_bytes(); + let dec_plaintext: [u8; PLAINTEXT_SIZE] = - aes::decrypt(&shared_secret, &self.value_enc)?; + aes::decrypt(&shared_secret, &salt, &self.value_enc)?; let value = u64::from_slice(&dec_plaintext[..u64::SIZE])?; diff --git a/core/tests/encryption.rs b/core/tests/encryption.rs index 9d33574..7d91929 100644 --- a/core/tests/encryption.rs +++ b/core/tests/encryption.rs @@ -20,10 +20,11 @@ fn test_aes_encrypt_and_decrypt() { JubJubAffine::from(GENERATOR * JubJubScalar::from(1234u64)); let plaintext = b"00112233445566778899"; + let salt = b"0123456789"; let encryption: [u8; ENCRYPTION_SIZE] = - aes::encrypt(&shared_secret_key, plaintext, &mut rng) + aes::encrypt(&shared_secret_key, salt, plaintext, &mut rng) .expect("Encrypted correctly."); - let dec_plaintext = aes::decrypt(&shared_secret_key, &encryption) + let dec_plaintext = aes::decrypt(&shared_secret_key, salt, &encryption) .expect("Decrypted correctly."); assert_eq!(&dec_plaintext, plaintext);