|
16 | 16 | // http://cvsweb.openbsd.org/cgi-bin/cvsweb/src/usr.bin/ssh/PROTOCOL.chacha20poly1305?annotate=HEAD |
17 | 17 |
|
18 | 18 | use aes_gcm::{AeadCore, AeadInPlace, Aes256Gcm, KeyInit, KeySizeUser}; |
19 | | -use byteorder::{BigEndian, ByteOrder}; |
20 | 19 | use digest::typenum::Unsigned; |
21 | 20 | use generic_array::GenericArray; |
22 | 21 | use rand::RngCore; |
@@ -84,27 +83,13 @@ pub struct SealingKey { |
84 | 83 | cipher: Aes256Gcm, |
85 | 84 | } |
86 | 85 |
|
87 | | -const GCM_COUNTER_OFFSET: u64 = 3; |
88 | | - |
89 | | -fn make_nonce( |
90 | | - nonce: &GenericArray<u8, NonceSize>, |
91 | | - sequence_number: u32, |
92 | | -) -> GenericArray<u8, NonceSize> { |
93 | | - let mut new_nonce = GenericArray::<u8, NonceSize>::default(); |
94 | | - new_nonce.clone_from_slice(nonce); |
95 | | - // Increment the nonce |
96 | | - let i0 = new_nonce.len() - 8; |
97 | | - |
98 | | - #[allow(clippy::indexing_slicing)] // length checked |
99 | | - let ctr = BigEndian::read_u64(&new_nonce[i0..]); |
100 | | - |
101 | | - // GCM requires the counter to start from 1 |
102 | | - #[allow(clippy::indexing_slicing)] // length checked |
103 | | - BigEndian::write_u64( |
104 | | - &mut new_nonce[i0..], |
105 | | - ctr + sequence_number as u64 - GCM_COUNTER_OFFSET, |
106 | | - ); |
107 | | - new_nonce |
| 86 | +fn inc_nonce(nonce: &mut GenericArray<u8, NonceSize>) { |
| 87 | + let mut carry = 1; |
| 88 | + for i in (0..nonce.len()).rev() { |
| 89 | + let n = nonce[i] as u16 + carry; |
| 90 | + nonce[i] = n as u8; |
| 91 | + carry = n >> 8; |
| 92 | + } |
108 | 93 | } |
109 | 94 |
|
110 | 95 | impl super::OpeningKey for OpeningKey { |
@@ -137,22 +122,21 @@ impl super::OpeningKey for OpeningKey { |
137 | 122 | #[allow(clippy::indexing_slicing)] // length checked |
138 | 123 | buffer.copy_from_slice(&ciphertext_in_plaintext_out[super::PACKET_LENGTH_LEN..]); |
139 | 124 |
|
140 | | - let nonce = make_nonce(&self.nonce, sequence_number); |
141 | | - |
142 | 125 | let mut tag_buf = GenericArray::<u8, TagSize>::default(); |
143 | 126 | tag_buf.clone_from_slice(tag); |
144 | 127 |
|
145 | 128 | #[allow(clippy::indexing_slicing)] |
146 | 129 | self.cipher |
147 | 130 | .decrypt_in_place_detached( |
148 | | - &nonce, |
| 131 | + &self.nonce, |
149 | 132 | &packet_length, |
150 | 133 | &mut ciphertext_in_plaintext_out[super::PACKET_LENGTH_LEN..], |
151 | 134 | &tag_buf, |
152 | 135 | ) |
153 | 136 | .map_err(|_| Error::DecryptionError)?; |
154 | 137 |
|
155 | | - Ok(ciphertext_in_plaintext_out) |
| 138 | + inc_nonce(&mut self.nonce); |
| 139 | + Ok(&ciphertext_in_plaintext_out[super::PACKET_LENGTH_LEN..]) |
156 | 140 | } |
157 | 141 | } |
158 | 142 |
|
@@ -191,18 +175,17 @@ impl super::SealingKey for SealingKey { |
191 | 175 | #[allow(clippy::indexing_slicing)] // length checked |
192 | 176 | packet_length.clone_from_slice(&plaintext_in_ciphertext_out[..super::PACKET_LENGTH_LEN]); |
193 | 177 |
|
194 | | - let nonce = make_nonce(&self.nonce, sequence_number); |
195 | | - |
196 | 178 | #[allow(clippy::indexing_slicing, clippy::unwrap_used)] |
197 | 179 | let tag_out = self |
198 | 180 | .cipher |
199 | 181 | .encrypt_in_place_detached( |
200 | | - &nonce, |
| 182 | + &self.nonce, |
201 | 183 | &packet_length, |
202 | 184 | &mut plaintext_in_ciphertext_out[super::PACKET_LENGTH_LEN..], |
203 | 185 | ) |
204 | 186 | .unwrap(); |
205 | 187 |
|
| 188 | + inc_nonce(&mut self.nonce); |
206 | 189 | tag.clone_from_slice(&tag_out) |
207 | 190 | } |
208 | 191 | } |
0 commit comments