Skip to main content

phoenix_core/encryption/
aes.rs

1// This Source Code Form is subject to the terms of the Mozilla Public
2// License, v. 2.0. If a copy of the MPL was not distributed with this
3// file, You can obtain one at http://mozilla.org/MPL/2.0/.
4//
5// Copyright (c) DUSK NETWORK. All rights reserved.
6
7use dusk_jubjub::JubJubAffine;
8use rand::{CryptoRng, RngCore};
9
10use aes_gcm::{
11    Aes256Gcm, Key,
12    aead::{Aead, AeadCore, KeyInit},
13};
14
15use hkdf::Hkdf;
16use sha2::Sha256;
17
18use crate::Error;
19
20const NONCE_SIZE: usize = 12;
21
22/// Size of the extra encryption data required by the
23/// cipher: the nonce (12 bytes) and the tag (16 bytes)
24pub const ENCRYPTION_EXTRA_SIZE: usize = NONCE_SIZE + 16;
25
26/// Encrypts a plaintext given a shared DH secret key, returning a vector
27/// containing a nonce and the ciphertext (which includes the tag)
28pub fn encrypt<R: RngCore + CryptoRng, const ENCRYPTION_SIZE: usize>(
29    shared_secret_key: &JubJubAffine,
30    salt: &[u8],
31    plaintext: &[u8],
32    rng: &mut R,
33) -> Result<[u8; ENCRYPTION_SIZE], Error> {
34    // To encrypt using AES256 we need 32-bytes keys. Thus, we use
35    // a 32-bytes key computed out of the 32-bytes serialization of the 64-bytes
36    // DH key, using the HKDF algorithm.
37    let ikm = shared_secret_key.to_bytes();
38    let info = b"Phoenix-Dusk".to_vec();
39
40    let hk = Hkdf::<Sha256>::new(Some(salt), &ikm);
41    let mut okm = [0u8; 32];
42    hk.expand(&info, &mut okm)
43        .expect("32 is a valid length for Sha256 to output");
44
45    let key = Key::<Aes256Gcm>::from_slice(&okm);
46
47    let cipher = Aes256Gcm::new(key);
48    let nonce = Aes256Gcm::generate_nonce(rng);
49    let ciphertext = cipher.encrypt(&nonce, plaintext.as_ref())?;
50
51    let mut encryption = [0u8; ENCRYPTION_SIZE];
52
53    encryption[..NONCE_SIZE].copy_from_slice(&nonce);
54    encryption[NONCE_SIZE..].copy_from_slice(&ciphertext);
55
56    Ok(encryption)
57}
58
59/// Decrypts an encryption (nonce + ciphertext) given a shared DH secret key,
60/// returning the plaintext
61pub fn decrypt<const PLAINTEXT_SIZE: usize>(
62    shared_secret_key: &JubJubAffine,
63    salt: &[u8],
64    encryption: &[u8],
65) -> Result<[u8; PLAINTEXT_SIZE], Error> {
66    // To decrypt using AES256 we need 32-bytes keys. Thus, we use
67    // a 32-bytes key computed out of the 32-bytes serialization of the 64-bytes
68    // DH key, using the HKDF algorithm.
69    let ikm = shared_secret_key.to_bytes();
70    let info = b"Phoenix-Dusk".to_vec();
71
72    let hk = Hkdf::<Sha256>::new(Some(salt), &ikm);
73    let mut okm = [0u8; 32];
74    hk.expand(&info, &mut okm)
75        .expect("32 is a valid length for Sha256 to output");
76
77    let key = Key::<Aes256Gcm>::from_slice(&okm);
78
79    let nonce = &encryption[..NONCE_SIZE];
80    let ciphertext = &encryption[NONCE_SIZE..];
81
82    let cipher = Aes256Gcm::new(key);
83
84    let mut plaintext = [0u8; PLAINTEXT_SIZE];
85    plaintext.copy_from_slice(&cipher.decrypt(nonce.into(), ciphertext)?);
86
87    Ok(plaintext)
88}