Skip to content

Commit 42a0b28

Browse files
authored
add read/write functions accepting additional authentication data to StatelessTransportState (#182)
1 parent d252121 commit 42a0b28

File tree

1 file changed

+61
-0
lines changed

1 file changed

+61
-0
lines changed

src/stateless_transportstate.rs

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,34 @@ impl StatelessTransportState {
7070
cipher.encrypt(nonce, payload, message)
7171
}
7272

73+
/// Construct a message from `plaintext` and write it to the `out` buffer like
74+
/// [`write_message`](Self::write_message). Additionally when computing
75+
/// the authentication tag, mix in the contents of `authtext` which the receiving
76+
/// side will need to also include for successful decryption and authentication.
77+
///
78+
/// Returns the number of bytes written to `out`.
79+
///
80+
/// # Errors
81+
///
82+
/// Will result in `Error::Input` if the size of the output exceeds the max message
83+
/// length in the Noise Protocol (65535 bytes).
84+
pub fn write_message_with_additional_data(
85+
&self,
86+
nonce: u64,
87+
authtext: &[u8],
88+
plaintext: &[u8],
89+
out: &mut [u8],
90+
) -> Result<usize, Error> {
91+
if !self.initiator && self.pattern.is_oneway() {
92+
return Err(StateProblem::OneWay.into());
93+
} else if plaintext.len() + TAGLEN > MAXMSGLEN || plaintext.len() + TAGLEN > out.len() {
94+
return Err(Error::Input);
95+
}
96+
97+
let cipher = if self.initiator { &self.cipherstates.0 } else { &self.cipherstates.1 };
98+
cipher.encrypt_ad(nonce, authtext, plaintext, out)
99+
}
100+
73101
/// Read a noise message from `message` and write the payload to the `payload` buffer.
74102
///
75103
/// Returns the number of bytes written to `payload`.
@@ -97,6 +125,39 @@ impl StatelessTransportState {
97125
}
98126
}
99127

128+
/// Read a noise message from `ciphertext` and write the decrypted payload to `out`
129+
/// buffer like [`read_message`](Self::read_message). Additionally when computing
130+
/// the authentication tag, mix in the contents of `authtext`. This needs to be the
131+
/// same data which was passed to
132+
/// [`write_message_with_additional_data`](Self::write_message_with_additional_data).
133+
///
134+
/// Returns the number of bytes written to `out`.
135+
///
136+
/// # Errors
137+
///
138+
/// Will result in `Error::Input` if the message is more than 65535 bytes.
139+
///
140+
/// Will result in `Error::Decrypt` if the contents couldn't be decrypted and/or the
141+
/// authentication tag didn't verify.
142+
///
143+
/// Will result in `StateProblem::Exhausted` if the max nonce overflows.
144+
pub fn read_message_with_additional_data(
145+
&self,
146+
nonce: u64,
147+
authtext: &[u8],
148+
ciphertext: &[u8],
149+
out: &mut [u8],
150+
) -> Result<usize, Error> {
151+
if ciphertext.len() > MAXMSGLEN {
152+
Err(Error::Input)
153+
} else if self.initiator && self.pattern.is_oneway() {
154+
Err(StateProblem::OneWay.into())
155+
} else {
156+
let cipher = if self.initiator { &self.cipherstates.1 } else { &self.cipherstates.0 };
157+
cipher.decrypt_ad(nonce, authtext, ciphertext, out)
158+
}
159+
}
160+
100161
/// Generate a new key for the egress symmetric cipher according to Section 4.2
101162
/// of the Noise Specification. Synchronizing timing of rekey between initiator and
102163
/// responder is the responsibility of the application, as described in Section 11.3

0 commit comments

Comments
 (0)