diem_crypto/
noise.rs

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