diem_crypto/
noise.rs

1// Copyright (c) The Diem Core Contributors
2// SPDX-License-Identifier: Apache-2.0
3
4//! Noise is a [protocol framework](https://noiseprotocol.org/) which we use in Diem to
5//! encrypt and authenticate communications between nodes of the network.
6//!
7//! This file implements a stripped-down version of Noise_IK_25519_AESGCM_SHA256.
8//! This means that only the parts that we care about (the IK handshake) are implemented.
9//!
10//! Note that to benefit from hardware support for AES, you must build this crate with the following
11//! flags: `RUSTFLAGS="-Ctarget-cpu=skylake -Ctarget-feature=+aes,+sse2,+sse4.1,+ssse3"`.
12//!
13//! Usage example:
14//!
15//! ```
16//! use diem_crypto::{noise, x25519, traits::*};
17//! use rand::prelude::*;
18//!
19//! # fn main() -> Result<(), diem_crypto::noise::NoiseError> {
20//! let mut rng = rand::thread_rng();
21//! let initiator_static = x25519::PrivateKey::generate(&mut rng);
22//! let responder_static = x25519::PrivateKey::generate(&mut rng);
23//! let responder_public = responder_static.public_key();
24//!
25//! let initiator = noise::NoiseConfig::new(initiator_static);
26//! let responder = noise::NoiseConfig::new(responder_static);
27//!
28//! let payload1 = b"the client can send an optional payload in the first message";
29//! let mut buffer = vec![0u8; noise::handshake_init_msg_len(payload1.len())];
30//! let initiator_state = initiator
31//!   .initiate_connection(&mut rng, b"prologue", responder_public, Some(payload1), &mut buffer)?;
32//!
33//! let payload2 = b"the server can send an optional payload as well as part of the handshake";
34//! let mut buffer2 = vec![0u8; noise::handshake_resp_msg_len(payload2.len())];
35//! let (received_payload, mut responder_session) = responder
36//!   .respond_to_client_and_finalize(&mut rng, b"prologue", &buffer, Some(payload2), &mut buffer2)?;
37//! assert_eq!(received_payload.as_slice(), &payload1[..]);
38//!
39//! let (received_payload, mut initiator_session) = initiator
40//!   .finalize_connection(initiator_state, &buffer2)?;
41//! assert_eq!(received_payload.as_slice(), &payload2[..]);
42//!
43//! let message_sent = b"hello world".to_vec();
44//! let mut buffer = message_sent.clone();
45//! let auth_tag = initiator_session
46//!   .write_message_in_place(&mut buffer)?;
47//! buffer.extend_from_slice(&auth_tag);
48//!
49//! let received_message = responder_session
50//!   .read_message_in_place(&mut buffer)?;
51//!
52//! assert_eq!(received_message, message_sent.as_slice());
53//!
54//! # Ok(())
55//! # }
56//! ```
57//!
58#![allow(clippy::integer_arithmetic)]
59
60use crate::{hash::HashValue, hkdf::Hkdf, traits::Uniform as _, x25519};
61use aes_gcm::{
62    aead::{generic_array::GenericArray, Aead, AeadInPlace, NewAead, Payload},
63    Aes256Gcm,
64};
65use sha2::Digest;
66use std::{
67    convert::TryFrom as _,
68    io::{Cursor, Read as _, Write as _},
69};
70use thiserror::Error;
71
72//
73// Useful constants
74// ----------------
75//
76
77/// A noise message cannot be larger than 65535 bytes as per the specification.
78pub const MAX_SIZE_NOISE_MSG: usize = 65535;
79
80/// The authentication tag length of AES-GCM.
81pub const AES_GCM_TAGLEN: usize = 16;
82
83/// The only Noise handshake protocol that we implement in this file.
84const PROTOCOL_NAME: &[u8] = b"Noise_IK_25519_AESGCM_SHA256\0\0\0\0";
85
86/// The nonce size we use for AES-GCM.
87const AES_NONCE_SIZE: usize = 12;
88
89/// A handy const fn to get the expanded size of a plaintext after encryption
90pub const fn encrypted_len(plaintext_len: usize) -> usize {
91    plaintext_len + AES_GCM_TAGLEN
92}
93
94/// A handy const fn to get the size of a plaintext from a ciphertext size
95pub const fn decrypted_len(ciphertext_len: usize) -> usize {
96    ciphertext_len - AES_GCM_TAGLEN
97}
98
99/// A handy const fn to get the size of the first handshake message
100pub const fn handshake_init_msg_len(payload_len: usize) -> usize {
101    // e
102    let e_len = x25519::PUBLIC_KEY_SIZE;
103    // encrypted s
104    let enc_s_len = encrypted_len(x25519::PUBLIC_KEY_SIZE);
105    // encrypted payload
106    let enc_payload_len = encrypted_len(payload_len);
107    //
108    e_len + enc_s_len + enc_payload_len
109}
110
111/// A handy const fn to get the size of the second handshake message
112pub const fn handshake_resp_msg_len(payload_len: usize) -> usize {
113    // e
114    let e_len = x25519::PUBLIC_KEY_SIZE;
115    // encrypted payload
116    let enc_payload_len = encrypted_len(payload_len);
117    //
118    e_len + enc_payload_len
119}
120
121/// This implementation relies on the fact that the hash function used has a 256-bit output
122#[rustfmt::skip]
123const _: [(); 32] = [(); HashValue::LENGTH];
124
125//
126// Errors
127// ------
128//
129
130/// A NoiseError enum represents the different types of error that noise can return to users of the crate
131#[derive(Debug, Error)]
132pub enum NoiseError {
133    /// the received message is too short to contain the expected data
134    #[error("noise: the received message is too short to contain the expected data")]
135    MsgTooShort,
136
137    /// HKDF has failed (in practice there is no reason for HKDF to fail)
138    #[error("noise: HKDF has failed")]
139    Hkdf,
140
141    /// encryption has failed (in practice there is no reason for encryption to fail)
142    #[error("noise: encryption has failed")]
143    Encrypt,
144
145    /// could not decrypt the received data (most likely the data was tampered with
146    #[error("noise: could not decrypt the received data")]
147    Decrypt,
148
149    /// the public key received is of the wrong format
150    #[error("noise: the public key received is of the wrong format")]
151    WrongPublicKeyReceived,
152
153    /// session was closed due to decrypt error
154    #[error("noise: session was closed due to decrypt error")]
155    SessionClosed,
156
157    /// the payload that we are trying to send is too large
158    #[error("noise: the payload that we are trying to send is too large")]
159    PayloadTooLarge,
160
161    /// the message we received is too large
162    #[error("noise: the message we received is too large")]
163    ReceivedMsgTooLarge,
164
165    /// the response buffer passed as argument is too small
166    #[error("noise: the response buffer passed as argument is too small")]
167    ResponseBufferTooSmall,
168
169    /// the nonce exceeds the maximum u64 value (in practice this should not happen)
170    #[error("noise: the nonce exceeds the maximum u64 value")]
171    NonceOverflow,
172}
173
174//
175// helpers
176// -------
177//
178
179fn hash(data: &[u8]) -> Vec<u8> {
180    sha2::Sha256::digest(data).to_vec()
181}
182
183fn hkdf(ck: &[u8], dh_output: Option<&[u8]>) -> Result<(Vec<u8>, Vec<u8>), NoiseError> {
184    let dh_output = dh_output.unwrap_or_else(|| &[]);
185    let hkdf_output = if dh_output.is_empty() {
186        Hkdf::<sha2::Sha256>::extract_then_expand_no_ikm(Some(ck), None, 64)
187    } else {
188        Hkdf::<sha2::Sha256>::extract_then_expand(Some(ck), dh_output, None, 64)
189    };
190
191    let hkdf_output = hkdf_output.map_err(|_| NoiseError::Hkdf)?;
192    let (k1, k2) = hkdf_output.split_at(32);
193    Ok((k1.to_vec(), k2.to_vec()))
194}
195
196fn mix_hash(h: &mut Vec<u8>, data: &[u8]) {
197    h.extend_from_slice(data);
198    *h = hash(h);
199}
200
201fn mix_key(ck: &mut Vec<u8>, dh_output: &[u8]) -> Result<Vec<u8>, NoiseError> {
202    let (new_ck, k) = hkdf(ck, Some(dh_output))?;
203    *ck = new_ck;
204    Ok(k)
205}
206
207//
208// Noise implementation
209// --------------------
210//
211
212/// A key holder structure used for both initiators and responders.
213#[derive(Debug)]
214pub struct NoiseConfig {
215    private_key: x25519::PrivateKey,
216    public_key: x25519::PublicKey,
217}
218
219/// Refer to the Noise protocol framework specification in order to understand these fields.
220#[cfg_attr(test, derive(Clone))]
221pub struct InitiatorHandshakeState {
222    /// rolling hash
223    h: Vec<u8>,
224    /// chaining key
225    ck: Vec<u8>,
226    /// ephemeral key
227    e: x25519::PrivateKey,
228    /// remote static key used
229    rs: x25519::PublicKey,
230}
231
232/// Refer to the Noise protocol framework specification in order to understand these fields.
233#[cfg_attr(test, derive(Clone))]
234pub struct ResponderHandshakeState {
235    /// rolling hash
236    h: Vec<u8>,
237    /// chaining key
238    ck: Vec<u8>,
239    /// remote static key received
240    rs: x25519::PublicKey,
241    /// remote ephemeral key receiced
242    re: x25519::PublicKey,
243}
244
245impl NoiseConfig {
246    /// A peer must create a NoiseConfig through this function before being able to connect with other peers.
247    pub fn new(private_key: x25519::PrivateKey) -> Self {
248        // we could take a public key as argument, and it would be faster, but this is cleaner
249        let public_key = private_key.public_key();
250        Self {
251            private_key,
252            public_key,
253        }
254    }
255
256    /// Handy getter to access the configuration's public key
257    pub fn public_key(&self) -> x25519::PublicKey {
258        self.public_key
259    }
260
261    //
262    // Initiator
263    // ---------
264
265    /// An initiator can use this function to initiate a handshake with a known responder.
266    pub fn initiate_connection(
267        &self,
268        rng: &mut (impl rand::RngCore + rand::CryptoRng),
269        prologue: &[u8],
270        remote_public: x25519::PublicKey,
271        payload: Option<&[u8]>,
272        response_buffer: &mut [u8],
273    ) -> Result<InitiatorHandshakeState, NoiseError> {
274        // checks
275        let payload_len = payload.map(<[u8]>::len).unwrap_or(0);
276        let buffer_size_required = handshake_init_msg_len(payload_len);
277        if buffer_size_required > MAX_SIZE_NOISE_MSG {
278            return Err(NoiseError::PayloadTooLarge);
279        }
280        if response_buffer.len() < buffer_size_required {
281            return Err(NoiseError::ResponseBufferTooSmall);
282        }
283        // initialize
284        let mut h = PROTOCOL_NAME.to_vec();
285        let mut ck = PROTOCOL_NAME.to_vec();
286        let rs = remote_public; // for naming consistency with the specification
287        mix_hash(&mut h, prologue);
288        mix_hash(&mut h, rs.as_slice());
289
290        // -> e
291        let e = x25519::PrivateKey::generate(rng);
292        let e_pub = e.public_key();
293
294        mix_hash(&mut h, e_pub.as_slice());
295        let mut response_buffer = Cursor::new(response_buffer);
296        response_buffer
297            .write(e_pub.as_slice())
298            .map_err(|_| NoiseError::ResponseBufferTooSmall)?;
299
300        // -> es
301        let dh_output = e.diffie_hellman(&rs);
302        let k = mix_key(&mut ck, &dh_output)?;
303
304        // -> s
305        let aead = Aes256Gcm::new(GenericArray::from_slice(&k));
306
307        let msg_and_ad = Payload {
308            msg: self.public_key.as_slice(),
309            aad: &h,
310        };
311        let nonce = GenericArray::from_slice(&[0u8; AES_NONCE_SIZE]);
312        let encrypted_static = aead
313            .encrypt(nonce, msg_and_ad)
314            .map_err(|_| NoiseError::Encrypt)?;
315
316        mix_hash(&mut h, &encrypted_static);
317        response_buffer
318            .write(&encrypted_static)
319            .map_err(|_| NoiseError::ResponseBufferTooSmall)?;
320
321        // -> ss
322        let dh_output = self.private_key.diffie_hellman(&rs);
323        let k = mix_key(&mut ck, &dh_output)?;
324
325        // -> payload
326        let aead = Aes256Gcm::new(GenericArray::from_slice(&k));
327
328        let msg_and_ad = Payload {
329            msg: payload.unwrap_or_else(|| &[]),
330            aad: &h,
331        };
332        let nonce = GenericArray::from_slice(&[0u8; AES_NONCE_SIZE]);
333        let encrypted_payload = aead
334            .encrypt(nonce, msg_and_ad)
335            .map_err(|_| NoiseError::Encrypt)?;
336
337        mix_hash(&mut h, &encrypted_payload);
338
339        response_buffer
340            .write(&encrypted_payload)
341            .map_err(|_| NoiseError::ResponseBufferTooSmall)?;
342
343        // return
344        let handshake_state = InitiatorHandshakeState { h, ck, e, rs };
345        Ok(handshake_state)
346    }
347
348    /// A client can call this to finalize a connection, after receiving an answer from a server.
349    pub fn finalize_connection(
350        &self,
351        handshake_state: InitiatorHandshakeState,
352        received_message: &[u8],
353    ) -> Result<(Vec<u8>, NoiseSession), NoiseError> {
354        // checks
355        if received_message.len() > MAX_SIZE_NOISE_MSG {
356            return Err(NoiseError::ReceivedMsgTooLarge);
357        }
358        // retrieve handshake state
359        let InitiatorHandshakeState {
360            mut h,
361            mut ck,
362            e,
363            rs,
364        } = handshake_state;
365
366        // <- e
367        let mut re = [0u8; x25519::PUBLIC_KEY_SIZE];
368        let mut cursor = Cursor::new(received_message);
369        cursor
370            .read_exact(&mut re)
371            .map_err(|_| NoiseError::MsgTooShort)?;
372        mix_hash(&mut h, &re);
373        let re = x25519::PublicKey::from(re);
374
375        // <- ee
376        let dh_output = e.diffie_hellman(&re);
377        mix_key(&mut ck, &dh_output)?;
378
379        // <- se
380        let dh_output = self.private_key.diffie_hellman(&re);
381        let k = mix_key(&mut ck, &dh_output)?;
382
383        // <- payload
384        let offset = cursor.position() as usize;
385        let received_encrypted_payload = &cursor.into_inner()[offset..];
386
387        let aead = Aes256Gcm::new(GenericArray::from_slice(&k));
388
389        let nonce = GenericArray::from_slice(&[0u8; AES_NONCE_SIZE]);
390        let ct_and_ad = Payload {
391            msg: received_encrypted_payload,
392            aad: &h,
393        };
394        let received_payload = aead
395            .decrypt(nonce, ct_and_ad)
396            .map_err(|_| NoiseError::Decrypt)?;
397
398        // split
399        let (k1, k2) = hkdf(&ck, None)?;
400        let session = NoiseSession::new(k1, k2, rs);
401
402        //
403        Ok((received_payload, session))
404    }
405
406    //
407    // Responder
408    // ---------
409    // There are two ways to use this API:
410    // - either use `parse_client_init_message()` followed by `respond_to_client()`
411    // - or use the all-in-one `respond_to_client_and_finalize()`
412    //
413    // the reason for the first deconstructed API is that we might want to do
414    // some validation of the received initiator's public key which might
415    //
416
417    /// A responder can accept a connection by first parsing an initiator message.
418    /// The function respond_to_client is usually called after this to respond to the initiator.
419    pub fn parse_client_init_message(
420        &self,
421        prologue: &[u8],
422        received_message: &[u8],
423    ) -> Result<
424        (
425            x25519::PublicKey,       // initiator's public key
426            ResponderHandshakeState, // state to be used in respond_to_client
427            Vec<u8>,                 // payload received
428        ),
429        NoiseError,
430    > {
431        // checks
432        if received_message.len() > MAX_SIZE_NOISE_MSG {
433            return Err(NoiseError::ReceivedMsgTooLarge);
434        }
435        // initialize
436        let mut h = PROTOCOL_NAME.to_vec();
437        let mut ck = PROTOCOL_NAME.to_vec();
438        mix_hash(&mut h, prologue);
439        mix_hash(&mut h, self.public_key.as_slice());
440
441        // buffer message received
442        let mut cursor = Cursor::new(received_message);
443
444        // <- e
445        let mut re = [0u8; x25519::PUBLIC_KEY_SIZE];
446        cursor
447            .read_exact(&mut re)
448            .map_err(|_| NoiseError::MsgTooShort)?;
449        mix_hash(&mut h, &re);
450        let re = x25519::PublicKey::from(re);
451
452        // <- es
453        let dh_output = self.private_key.diffie_hellman(&re);
454        let k = mix_key(&mut ck, &dh_output)?;
455
456        // <- s
457        let mut encrypted_remote_static = [0u8; x25519::PUBLIC_KEY_SIZE + AES_GCM_TAGLEN];
458        cursor
459            .read_exact(&mut encrypted_remote_static)
460            .map_err(|_| NoiseError::MsgTooShort)?;
461
462        let aead = Aes256Gcm::new(GenericArray::from_slice(&k));
463
464        let nonce = GenericArray::from_slice(&[0u8; AES_NONCE_SIZE]);
465        let ct_and_ad = Payload {
466            msg: &encrypted_remote_static,
467            aad: &h,
468        };
469        let rs = aead
470            .decrypt(nonce, ct_and_ad)
471            .map_err(|_| NoiseError::Decrypt)?;
472        let rs = x25519::PublicKey::try_from(rs.as_slice())
473            .map_err(|_| NoiseError::WrongPublicKeyReceived)?;
474        mix_hash(&mut h, &encrypted_remote_static);
475
476        // <- ss
477        let dh_output = self.private_key.diffie_hellman(&rs);
478        let k = mix_key(&mut ck, &dh_output)?;
479
480        // <- payload
481        let offset = cursor.position() as usize;
482        let received_encrypted_payload = &cursor.into_inner()[offset..];
483
484        let aead = Aes256Gcm::new(GenericArray::from_slice(&k));
485
486        let nonce = GenericArray::from_slice(&[0u8; AES_NONCE_SIZE]);
487        let ct_and_ad = Payload {
488            msg: received_encrypted_payload,
489            aad: &h,
490        };
491        let received_payload = aead
492            .decrypt(nonce, ct_and_ad)
493            .map_err(|_| NoiseError::Decrypt)?;
494        mix_hash(&mut h, received_encrypted_payload);
495
496        // return
497        let handshake_state = ResponderHandshakeState { h, ck, rs, re };
498        Ok((rs, handshake_state, received_payload))
499    }
500
501    /// A responder can respond to an initiator by calling this function with the state obtained,
502    /// after calling parse_client_init_message
503    pub fn respond_to_client(
504        &self,
505        rng: &mut (impl rand::RngCore + rand::CryptoRng),
506        handshake_state: ResponderHandshakeState,
507        payload: Option<&[u8]>,
508        response_buffer: &mut [u8],
509    ) -> Result<NoiseSession, NoiseError> {
510        // checks
511        let payload_len = payload.map(<[u8]>::len).unwrap_or(0);
512        let buffer_size_required = handshake_resp_msg_len(payload_len);
513        if buffer_size_required > MAX_SIZE_NOISE_MSG {
514            return Err(NoiseError::PayloadTooLarge);
515        }
516        if response_buffer.len() < buffer_size_required {
517            return Err(NoiseError::ResponseBufferTooSmall);
518        }
519
520        // retrieve handshake state
521        let ResponderHandshakeState {
522            mut h,
523            mut ck,
524            rs,
525            re,
526        } = handshake_state;
527
528        // -> e
529        let e = x25519::PrivateKey::generate(rng);
530        let e_pub = e.public_key();
531
532        mix_hash(&mut h, e_pub.as_slice());
533        let mut response_buffer = Cursor::new(response_buffer);
534        response_buffer
535            .write(e_pub.as_slice())
536            .map_err(|_| NoiseError::ResponseBufferTooSmall)?;
537
538        // -> ee
539        let dh_output = e.diffie_hellman(&re);
540        mix_key(&mut ck, &dh_output)?;
541
542        // -> se
543        let dh_output = e.diffie_hellman(&rs);
544        let k = mix_key(&mut ck, &dh_output)?;
545
546        // -> payload
547        let aead = Aes256Gcm::new(GenericArray::from_slice(&k));
548
549        let msg_and_ad = Payload {
550            msg: payload.unwrap_or_else(|| &[]),
551            aad: &h,
552        };
553        let nonce = GenericArray::from_slice(&[0u8; AES_NONCE_SIZE]);
554        let encrypted_payload = aead
555            .encrypt(nonce, msg_and_ad)
556            .map_err(|_| NoiseError::Encrypt)?;
557        mix_hash(&mut h, &encrypted_payload);
558        response_buffer
559            .write(&encrypted_payload)
560            .map_err(|_| NoiseError::ResponseBufferTooSmall)?;
561
562        // split
563        let (k1, k2) = hkdf(&ck, None)?;
564        let session = NoiseSession::new(k2, k1, rs);
565
566        //
567        Ok(session)
568    }
569
570    /// This function is a one-call that replaces calling the two functions parse_client_init_message
571    /// and respond_to_client consecutively
572    pub fn respond_to_client_and_finalize(
573        &self,
574        rng: &mut (impl rand::RngCore + rand::CryptoRng),
575        prologue: &[u8],
576        received_message: &[u8],
577        payload: Option<&[u8]>,
578        response_buffer: &mut [u8],
579    ) -> Result<
580        (
581            Vec<u8>,      // the payload the initiator sent
582            NoiseSession, // The created session
583        ),
584        NoiseError,
585    > {
586        let (_, handshake_state, received_payload) =
587            self.parse_client_init_message(prologue, received_message)?;
588        let session = self.respond_to_client(rng, handshake_state, payload, response_buffer)?;
589        Ok((received_payload, session))
590    }
591}
592
593//
594// Post-Handshake
595// --------------
596
597/// A NoiseSession is produced after a successful Noise handshake, and can be use to encrypt and decrypt messages to the other peer.
598#[cfg_attr(test, derive(Clone))]
599pub struct NoiseSession {
600    /// a session can be marked as invalid if it has seen a decryption failure
601    valid: bool,
602    /// the public key of the other peer
603    remote_public_key: x25519::PublicKey,
604    /// key used to encrypt messages to the other peer
605    write_key: Vec<u8>,
606    /// associated nonce (in practice the maximum u64 value cannot be reached)
607    write_nonce: u64,
608    /// key used to decrypt messages received from the other peer
609    read_key: Vec<u8>,
610    /// associated nonce (in practice the maximum u64 value cannot be reached)
611    read_nonce: u64,
612}
613
614impl NoiseSession {
615    fn new(write_key: Vec<u8>, read_key: Vec<u8>, remote_public_key: x25519::PublicKey) -> Self {
616        Self {
617            valid: true,
618            remote_public_key,
619            write_key,
620            write_nonce: 0,
621            read_key,
622            read_nonce: 0,
623        }
624    }
625
626    /// create a dummy session with 0 keys
627    #[cfg(any(test, feature = "fuzzing"))]
628    pub fn new_for_testing() -> Self {
629        Self::new(
630            vec![0u8; 32],
631            vec![0u8; 32],
632            [0u8; x25519::PUBLIC_KEY_SIZE].into(),
633        )
634    }
635
636    /// obtain remote static public key
637    pub fn get_remote_static(&self) -> x25519::PublicKey {
638        self.remote_public_key
639    }
640
641    /// encrypts a message for the other peers (post-handshake)
642    /// the function encrypts in place, and returns the authentication tag as result
643    pub fn write_message_in_place(&mut self, message: &mut [u8]) -> Result<Vec<u8>, NoiseError> {
644        // checks
645        if !self.valid {
646            return Err(NoiseError::SessionClosed);
647        }
648        if message.len() > MAX_SIZE_NOISE_MSG - AES_GCM_TAGLEN {
649            return Err(NoiseError::PayloadTooLarge);
650        }
651
652        // encrypt in place
653        let aead = Aes256Gcm::new(GenericArray::from_slice(&self.write_key));
654        let mut nonce = [0u8; 4].to_vec();
655        nonce.extend_from_slice(&self.write_nonce.to_be_bytes());
656        let nonce = GenericArray::from_slice(&nonce);
657
658        let authentication_tag = aead
659            .encrypt_in_place_detached(nonce, b"", message)
660            .map_err(|_| NoiseError::Encrypt)?;
661
662        // increment nonce
663        self.write_nonce = self
664            .write_nonce
665            .checked_add(1)
666            .ok_or(NoiseError::NonceOverflow)?;
667
668        // return a subslice without the authentication tag
669        Ok(authentication_tag.to_vec())
670    }
671
672    /// decrypts a message from the other peer (post-handshake)
673    /// the function decrypts in place, and returns a subslice without the auth tag
674    pub fn read_message_in_place<'a>(
675        &mut self,
676        message: &'a mut [u8],
677    ) -> Result<&'a [u8], NoiseError> {
678        // checks
679        if !self.valid {
680            return Err(NoiseError::SessionClosed);
681        }
682        if message.len() > MAX_SIZE_NOISE_MSG {
683            self.valid = false;
684            return Err(NoiseError::ReceivedMsgTooLarge);
685        }
686        if message.len() < AES_GCM_TAGLEN {
687            self.valid = false;
688            return Err(NoiseError::ResponseBufferTooSmall);
689        }
690
691        // decrypt in place
692        let aead = Aes256Gcm::new(GenericArray::from_slice(&self.read_key));
693
694        let mut nonce = [0u8; 4].to_vec();
695        nonce.extend_from_slice(&self.read_nonce.to_be_bytes());
696        let nonce = GenericArray::from_slice(&nonce);
697
698        let (buffer, authentication_tag) = message.split_at_mut(message.len() - AES_GCM_TAGLEN);
699        let authentication_tag = GenericArray::from_slice(authentication_tag);
700        aead.decrypt_in_place_detached(nonce, b"", buffer, authentication_tag)
701            .map_err(|_| {
702                self.valid = false;
703                NoiseError::Decrypt
704            })?;
705
706        // increment nonce
707        self.read_nonce = self
708            .read_nonce
709            .checked_add(1)
710            .ok_or(NoiseError::NonceOverflow)?;
711
712        // return a subslice of the buffer representing the decrypted plaintext
713        Ok(buffer)
714    }
715}
716
717impl std::fmt::Debug for NoiseSession {
718    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
719        write!(f, "NoiseSession[...]")
720    }
721}