Skip to content

Commit

Permalink
core: Compute the AES key using HKDF
Browse files Browse the repository at this point in the history
  • Loading branch information
xevisalle committed Dec 17, 2024
1 parent bc69c33 commit bd24cd3
Show file tree
Hide file tree
Showing 5 changed files with 40 additions and 10 deletions.
1 change: 1 addition & 0 deletions core/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- Call `gen_note_sk` in `SecretKey::owns` to avoid code duplication [#246]
- `ViewKey` now checks both `a` and `B` in `ct_eq()`
- Compute AES key using HKDF

### Removed

Expand Down
3 changes: 3 additions & 0 deletions core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ 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.4"
sha2 = "0.10.8"
hex-literal = "0.4"

[dev-dependencies]
assert_matches = "1.3"
Expand Down
33 changes: 27 additions & 6 deletions core/src/encryption/aes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ use aes_gcm::{
Aes256Gcm, Key,
};

use hkdf::Hkdf;
use sha2::Sha256;

use crate::Error;

const NONCE_SIZE: usize = 12;
Expand All @@ -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<R: RngCore + CryptoRng, const ENCRYPTION_SIZE: usize>(
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::<Aes256Gcm>::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::<Sha256>::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::<Aes256Gcm>::from_slice(&okm);

let cipher = Aes256Gcm::new(key);
let nonce = Aes256Gcm::generate_nonce(rng);
Expand All @@ -48,12 +60,21 @@ pub fn encrypt<R: RngCore + CryptoRng, const ENCRYPTION_SIZE: usize>(
/// returning the plaintext
pub fn decrypt<const PLAINTEXT_SIZE: usize>(
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::<Aes256Gcm>::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::<Sha256>::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::<Aes256Gcm>::from_slice(&okm);

let nonce = &encryption[..NONCE_SIZE];
let ciphertext = &encryption[NONCE_SIZE..];
Expand Down
8 changes: 6 additions & 2 deletions core/src/note.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.")
}
};
Expand Down Expand Up @@ -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])?;

Expand Down
5 changes: 3 additions & 2 deletions core/tests/encryption.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down

0 comments on commit bd24cd3

Please sign in to comment.