MCPcopy Create free account
hub / github.com/DNSCrypt/encrypted-dns-server / decrypt_pq_ciphertext

Function decrypt_pq_ciphertext

src/dnscrypt.rs:141–191  ·  view source on GitHub ↗

Decrypt a PQ query that carries an X-Wing ciphertext, and prepare a freshly issued resumption ticket for the response.

(
    wrapped_packet: &[u8],
    params: &Arc<DNSCryptEncryptionParams>,
    pq_ticket_key: &pq::TicketKey,
)

Source from the content-addressed store, hash-verified

139/// Decrypt a PQ query that carries an X-Wing ciphertext, and prepare a
140/// freshly issued resumption ticket for the response.
141fn decrypt_pq_ciphertext(
142 wrapped_packet: &[u8],
143 params: &Arc<DNSCryptEncryptionParams>,
144 pq_ticket_key: &pq::TicketKey,
145) -> Result<(EncryptionParams, Vec<u8>), Error> {
146 let pq_params = params.pq().ok_or_else(|| anyhow!("No PQ params"))?;
147 let cm = DNSCRYPT_QUERY_MAGIC_SIZE;
148 let ct_len = pq::XWING_CT_SIZE;
149 let nonce_size = DNSCRYPT_QUERY_NONCE_SIZE;
150 ensure!(
151 wrapped_packet.len() >= cm + ct_len + nonce_size + DNSCRYPT_MAC_SIZE + DNS_HEADER_SIZE,
152 "Short PQ query"
153 );
154 let mut client_magic = [0u8; 8];
155 client_magic.copy_from_slice(&wrapped_packet[..cm]);
156 let ct = &wrapped_packet[cm..cm + ct_len];
157 let client_nonce = &wrapped_packet[cm + ct_len..cm + ct_len + nonce_size];
158 let encrypted_packet = &wrapped_packet[cm + ct_len + nonce_size..];
159
160 let kem_ss = pq_params.keypair().decapsulate(ct)?;
161 let cert_ctx = pq_params.cert_context();
162 let es_version = pq_params.es_version();
163 let shared_key = pq::derive_shared_key(&kem_ss, &es_version, &client_magic, cert_ctx, ct);
164
165 let mut nonce = [0u8; DNSCRYPT_FULL_NONCE_SIZE];
166 nonce[..nonce_size].copy_from_slice(client_nonce);
167 let packet = shared_key.decrypt(&nonce, encrypted_packet)?;
168
169 let sk_bytes = *shared_key.as_raw_bytes();
170 let rs = pq::resume_secret(&sk_bytes, &client_magic, client_nonce);
171 let mut ticket_nonce = [0u8; pq::TICKET_NONCE_SIZE];
172 rand::rng().fill_bytes(&mut ticket_nonce);
173 let ticket_expiry = now().saturating_add(pq::PQ_TICKET_LIFETIME);
174 let peh = pq_params.profile_extension_hash();
175 let serial = pq_params.serial();
176 let ts_end = pq_params.ts_end();
177 let tp = pq::ticket_plain(&rs, &es_version, &client_magic, &serial, &ts_end, ticket_expiry, &peh);
178 let ticket = pq::seal_ticket(pq_ticket_key, &ticket_nonce, &tp);
179 let control = pq::control_block(pq::PQ_TICKET_LIFETIME, &ticket);
180 debug!("PQ X-Wing query decapsulated; resumption ticket issued");
181
182 rand::rng().fill_bytes(&mut nonce[nonce_size..]);
183 Ok((
184 EncryptionParams::Pq {
185 shared_key,
186 nonce,
187 control,
188 },
189 packet,
190 ))
191}
192
193/// Decrypt a resumed PQ query, validating its ticket and deriving the
194/// per-query key without a KEM decapsulation.

Callers 1

decryptFunction · 0.85

Calls 15

derive_shared_keyFunction · 0.85
resume_secretFunction · 0.85
nowFunction · 0.85
ticket_plainFunction · 0.85
seal_ticketFunction · 0.85
control_blockFunction · 0.85
pqMethod · 0.80
decapsulateMethod · 0.80
keypairMethod · 0.80
cert_contextMethod · 0.80
es_versionMethod · 0.80
decryptMethod · 0.80

Tested by

no test coverage detected